アプリ版:「スタンプのみでお礼する」機能のリリースについて

MFCのデバイスコンテキストを取得して、DirectXなどで描画を行っています。
環境は、
VS2008
DirextX 9.0
MDIなんですがOnInitDialogでDirectXのデバイスを取得しています。
次にOnDrawで描画を行っています。
GetDcでコンテキストを取得し、円の描画を行っています。

MDIですので、5以上のファイルを作成すると、描画が行われなくなります。

共通デバイスコンテキストは、5以上持てないということは検索して分かったのですが、5以上のファイルに描画を成功させるためには、どうすればいいのでしょうか?

・単純に新規ファイルを作ったときに、以前に作ったファイルのデバイスコンテキストを開放また、Directxのデバイスを開放すればいい?

・DirectXのデバイスをファイルごとに作成するのではなく、共通してもてば解決できる??

・そもそも解放したりしても無理??

と考えているのですが、どうでしょうか?
助言をお願いします。

A 回答 (4件)

 補足頂きました。


 言葉足らずでした。多重継承をしている訳ではありません。
 DirectXと言う構造体の中にアプリ内で共有するデータをstaticメンバ変数として入れておき、全員でそれを利用しているだけです。要するにグローバル変数の様なものです。
 アプリ内で共有するデータの作り方は、その人の考え方次第と言う事に成ります。

 staticメンバ変数・関数の書式に馴染みが無ければ、以下を参考にすると良いです。
 http://ja.wikipedia.org/wiki/%E4%BA%88%E7%B4%84% …

↓これを書き忘れていました。継承する訳ではありません。
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変数自体、余り使われないようです・・・。
    • good
    • 0

 補足頂きました。



 長々と試していたのですが、
 
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);
}

この回答への補足

たびたびすみません。
上記に詳しく記述していただいているのですが、

DirectXのクラスを作成するでいいんでしょうか?
そして、そのクラスを継承を行いな各クラスで使用するで問題ないのでしょうか?
その場合、多重継承となって、いくような気が多重継承以外では、無理ですかね。

初歩的な質問かもしれませんが宜しく御願い致します。

補足日時:2008/12/09 13:10
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
すみません。わざわざいろいろ試していただいて。

最初に原因として、考えてた一番修正が多くあまりやりたくないものが原因とは
少しへこみます。
上記を参考にコーディングをやりなおしてみます。


また結果の報告をさせていただきます。

お礼日時:2008/12/08 21:06

 補足頂きました。



 「g_pBackBuffer」が、個別のファイルに対するバックバッファでしょうか。
 もしかして、この変数は「externやstatic」に成っていませんか?

 ↓こんな感じに成っていませんか
 extern g_pBackBuffer = NULL;

 もしそうならば、MDIチャイルドウィンドウ(ファイルを開くたびに開くウィンドウ)のクラスのメンバ変数にしなければいけません。

この回答への補足

お返事ありがとうございます。

> 「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」にはしていませんが、ここの宣言に問題があるような
気がしてきましたが、どうでしょうか?

補足日時:2008/12/08 13:41
    • good
    • 0

 こんばんは。



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

 の様にすれば良いのでは無いでしょうか。

この回答への補足

回答ありがとうございます。
早速ためしてみましたが、やはり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での戻りが
正常値が戻ってきてないです。

上記では、開きっぱなしになっていないはずですので、
他の原因があるのでしょうか?

補足日時:2008/12/08 09:34
    • good
    • 0
この回答へのお礼

返事が遅くなり、申し訳ありませんでした。
上記のとおり、変更すると、5個以上のでも描画できました。
ありがとうございます。
ただ、いろいろと新たな問題がでてきましたけど・・・orz

実は、追加の仕様で、画面を分割する必要性がでてきまして、
ChildFormを4分割を行ったのですが、
上記の場所で、デバイスを取得すると、MainFormに描画されるようになってしまいました。

現在、試行錯誤して、上記のやりかたで、分割でも問題なくその領域に描画で
きるように修正中です。

お礼日時:2008/12/12 13:44

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!