トップページ > 記事閲覧
SetDrawScreenについて
名前:雑食のとと 日時: 2021/02/01 16:57

特定条件下でSetDrawScreenにMakeScreenで作成したウインドウを渡したところ、例外が発生してしまいました。 例外はヌルポインタによるもので、 DxLibMakeから参照しましたところ Graphics_D3D11_StretchRect関数の第四引数OWI->BufferTexture2D(仮引数名はDestTexture) がNULLになっていました。 条件を変えながら試したところ、 SetScreenFlipTargetWindow関数で存在するユーザー定義ウインドウAを指定し、 ウインドウAを破棄したあとSetScreenFlipTargetWindow(NULL)などを呼ばずに (=ScreenFlip先のウインドウを破棄したウインドウから変更せずに) SetDrawScreen関数を呼びだすと発生するようでした。 マイナーな関数を使っているうえに特殊なケースの問題ではありますが、 このような条件下で例外が発生しないよう修正していただけましたら幸いです。 また、全く見当違いのことを申し上げていましたらすみません。 どうぞよろしくお願いいたします。
メンテ

Page: 1 |

Re: SetDrawScreenについて ( No.1 )
名前:管理人 日時:2021/02/02 22:20

すみません、以下のような SetScreenFlipTargetWindow を使用する雑食のととさんが 現象を再現された状況に近いと思われるコードを書いて試してみたのですが、例外は発生しませんでした ( ウィンドウ2を閉じて、その直後に MakeScreen で作成したグラフィックハンドルを SetDrawScreen に渡して実行しています ) #include "DxLib.h" char *szClassNme[ 2 ] = { "ウィンドウ1クラスネーム", "ウィンドウ2クラスネーム", } ; // メッセージ処理用関数 LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_DESTROY: //PostQuitMessage( 0 ) ; break ; default : return(DefWindowProc( hWnd, msg, wParam, lParam ) ) ; } return ( 0L ) ; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR lpszCmdLine, int nCmdShow) { int pos, pos_add ; LONGLONG temp_time ; MSG msg ; HWND hWnd[ 2 ] ; WNDCLASS myProg ; // ウインドウの作成 myProg.style = CS_HREDRAW | CS_VREDRAW ; myProg.lpfnWndProc = WndProc ; myProg.cbClsExtra = 0 ; myProg.cbWndExtra = 0 ; myProg.hInstance = hInstance ; myProg.hIcon = NULL ; myProg.hCursor = LoadCursor( NULL, IDC_ARROW ) ; myProg.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH ) ; myProg.lpszMenuName = NULL ; myProg.lpszClassName = szClassNme[ 0 ] ; if( !RegisterClass( &myProg ) ) { return FALSE; } hWnd[ 0 ] = CreateWindow( szClassNme[ 0 ], "ウインドウ1", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hInstance, NULL ) ; ShowWindow( hWnd[ 0 ], nCmdShow ) ; UpdateWindow( hWnd[ 0 ] ) ; myProg.lpszClassName = szClassNme[ 1 ] ; if( !RegisterClass( &myProg ) ) { return FALSE; } hWnd[ 1 ] = CreateWindow( szClassNme[ 1 ], "ウインドウ2", WS_OVERLAPPEDWINDOW, 700, 100, 500, 500, NULL, NULL, hInstance, NULL ) ; ShowWindow( hWnd[ 1 ], nCmdShow ) ; UpdateWindow( hWnd[ 1 ] ) ; // ウインドウモードで起動 ChangeWindowMode( TRUE ) ; // VSYNC待ちをしない設定に変更 SetWaitVSyncFlag( FALSE ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // MakeScreen で描画先にできる画像を作成 int Screen = MakeScreen( 640, 480 ) ; // メッセージループ pos = 0 ; pos_add = 8 ; while( ProcessMessage() == 0 ) { if( PeekMessage( &msg, hWnd[ 0 ], 0, 0, PM_REMOVE ) ) { TranslateMessage(&msg); DispatchMessage(&msg); } if( PeekMessage( &msg, hWnd[ 1 ], 0, 0, PM_REMOVE ) ) { TranslateMessage(&msg); DispatchMessage(&msg); } // 移動処理 pos += pos_add ; if( pos > 400 || pos < 0 ) { pos_add = -pos_add ; } // 描画先を裏画面に変更 SetDrawScreen( DX_SCREEN_BACK ) ; // メインウインドウ用の描画 ClearDrawScreen() ; DrawBox( pos, 0, pos + 64, 64, GetColor( 255,0,0 ), TRUE ) ; SetScreenFlipTargetWindow( NULL ) ; ScreenFlip() ; // ウインドウ1用の描画 ClearDrawScreen() ; DrawBox( 0, pos, 48, pos + 48, GetColor( 0,255,0 ), TRUE ) ; SetScreenFlipTargetWindow( hWnd[ 0 ] ) ; ScreenFlip() ; // ウインドウ2用の描画 if( hWnd[ 1 ] != NULL ) { ClearDrawScreen() ; DrawBox( pos, pos, pos + 80, pos + 80, GetColor( 0, 0, 255 ), TRUE ) ; SetScreenFlipTargetWindow( hWnd[ 1 ] ) ; ScreenFlip() ; // 表示直後にウィンドウを閉じる PostMessage( hWnd[ 1 ], WM_CLOSE, 0, 0 ); hWnd[ 1 ] = NULL ; } // 描画先を MakeScreen で作成した画像に変更 SetDrawScreen( Screen ) ; // 時間待ち処理 Sleep( 16 ) ; } // DXライブラリの後始末 DxLib_End(); return 0 ; } よろしければ上記のサンプルでは雑食のととさんの環境でも例外が発生しないか試してみていただけないでしょうか? m(_ _)m
メンテ
Re: SetDrawScreenについて ( No.2 )
名前:雑食のとと 日時:2021/02/04 17:07

管理人 さま サンプルを作ってくださりありがとうございます。 こちらでも、このサンプルでは問題は発生しませんでした。 手元で問題のプログラムとは別にコードを書いてみましたところ、 同様の例外が別関数(ScreenFlip)で発生しました。 DxLibMakeを見る限り問題になっている関数は同様のようです。 SetScreenFlipTargetWindowで無効なハンドルを設定している時に ScreenFlipを呼び出したところ発生しました。 また、元のプログラムでの、SetDrawScreen内で例外が起こっていることについては 関数の前後に、Win32での出力を行える関数OutputDebugStringを使用して判断しています。 SetDrawScreenで発生する例についてはもうしばらく調べてみたいと思いますが、 取り急ぎ、類似の例がありましたのでご報告させていただきます。 はじめの件については追って返信させてください。 #include "DxLib.h" LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_DESTROY: //PostQuitMessage( 0 ) ; break; default: return(DefWindowProc(hWnd, msg, wParam, lParam)); } return (0L); } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; HWND hWnd[2]; WNDCLASS myProg; //ウインドウの作成 myProg.style = CS_HREDRAW | CS_VREDRAW; myProg.lpfnWndProc = WndProc; myProg.cbClsExtra = 0; myProg.cbWndExtra = 0; myProg.hInstance = hInstance; myProg.hIcon = NULL; myProg.hCursor = LoadCursor(NULL, IDC_ARROW); myProg.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); myProg.lpszMenuName = NULL; myProg.lpszClassName = "ウインドウクラス"; if (!RegisterClass(&myProg)) { return FALSE; } hWnd[0] = CreateWindow( "ウインドウクラス", "ウインドウ1", WS_OVERLAPPEDWINDOW, 100, 100, 500, 500, NULL, NULL, hInstance, NULL ); ShowWindow(hWnd[0], nCmdShow); UpdateWindow(hWnd[0]); DxLib::SetWindowVisibleFlag(FALSE); DxLib::SetAlwaysRunFlag(TRUE); DxLib::SetUseTSFFlag(FALSE); //ウインドウモードで起動 ChangeWindowMode(TRUE); //初期化 DxLib::DxLib_Init(); int screen = MakeScreen(640,480); //ウインドウ消去の為に使用 int counter = 0; while (ProcessMessage() != -1) { //メッセージ処理 if (hWnd[0] != NULL) { if (PeekMessage(&msg, hWnd[0], 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } if (counter > 1) { DestroyWindow(hWnd[0]); OutputDebugString(_T("Window has destroyed\n")); hWnd[0] = NULL; } counter++; } //screenにBoxを描画 DxLib::SetDrawScreen(screen); DxLib::DrawBox(50,50,100,100,GetColor(255,0,0),TRUE); //裏画面にscreen内容を描画 DxLib::SetDrawScreen(DX_ORIGINAL_SCREEN_BACK); DxLib::DrawGraph(0, 0, screen, TRUE); //裏画面を指定のウインドウに反映 DxLib::SetScreenFlipTargetWindow(hWnd[0]); DxLib::ScreenFlip(); Sleep(16); } return DxLib::DxLib_End(); }
メンテ
Re: SetDrawScreenについて ( No.3 )
名前:管理人 日時:2021/02/05 00:07

> 手元で問題のプログラムとは別にコードを書いてみましたところ、 > 同様の例外が別関数(ScreenFlip)で発生しました。 載せていただいたプログラムを実行してみたのですが、私の手元の環境では 例外が発生しませんでした… > SetScreenFlipTargetWindowで無効なハンドルを設定している時に > ScreenFlipを呼び出したところ発生しました。 すみません、調べたところウィンドウハンドルが有効かを完璧に判定する方法は無いようなので ( IsWindow というウィンドウハンドルの値が有効かどうかを判定する為の API があるのですが、 ウィンドウハンドルの値は使い回されているので、仮に雑食のととさんのプログラムでウィンドウを クローズしても、他のプロセスが新たなウィンドウを作成して、そのウィンドウに雑食のととさんの プログラムでクローズしたウィンドウと同じウィンドウハンドルの値が割り当てられた場合、 IsWindow は雑食のととさんのプログラム内でクローズしたウィンドウハンドルの値に対して 『有効なウィンドウハンドルである』と判定する )、 SetScreenFlipTargetWindow に渡していたウィンドウハンドルが無効になった際は SetScreenFlipTargetWindow( NULL ); を実行するようにしてください m(_ _;m
メンテ
Re: SetDrawScreenについて ( No.4 )
名前:雑食のとと(解決) 日時:2021/02/06 23:21

管理人 さま ご返信くださりありがとうございます。 クリティカルなサンプルコードを提供できずすみませんでした。 もしかしたら環境に依存した例外だったのかもしれないです。 自分で使う分にはSetScreenFlipTargetWindow( NULL );を適当なタイミングで呼べば十分対応できますので 解決とさせていただきます。 またどうしようもない事態になった際にはご助力くださいませ。 ありがとうございます。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存