MFCデバイスコンテキストの取得と描画について

このQ&Aのポイント
  • MFCのデバイスコンテキストを取得して、DirectXなどで描画を行っています。環境は、VS2008、DirextX 9.0、MDIなんですがOnInitDialogでDirectXのデバイスを取得しています。
  • MDIですので、5以上のファイルを作成すると、描画が行われなくなります。共通デバイスコンテキストは、5以上持てないということは検索して分かったのですが、5以上のファイルに描画を成功させるためには、どうすればいいのでしょうか?
  • 単純に新規ファイルを作ったときに、以前に作ったファイルのデバイスコンテキストを開放また、Directxのデバイスを開放すればいい?DirecXのデバイスをファイルごとに作成するのではなく、共通してもてば解決できる?そもそも解放したりしても無理??と考えているのですが、どうでしょうか?助言をお願いします。
回答を見る
  • ベストアンサー

MFC デバイスコンテキストについて

MFCのデバイスコンテキストを取得して、DirectXなどで描画を行っています。 環境は、 VS2008 DirextX 9.0 MDIなんですがOnInitDialogでDirectXのデバイスを取得しています。 次にOnDrawで描画を行っています。 GetDcでコンテキストを取得し、円の描画を行っています。 MDIですので、5以上のファイルを作成すると、描画が行われなくなります。 共通デバイスコンテキストは、5以上持てないということは検索して分かったのですが、5以上のファイルに描画を成功させるためには、どうすればいいのでしょうか? ・単純に新規ファイルを作ったときに、以前に作ったファイルのデバイスコンテキストを開放また、Directxのデバイスを開放すればいい? ・DirectXのデバイスをファイルごとに作成するのではなく、共通してもてば解決できる?? ・そもそも解放したりしても無理?? と考えているのですが、どうでしょうか? 助言をお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.4

 補足頂きました。  言葉足らずでした。多重継承をしている訳ではありません。  DirectXと言う構造体の中にアプリ内で共有するデータをstaticメンバ変数として入れておき、全員でそれを利用しているだけです。要するにグローバル変数の様なものです。  アプリ内で共有するデータの作り方は、その人の考え方次第と言う事に成ります。  staticメンバ変数・関数の書式に馴染みが無ければ、以下を参考にすると良いです。  http://ja.wikipedia.org/wiki/%E4%BA%88%E7%B4%84%E8%AA%9E_(C%2B%2B) ↓これを書き忘れていました。継承する訳ではありません。 struct DirectX { template<class _Tp>static BOOL ReleaseCOM(_Tp& p) { if(p == NULL) return FALSE; HRESULT hResult = p->Release(); p = NULL; return hResult == S_OK; } static BOOL Init(HWND hWnd); static BOOL UnInit(); static LPDIRECT3D9 g_pD3DPlan;//staticメンバ static LPDIRECT3DDEVICE9 g_pDEVPlan;//staticメンバ };  例えば、 struct DirectX { LPDIRECT3D9 pD3DPlan; LPDIRECT3DDEVICE9 pDEVPlan; }; extern DirectX g_dx;//此れを全員で使う  でも構いません。要はグローバル変数を一箇所にまとめようとしているような物です。  ただ、C++ではextern変数自体、余り使われないようです・・・。

その他の回答 (3)

回答No.3

 補足頂きました。  長々と試していたのですが、   class CPlanScopeView : public CView { DECLARE_DYNCREATE(CPlanScopeView) public: LPDIRECT3D9   g_pD3DPlan; //(1)LPDIRECT3D9オブジェクト  LPDIRECT3DDEVICE9   g_pDEVPlan; //(2)IDirect3DDevice9オブジェクト LPDIRECT3DSURFACE9 g_pBackBuffer; ・・・・  (1)(2)はそれぞれ、アプリで唯一として共有しないといけない様なので、ファイルの個数分作成しては良くない見たいです。  なので、ファイルの個数分存在してよいのはg_pBackBufferのみです。  MDIで初期化が複雑化しているので、どれを何処におくかを入念に検討した方が良いかもしれません・・・。  ファイルは幾つ開いても大丈夫でした。一応こんな感じで確認しました。Viewウィンドウではなく、Documentウィンドウの方にバックバッファを持たせた方が良いかもしれません。参考程度に。 //唯一存在するDXのデバイスなど //DirectX.cpp ///////////////////////////////////////////////////////// //スタティックメンバ変数 LPDIRECT3D9 DirectX::g_pD3DPlan = NULL; LPDIRECT3DDEVICE9 DirectX::g_pDEVPlan = NULL; //DXの初期化 BOOL DirectX::Init(HWND hWnd) { g_pD3DPlan = ::Direct3DCreate9(D3D_SDK_VERSION); if(!g_pD3DPlan)return FALSE; D3DPRESENT_PARAMETERS d3dpp = {0}; d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; g_pD3DPlan->CreateDevice(D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd , D3DCREATE_SOFTWARE_VERTEXPROCESSING , &d3dpp, &g_pDEVPlan ); return g_pDEVPlan != 0; } //DXの始末 BOOL DirectX::UnInit() { if(!ReleaseCOM(g_pDEVPlan))return FALSE; if(!ReleaseCOM(g_pD3DPlan))return FALSE; return TRUE; } //DirectX.cpp ///////////////////////////////////////////////////////// //CMainFrame.cpp CMainFrame::~CMainFrame() { //DXの後始末 DirectX::UnInit(); } int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { //MFCの処理ココから //MFCの処理ココまで //OnCreateのラスト、ココでDXの初期化 DirectX::Init(this->GetSafeHwnd()); return 0; } //CMainFrame.cpp ///////////////////////////////////////////////////////// //CMyMDIDoc.cpp CMyMDIDoc::CMyMDIDoc() : g_pBackBuffer(NULL)//初期化 { // TODO: この位置に1度だけ呼ばれる構築用のコードを追加してください。 } CMyMDIDoc::~CMyMDIDoc() { //サーフェースの始末 DirectX::ReleaseCOM(g_pBackBuffer); } BOOL CMyMDIDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; // TODO: この位置に再初期化処理を追加してください。 // (SDI ドキュメントはこのドキュメントを再利用します。) //ココでサーフェースを作る DirectX::g_pDEVPlan->CreateOffscreenPlainSurface(320, 240, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &g_pBackBuffer, NULL); //作成に成功したら黒く塗り潰す if(g_pBackBuffer) { HDC hDC = this->GetSurfaceDC(); ::PatBlt(hDC, 0, 0, 320, 240, BLACKNESS); this->ReleaseSurfaceDC(hDC); } return g_pBackBuffer != 0 ? TRUE : FALSE; } //サーフェースのDCを取る HDC CMyMDIDoc::GetSurfaceDC() { HDC hDC; g_pBackBuffer->GetDC(&hDC); return hDC; } //サーフェースのDCを消す BOOL CMyMDIDoc::ReleaseSurfaceDC(HDC hDC) { return g_pBackBuffer->ReleaseDC(hDC) == S_OK; } //CMyMDIDoc.cpp ///////////////////////////////////////////////////////// //CMyMDIView.cpp(質問者様のCPlanScopeViewに該当するクラス) void CMyMDIView::OnDraw(CDC* pDC) { CMyMDIDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: この場所にネイティブ データ用の描画コードを追加します。 //サーフェースのDCを取る HDC hDC = pDoc->GetSurfaceDC(); //しくじったらメッセージでも表示する if(hDC == NULL) { ::MessageBox(NULL, " error ", " ", MB_OK); } //円を描く ::Ellipse(hDC, 0, 0, 320, 240); //ビューに描写 ::BitBlt(*pDC, 0, 0, 320, 240, hDC, 0, 0, SRCCOPY); //サーフェースのDCを消す pDoc->ReleaseSurfaceDC(hDC); }

hir0yuki
質問者

お礼

回答ありがとうございます。 すみません。わざわざいろいろ試していただいて。 最初に原因として、考えてた一番修正が多くあまりやりたくないものが原因とは 少しへこみます。 上記を参考にコーディングをやりなおしてみます。 また結果の報告をさせていただきます。

hir0yuki
質問者

補足

たびたびすみません。 上記に詳しく記述していただいているのですが、 DirectXのクラスを作成するでいいんでしょうか? そして、そのクラスを継承を行いな各クラスで使用するで問題ないのでしょうか? その場合、多重継承となって、いくような気が多重継承以外では、無理ですかね。 初歩的な質問かもしれませんが宜しく御願い致します。

回答No.2

 補足頂きました。  「g_pBackBuffer」が、個別のファイルに対するバックバッファでしょうか。  もしかして、この変数は「externやstatic」に成っていませんか?  ↓こんな感じに成っていませんか  extern g_pBackBuffer = NULL;  もしそうならば、MDIチャイルドウィンドウ(ファイルを開くたびに開くウィンドウ)のクラスのメンバ変数にしなければいけません。

hir0yuki
質問者

補足

お返事ありがとうございます。 > 「g_pBackBuffer」が、個別のファイルに対するバックバッファでしょうか。 はい。個別のバックバッファになっています。 g_pBackBufferはクラスのメンバ変数にしています。 class CPlanScopeView : public CView { DECLARE_DYNCREATE(CPlanScopeView) public: LPDIRECT3D9   g_pD3DPlan; //LPDIRECT3D9オブジェクト LPDIRECT3DDEVICE9   g_pDEVPlan; //IDirect3DDevice9オブジェクトLPDIRECT3DSURFACE9 g_pBackBuffer; ・・・・ としています。 なので「externやstatic」にはしていませんが、ここの宣言に問題があるような 気がしてきましたが、どうでしょうか?

回答No.1

 こんばんは。  LPDIRECT3DSURFACE9の事でしょうか。サーフェースやテクスチャは同時に幾つ存在しても構わないです。  デバイスコンテキストは描写する寸前で取って、描写が終わったら直に解放した方が良いです。  OnInitDialog()で開きっ放しにしておくのは、トラブルの元です。   void MyDlg::OnDraw(...) { HDC hDCSurface = NULL; //書く直前にGetDC()する m_pSurface->GetDC(&hDCSurface); //円を描く ::Ellipse(hDCSurface, , ,); //書き終わったら直閉じる m_pSurface->ReleaseDC(hDCSurface); }  の様にすれば良いのでは無いでしょうか。

hir0yuki
質問者

お礼

返事が遅くなり、申し訳ありませんでした。 上記のとおり、変更すると、5個以上のでも描画できました。 ありがとうございます。 ただ、いろいろと新たな問題がでてきましたけど・・・orz 実は、追加の仕様で、画面を分割する必要性がでてきまして、 ChildFormを4分割を行ったのですが、 上記の場所で、デバイスを取得すると、MainFormに描画されるようになってしまいました。 現在、試行錯誤して、上記のやりかたで、分割でも問題なくその領域に描画で きるように修正中です。

hir0yuki
質問者

補足

回答ありがとうございます。 早速ためしてみましたが、やはり6個目で、表示されなくなりました。。。 hr = g_pBackBuffer->GetDC(&hDC_Test); if (!FAILED(hr)){ SelectObject(hDC_Test,g_Brush); ::Ellipse(hDC_Test,,,,); g_pBackBuffer->ReleaseDC(hDC_Test); } と書いたのですが。。。 デバッグで見てみると、6個目のファイル作成時のGetDCでの戻りが 正常値が戻ってきてないです。 上記では、開きっぱなしになっていないはずですので、 他の原因があるのでしょうか?

関連するQ&A

  • MFC DirectXのデバイスの再設定

    MFCのMDIで、DirectXおよびWinAPIを仕様して領域に描画を行うものを作っています。 環境ですが、 VS2008 DirectX9.0 です。 子ウィンドウは4分割しており、(0,0)と(1,0)が描画領域で、(0,1)(1,1)はフォームです。 そこで、以前は各子ウィンドウごとに、デバイスを取得し、描画をおこなっていたのですが、ファイルを5個以上作成すると、WinAPIで描画されるものが表示されなくなりました。 それは、デバイスコンテキストは、5個以上もてないことが発覚したためとわかったので、デバイスは親で持つことにし、共通化することになりました。 しかし、それでは、親ウィンドウで取得しているため、描画のウィンドウサイズなどが異なるため、意図した領域にかけておりません。 そこで、各領域に再設定を行いたいのですが、どうすればよいのでしょうか? 対策として、下記のように考えたのですが、検討違いでしょうか? ・デバイスの画面の設定をResetなどをつかって、リセットし、描画領域の再設定を行う。(Resetだと、再度デバイスの取得を行うと思っているのですが、これだとファイルごとにもっているのと変わらないような気がします。) ・CreateOffscreenPlainSurface等でオフスクリーン サーフェイスを作成し、描画する。(描画の座標情報等の微調整がいるような気がします。) ・単純に再設定できるから再設定を行う。 アドバイスを御願い致します。

  • ピクチャーコントロールのデバイスコンテキストを取得するためには?

    VC2005についてです ピクチャーコントロールのデバイスコンテキストを取得するためには どうすればよいでしょうか? MDIGetActive()->GetDC()->TextOutA(20,50,"文字列です"); この様にすれば、アクティブになった 子ウィンドウデバイスコンテキストを取得することができますが、 アクティブになった、この子ウィンドウの上にある ピクチャーコントロールに 描画するためには どうすればよいでしょうか? MDIで、複数のウィンドウのうちで アクティブになった ものだけを 操作したいのです。 よろしくお願いします。

  • デバイスコンテキストについて

    いつもお世話になります。 MFCアプリケーションWIZでデスクトップアプリを作成しているのですが、 HDC型のデバイスコンテキストの取得方法がわかりません。 CWndのメンバ変数m_hWndにウィンドウハンドルが格納されるというのは わかったのですが、 hDC = GetDC(m_hWnd)だと間違っているのですよねー。 ご教示よろしくお願い致します。

  • ピクチャーコントロールのデバイスコンテキストを取得するためには?

    VC2005についてです ピクチャーコントロールのデバイスコンテキストを操作するためには どうすればよいでしょうか? void CMainFrame::OnButton() { // ここに処理を書く CMainFrame *pFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd; CButton *pButton =  (CButton*)pFrame->m_wndDialogBar.GetDlgItem(IDC_BUTTON1); pButton->SetWindowText("button"); MDIGetActive()->GetDC()->TextOutA(0,0,"文字列です"); } この様にすれば、アクティブになった 子ウィンドウデバイスコンテキストを取得することができますが、 アクティブになった、この子ウィンドウの上にある ピクチャーコントロールに 描画するためには どうすればよいでしょうか? MDIで、複数のウィンドウのうちで アクティブになった ものだけを 操作したいのです。 MDIGetActive()->GetDlgItem(IDC_PICTURE1)->GetDC()->TextOutA(0,0,"文字列です"); この方法では、エラーがでます。 よろしくお願いします。

  • デバイスコンテキストについて詳しく教えてください

    C言語でwin32APIを勉強しているのですが、デバイスコンテキストとは具体的にどのようなものでしょうか?Windowsが管理しているGDIで描画をするための構造体らしいですが・・・。 それともう1つ質問です。解説サイトに「デバイスコンテキストは使ったらすぐ解放しなければならない」と書かれているのですが、なぜすぐに解放しなければならないのですか?サンプルプログラムを見ていると、まだ使えそうなデバイスコンテキストもすぐ解放し、次に必要になれば新たにデバイスコンテキストを確保していますが、そのまま取って置くのは駄目なのでしょうか。そのようなプログラム(汎用的なデバイスコンテキストをWinMainの最初に確保し、完全に使わなくなった時点で解放する)を作って動作させてみても、ぱっと見では問題が見つかりません。ですがこれではやはり問題があるのでしょうか? 質問は以上の2点です。回答よろしくお願いします。

  • ピクチャーコントロールのデバイスコンテキストを取得するためには?

    すみません、解決しませんでした・・・ C2005についてです ピクチャーコントロールのデバイスコンテキストを操作するためには どうすればよいでしょうか? void CMainFrame::OnButton() { CMDIChildWnd *mc; mc=MDIGetActive(); CStatic* pStatic=(CStatic*)mc->GetDlgItem(IDC_PICTURE1); CClientDC myPictDC(pStatic); myPictDC.TextOutA(0,0,"aiueo"); } この様にすれば、文字が出力されますが、 モニターの画面上の左上 (0,0)の位置に 出力されてしまいます。 アクティブになった、この子ウィンドウの上にある ピクチャーコントロールに 描画するためには どうすればよいでしょうか? MDIで、複数のウィンドウのうちで アクティブになった ものだけを 操作したいのです。 ピクチャーコントロールの上に描画するためには どうすればよいでしょう? よろしくお願いします。

  • ダイアログボックス・・・・・ bySDK

    現在SDKにて画像処理ソフトを作成しています。もちろん個人にて。 そこで確実にほしい機能”ヒストグラム”の表示を行おうと思ったのですが、問題が起こりました。 目的は”2値化"という処理に伴い、ダイアログボックスに入力した画像のヒストグラムを表示させたいということです。 もちろんヒストグラムは単に白黒だけで表示させたいと思っています。 問題というのはダイアログボックスに任意の図形をどのように描画するかです。ビットマップの描画は以前行ったことがあるのですが、任意の図形は行ったことがありませんでした。 試しに、ダイアログボックスにPicture Controlを貼り付け、そのPicture ControlのデバイスコンテキストをGetDCにより無理やり取得し、そのデバイスコンテキストに直線などの描画を行ってみましたが、表示はされませんでした。(あたりまえかも・・・・) そこでまず、ダイアログボックスに使用するコントロール類は何を設定したらよいか? そして、そのコントロールから取得したデバイスコンテキストに直接描画は可能か? これらの質問に答えられる方はアドバイスをお願いしたいと思います。 よろしくお願いします。

  • VC++2010(MFC)OnDraw以外での描画

    xxxView.cppファイル内のOnDraw以外の部分で、以下のコードを書きビルドしましたが、「'CWnd::GetDC' : 静的でないメンバー関数の呼び出しが正しくありません」というエラーと「'CWnd::ReleaseDC' : 関数に 0 個の引数を指定できません」というエラーが出てしまい、描画できません。エラーの出ない、正しいコードを教えて下さい。 CPaintDC* pDC; CWnd::GetDC(); pDC->TextOut(10,10,"テスト"); CWnd::ReleaseDC();

  • VC++ Ver1.51でのデバイスコンテキストからのビットマップ作成について

    VC++ Ver1.51でプリンタのデバイスコンテキストからビットマップを作成しなければならなくなったのですがビットマップ編集の経験が無いもので行き詰まってしまいました、分かる方が居られましたらアドバイスいただけませんでしょうか? 自分で書いてみたところを抜粋して書きます。 BITMAPFILEHEADER LtpBitmapFH; BITMAPINFOHEADER LtpBitmapIH; LlnWidth = LtpBitmapIH.biWidth; LlnHeight = LtpBitmapIH.biHeight; // メモリデバイスコンテキスト取得 MhBitmapMemDC = CreateCompatibleDC(PrinterDC); // PrinterDC がプリンタのDCです。 MhBitmapDC = CreateCompatibleBitmap(MhBitmapMemDC,(int)(LlnWidth),(int)(LlnHeight)); LlnSelObj = SelectObject(MhBitmapMemDC,MhBitmapDC); GetObject(MhBitmapDC,sizeof(BITMAPINFOHEADER),&LtpBitmapInfo); LlnRet = BitBlt(MhBitmapMemDC, 0, 0, (int)(LlnWidth), (int)(LlnHeight), PrinterDC, 0, 0, SRCCOPY); // BitBltがうまくいかなかったのでこの間の処理はできていません // 後かたづけ(ここも不足しているかもしれません) DeleteObject(MhBitmapDC); 以上のようにしています。 BitBltの戻り値がエラーで返ってきます。(BitBltがうまく使えてないのでそこから下も未完成です、すいません)本来使うべきAPIでは無いのかもしれません。 現在やりたいことは、DCを読み込んでビットマップファイルを作成したかったのですが、いろいろ試して自分では難しかったので白地のビットマップファイルをあらかじめ作成しておいて、そこにメモリDCの内容をコピーして別名でビットマップファイルを作成したいと思っています。 いろいろ検索してみたのですがCreateDIBSection等が使用されていたりver1.51では使用できないものが多かったのでもし経験のある方のお目にとまれば助言お願いいたします。

  • MFCのメモリ開放が必要なメソッド

    現在、MFCを使ってドローツールを作成しています。 今まで、DCの取得にGetDC()を多用していたのですが、 今日初めて、GetDC()とReleaseDC()は必ずセットで使う事を知りました。 恥ずかしい話ですが、まだまだMFCには詳しくありません。 このように、WindowsのC言語開発でメモリ開放がセットになっている関数で 初心者がよく失敗しがちなものが他にもありましたら教えて下さい。 どうぞ宜しくお願い致します。