caveと申します。
DXライブラリは、先日から使い始めたばかりですが非常に扱いやすく助かっております。
さて、表題のとおり、フルスクリーンモードからウィンドウモードに切り替える際の、
ChangeWindowModeにて停止する問題に悩まされております。
以下に再現時のコードを記載します。
(アップローダにもおいてあります http://www.dotup.org/uploda/www.dotup.org6148.zip.html)
//ここから
#include "DxLib.h"
#include "resource.h"
#define SCREEN_WIDTH 320 //スクリーンの幅
#define SCREEN_HEIGHT 240 //スクリーンの高さ
#define SCREEN_COLOR 32 //スクリーンの色
BOOL g_bFullScreen = TRUE; //Window/Fullscreenモード
//ウィンドウ->フルスクリーンに変更
BOOL ToFullScreenMode()
{
ChangeWindowMode(FALSE); //FullScreenモードに切り替え
//解像度の設定
if (SetGraphMode(640,480,32)!= DX_CHANGESCREEN_OK) {
return FALSE;}
SetEmuration320x240(TRUE); //320x240 倍 拡大モード
SetDrawScreen(DX_SCREEN_BACK); //ダブルバッファリング(裏画面に描画を行う)
g_bFullScreen = TRUE;
return TRUE;
}
//フルスクリーン->ウィンドウに変更
BOOL ToWindowMode()
{
ChangeWindowMode(TRUE); //Windowモードに切り替え(ここで停止)
SetGraphMode(SCREEN_WIDTH,SCREEN_HEIGHT,32);
SetWindowSizeChangeEnableFlag(TRUE,TRUE); //ウインドウのサイズを自由に変更出来るようにする
//中央に配置(おおよそ)
RECT rc = {0,0,SCREEN_WIDTH,SCREEN_HEIGHT};
//DXライブラリの作成するウィンドウについて
//ウィンドウスタイルは(0x94CE0000)でWS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_GROUP
//ちなみに拡張ウィンドウスタイルは(0x300)でWS_EX_WINDOWEDGE|WS_EX_CLIENTEDGE
AdjustWindowRect(&rc,WS_POPUP|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_GROUP,TRUE);
int nPosX = (GetSystemMetrics(SM_CXSCREEN)/2) - ((rc.right - rc.left)/2);
int nPosY = (GetSystemMetrics(SM_CYSCREEN)/2) - ((rc.bottom - rc.top)/2);
SetWindowInitPosition(nPosX,nPosY); //起動時のウィンドウズの位置を設定
SetWindowSizeExtendRate(1.0); //拡大倍率
SetDrawScreen(DX_SCREEN_BACK); //ダブルバッファリング(裏画面に描画を行う)
g_bFullScreen = FALSE;
return TRUE;
}
//Windowsプロシージャのフック
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_QUIT: //終了
PostMessage(hWnd,WM_SYSCOMMAND,SC_CLOSE,0);
break;
case ID_WINDOW1X: //画面-ウィンドウ-1倍
case ID_WINDOW2X: //画面-ウィンドウ-2倍
case ID_WINDOW3X: //画面-ウィンドウ-3倍
{
if (g_bFullScreen)
if (!ToWindowMode()) break;
RECT rc;
GetWindowRect(hWnd,&rc);
SetWindowInitPosition(rc.left,rc.top);
double dSize;
if (LOWORD(wParam) == ID_WINDOW1X) dSize = 1.0;
else if (LOWORD(wParam) == ID_WINDOW2X) dSize = 2.0;
else dSize = 3.0;
SetWindowSizeExtendRate(dSize);
break;
}
case ID_FULLSCREEN: //画面-フルスクリーン
if (!g_bFullScreen) {
ToFullScreenMode();
}
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
//return DefWindowProc(hWnd,msg,wParam,lParam); //どうやらDXライブラリがしてくれる模様
return 0;
}
//WinMain
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow )
{
//VRAM利用をOFFにする
//(コメントアウトすると正常に動作する)
SetScreenMemToVramFlag(FALSE);
//フルスクリーン/ウィンドウ時の初期化箇所
if (g_bFullScreen) {
ChangeWindowMode(FALSE); //FullScreenモード
//解像度の設定
if (SetGraphMode(640,480,SCREEN_COLOR)!= DX_CHANGESCREEN_OK) {
//解像度の設定失敗
return -1;
}
SetEmuration320x240(TRUE); //320x240 倍 拡大モード
} else {
ChangeWindowMode(TRUE); //Windowモード
SetWindowSizeChangeEnableFlag(TRUE,TRUE); //ウインドウのサイズを自由に変更出来るようにする
int nPosX = 0; //ini.GetIniInteger(_T("Window"),_T("X"),INT_MIN);
int nPosY = 0; //ini.GetIniInteger(_T("Window"),_T("Y"),INT_MIN);
SetWindowInitPosition(nPosX,nPosY); //起動時のウィンドウズの位置を設定
SetWindowSizeExtendRate(1.0); //ini.GetIniDouble(_T("Window"),_T("Size"),1.0)); //拡大倍率
SetGraphMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_COLOR);
}
//各種Hook
SetHookWinProc(WndProc); //メッセージプロシージャをHook
SetWindowUserCloseEnableFlag(FALSE); //×ボタンのHook
//メニューの生成
SetUseGDIFlag(TRUE); //GDI利用
SetUseMenuFlag(TRUE); //メニュー利用
LoadMenuResource(IDR_MENU); //リソースからメニューを読み込み
SetDisplayMenuFlag(TRUE); //メニューの表示
SetMainWindowText("Test Application"); //タイトル文字
if( DxLib_Init() == -1 ) { //DXライブラリ初期化
return -1;
}
SetDrawScreen(DX_SCREEN_BACK);
SetMouseDispFlag(TRUE); //マウスカーソルの表示
int nFrame = 0;
while (1) //ゲームループ開始
{
ClearDrawScreen(); //画面のクリア
DrawBox(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,GetColor(0,255,0),FALSE); //描画枠
DrawFormatString(0,0,GetColor(255,255,255),"Frame:%d",nFrame); //フレーム数
Sleep(16);
ScreenFlip();
nFrame++;
//終了判定:×ボタン,終了メニュー,ALT+F4キー,ESCキー
if (GetWindowUserCloseFlag(TRUE) || CheckHitKey(KEY_INPUT_ESCAPE))
break; //正常終了
if (ProcessMessage()== -1)
break; //エラー終了
}
return 0 ; // ソフトの終了
}
//[EOF]
//ここまで
問題箇所は、フルスクリーンモードで初期化した後メニューから、
ウィンドウモードに切り替える選択をした際の
ChangeWindowMode(TRUE); //Windowモードに切り替え(ここで停止)
にて停止します。
プログラムはハングアップした状態となり、
メインウィドウはメッセージ処理(WM_XXX)を処理をしておらず、ゲームループに戻ることもありませんでした。
その箇所のLog.txtです。
//Log.txt抜粋ここから
ChangeWindowMode実行
ウインドウモードフラグが立てられました
ウインドウスタイルをウインドウモード用に変更します... 完了
画面モード変更処理を開始します
フォントの初期化を行います
フォントの初期化は正常に終了しました
グラフィック管理系の終了処理は正常に終了しました
ウインドウスタイルをウインドウモード用に変更します... 完了
出力画面用の DirectDrawSurface を作成します
各スクリーンメモリの配置位置
PrimaryBuffer : SYSTEMMEMORY( MEMIMG )
BaskBuffer : SYSTEMMEMORY( MEMIMG )
出力画面用の DirectDrawSurface の作成は正常に終了しました
グラフィック管理系の初期化を行います
3Dグラフィック描画機能は使用しません
フォントの初期化を行います
フォントの初期化は正常に終了しました
グラフィック管理系の初期化は正常に終了しました
画面モード変更処理は正常に終了しました
//Log.txt抜粋ここまで
Logを見る限り、画面モードの変更に失敗している様子はありませんでした。
さまざまな箇所をコメントアウト/インしながら検証したところ、
SetScreenMemToVramFlag(FALSE);
この1行がある場合(つまりはメインメモリに画像データを置いている場合)に再現しております。
サブPCは持っていないので、1台での検証です。
もしかしたら、こちらの環境依存の問題かもしれません。
開発環境は以下のとおりです。
・Visual Studio 2005 Professional Edition
(Visual C++ 2005)
・OS:WindowsXP ( Build 2600 Service Pack 3 )
・DXライブラリ Ver2.25
・CPU:AMD Athlon64X2 Dual Core Processor 3800+
・Memory:2048MB DDR2
・Graphic:Leadtek WinFast PX6600 GT TDH (GeForce 6600GT)
お忙しいところ申し訳ありません。
今のところ、VRAM利用のみに制限することにして対処しております。
もしかしたら、DXライブラリの不具合かと思われたので、こちらにて報告させていただきます。
長文失礼しました。