プロが教える店舗&オフィスのセキュリティ対策術

WIN32、VC++2005で開発中です。
ダイアログが複数あり各々に違う背景色を着けたい場合、
下記のようなプログラムを書いたのですが、IF文の中に行けません。
「i」には0が入ってしまうんですが、なぜでしょうか?
ほかにいい方法ありませんか?
ボタンコントロールではちゃんと判別してくれました。

case WM_CTLCOLORDLG:
i = GetWindowLong( (HWND)lParam, GWL_ID );
if ( i == IDD_ICHI_D ) { //位置出し画面描画
return (BOOL)CreateSolidBrush( RGB( 255,170,255 ));
}
break;

WIN32初心者なのでなるべくわかりやすくご教授お願いします。

A 回答 (3件)

こんにちは。



>>「i」には0が入ってしまうんですが、なぜでしょうか?
 ハンドルからIDが取り出せるのは、コントロールだけの様です。

>>ほかにいい方法ありませんか?
 SetWindowLong()/GetWindowLong()で自由データに構造体のポインタ等を渡してプロシージャの中で参照するやり方が手っ取り早いです。

 その為にはGWL_USERDATAフラグを使用しますが、ダイアログの場合はDWL_USERフラグの方を使用します。
 http://msdn.microsoft.com/ja-jp/library/cc364760 …

>>return (BOOL)CreateSolidBrush( RGB( 255,170,255 ));
 ブラシハンドルの削除責任はダイアログ側に有ります。此のやり方ですと、リソースが開放されないので要注意です。

 以下参考程度に。

//ダイアログのブラシとIDのペア
struct DialogData
{
explicit DialogData(UINT ui = 0, HBRUSH h = 0) : uiID(ui), hBrush(h)
{}

UINTuiID;
HBRUSHhBrush;
};

//--------------------------ダイアログプロシージャ内--------------------------------
case WM_INITDIALOG:
{
//ダイアログハンドルにlParamをセットする
::SetWindowLong(hDlg, DWL_USER, lParam);

return TRUE;
}

case WM_CTLCOLORDLG:
{
//ハンドルを取る
const HWND hDlg = (HWND)lParam;

//ハンドルにセットしたポインタを取る
const DialogData* p = (DialogData*)::GetWindowLong(hDlg, DWL_USER);

//一応確認
if(p)
{
//背景用のブラシを返す
return (BOOL)p->hBrush;
}
break;
}

case WM_DESTROY:
{
//ハンドルがなくなるので、関連付けた動的メモリを開放する
DialogData* p = (DialogData*)::GetWindowLong(hDlg, DWL_USER);
if(p)
{
//背景用のブラシハンドルを消去
::DeleteObject(p->hBrush);

//動的メモリを開放
delete p;

//無いとは思うが、念のため
::SetWindowLong(hDlg, DWL_USER, 0);
}
return FALSE;
}
//-------------------------------------------------------------------------------------

//--------------------------------ダイアログを作成する時---------------------------------
//この動的メモリをプロシージャに送り届ける
DialogData* p = new DialogData(IDD_DIALOG1, ::CreateSolidBrush( RGB( 255,170,255 )));

//最後のパラメータに指定すると、WM_INITDIALOGのlParamで受け取る事が出来ます
HWND hDlg = ::CreateDialogParam(hInst, MAKEINTRESOURCE(p->uiID), 0, &::DialogProc, (LPARAM)p);
//----------------------------------------------------------------------------------

 ダイアログを作成すると同時にデータを送り届ける為には以下を使用します。
 「CreateDialogParam()」モードレスダイアログの場合
 http://msdn.microsoft.com/ja-jp/library/cc410696 …

 「DialogBoxParam()」モーダルダイアログの場合
 http://msdn.microsoft.com/en-us/library/ms645465 …
    • good
    • 0

>「i」には0が入ってしまうんですが、なぜでしょうか?


この関数には欠陥があります。
この関数はエラー時0を返すということになっていますが
関数の成功時に返却する要求したデータフラグに対する
32 ビット値のなかに0も含まれています。

故にこの関数のエラー処理は戻り値ではなく、
SetLastError及びGetLastErrorによる
拡張エラー情報を使う必要があります
LONG Ret;
SetLastError(0);
Ret = GetWindowLong( (HWND)lParam, GWL_ID );
if ( Ret==0 && (GetLastError()!=0)){
//エラー処理
}

まずはこれで本当にエラーが無いのか、
エラーならどういたエラーなのか調べてみてください。
    • good
    • 0

★アドバイス


>ダイアログが複数あり各々に違う背景色を着けたい場合、
 ↑
 これはダイアログのプロシージャが共通なのですか?
 どの道 GetWindowLong の GWL_ID は 0(HMENUの値)になってしまうため
 質問にある方法では判定できないでしょう。
 GWL_ID はコントロールID を取得するときしか使えない。
 (ダイアログのIDではないため)
・判定方法1
 (1)SetWindowLong 関数(GWL_USERDATA)を使って ID をセット
 (2)GetWindowLong 関数(GWL_USERDATA)を使って ID を取得/判定
 または
 (1)SetProp 関数(プロパティ)を使って ID をセット
 (2)GetProp 関数(プロパティ)を使って ID を取得/判定
 という組み合わせを利用します。
・判定方法2
 グローバル変数(ハンドルの配列)を用意して WM_CTLCOLORDLG 内で
 ウインドウ・ハンドルを使って分岐する方法もあります。
 こちらの方が初心者向けです。
・あと気になった点。
>return (BOOL)CreateSolidBrush( RGB( 255,170,255 ));
 ↑
 これはマズイです。
 WM_CTLCOLORDLG 内などでは HBRUSH 型の変数に CreateSolidBrush 関数の戻り値を
 保存しておき、return のときにその保存された変数を使って戻します。
 こうしないとメモリリークとなり再描画がおかしくなります。
 (実行して画面の再描画がある回数を越えると表示がおかしくなる)

サンプル:
// 背景ブラシのグローバル変数
static HBRUSH gBrushTable[ MAX_DIALOG ]; ←ダイアログの最大値
static INT gMaxDialog; ←ダイアログの生成個数

// 共通なプロシージャ関数
BOOL CALLBACK DialogProc( HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
 switch ( uMsg ){
  case WM_INITDIALOG:
   SetWindowLong( hDlg, GWL_USERDATA, (LONG)lParam );
   return TRUE;
  case WM_CLOSE:
  {
   INT nIDD = (INT)SetWindowLong(hDlg,GWL_USERDATA);
   
   DeleteObject( gBrushTable[nIDD] );
   gBrushTable[ nIDD ] = NULL;
   EndDialog( hDlg, IDOK );
   return TRUE;
  }
  case WM_CTLCOLORDLG:
   return gBrushTable[ SetWindowLong(hDlg,GWL_USERDATA) ];
  default:
   return FALSE;
 }
}

// ダイアログ1の生成
INT nID = 1;
if ( CreateDialogParam(hInstance,MAKEINTRESOURCE(IDD),hWndParent,DialogProc,nID) != NULL ){
 gBrushTable[ nID ] = CreateSolidBrush( RGB(255,170,255) );
 gMaxDialog++;
}

// ダイアログ2の生成
INT nID = 2;
if ( CreateDialogParam(hInstance,MAKEINTRESOURCE(IDD),hWndParent,DialogProc,nID) != NULL ){
 gBrushTable[ nID ] = CreateSolidBrush( RGB(255,200,0) );
 gMaxDialog++;
}
こんな感じでどうでしょうか。
    • good
    • 0

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