ウィンドウの作成がうまくいきません。
C++で一からWin32Apiでウィンドウを作ろうとしています。
単発のウィンドウ表示はうまくいったのですが、複数のウィンドウを表示しようとすると動作が怪しくなります。
以下にプログラムを載せさせて頂きますのでご指摘お願いします。
(1)LRESULT C_BaseWnd::LocalWindProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)の関数でメインウィンドウの処理を行っているのですが、メインウィンドウ上で「a(0x61)」キーを入力したとき新しくサブウィンドウを表示させています。その表示したサブウィンドウを閉じて再度メインウィンドウから「a(0x61)」キーを入力してサブウィンドウを表示しようとしても応答がありません。原因と改善方法を教えていただけるとうれしいです。
(2)そのほか全体的に「この記述おかしいだろう」「こうしたほうがいいんじゃないか」など細かいところでも良いので教えていただけるとうれしいです。
よろしくお願いします。
#include <Windows.h>
class C_BaseWnd
{
public:
C_BaseWnd();
virtual ~C_BaseWnd();
virtual HRESULT Init( HINSTANCE hInst, int nCmdShow, LPTSTR className, LPTSTR windowName, UINT width, UINT height, DWORD style, BOOL windowFlag );
virtual void Uninit(void);
protected:
WNDCLASSEX m_wndClassEx;
HWND m_hWnd;
// 親のウィンドウプロシージャ
virtual LRESULT LocalWindProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// 子のウィンドウプロシージャ
virtual LRESULT ChildWindProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
private:
// 個々のウィンドウプロシージャを呼び出すコールバック
static LRESULT CALLBACK s_CallWindProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
// メインウィンドウフラグ格納
bool m_bMain;
};
int WINAPI WinMain( HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow )
{
// 初期化処理
C_BaseWnd *window = new C_BaseWnd();
window->Init( hCurInst, nCmdShow, "Application Name", "Window Name", 1280, 720, WS_OVERLAPPEDWINDOW, true );
MSG msg;
while( GetMessage(&msg, NULL, 0, 0) ) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
window->Uninit();
delete window;
return 0;
}
C_BaseWnd::C_BaseWnd()
{
m_hWnd = NULL;
m_bMain = false;
}
C_BaseWnd::~C_BaseWnd()
{
}
HRESULT C_BaseWnd::Init(HINSTANCE hInst, int nCmdShow,
LPTSTR className, LPTSTR windowName, UINT width, UINT height, DWORD style, BOOL windowFlag)
{
m_wndClassEx.cbSize = sizeof(WNDCLASSEX);
m_wndClassEx.lpfnWndProc = s_CallWindProc;
m_wndClassEx.style = (CS_HREDRAW | CS_VREDRAW);
m_wndClassEx.cbClsExtra = 0;
m_wndClassEx.cbWndExtra = 0;
m_wndClassEx.hInstance = hInst;
m_wndClassEx.hIcon = NULL;
m_wndClassEx.hCursor = LoadCursor(NULL, IDC_ARROW);
m_wndClassEx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
m_wndClassEx.lpszMenuName = NULL;
m_wndClassEx.lpszClassName = className;
m_wndClassEx.hIconSm = NULL;
if( RegisterClassEx(&m_wndClassEx) == 0 ) return E_FAIL;
m_hWnd = CreateWindowEx(
0, className, windowName, style,
CW_USEDEFAULT, CW_USEDEFAULT,
width, height,
NULL, NULL, hInst, NULL);
if( m_hWnd == NULL ) return E_FAIL;
// 自身をウィンドウハンドルにセットする
SetWindowLong( m_hWnd, GWL_USERDATA, (LONG)this );
ShowWindow(m_hWnd, nCmdShow);
UpdateWindow(m_hWnd);
if( windowFlag ) m_bMain = true;
return S_OK;
}
void C_BaseWnd::Uninit(void)
{
UnregisterClass(m_wndClassEx.lpszClassName, m_wndClassEx.hInstance);
}
LRESULT C_BaseWnd::LocalWindProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg ) {
case WM_CHAR:
if( wParam == 0x61 )
{
// サブウィンドウ初期化処理
C_BaseWnd *window2 = new C_BaseWnd();
window2->Init( (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), SW_SHOW, "Application Name2", "Window Name2", 1920, 1080, WS_OVERLAPPEDWINDOW, false );
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
LRESULT C_BaseWnd::ChildWindProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg ) {
case WM_CHAR:
break;
case WM_CLOSE:
break;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
LRESULT CALLBACK C_BaseWnd::s_CallWindProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// セットした個別のインスタンスを取得
C_BaseWnd *pInst = (C_BaseWnd *)GetWindowLong(hWnd, GWL_USERDATA);
if( !pInst ) {
return DefWindowProc(hWnd, msg, wParam, lParam);
}
if( pInst->m_bMain )
{
return pInst->LocalWindProc(hWnd, msg, wParam, lParam);
}
else
{
return pInst->ChildWindProc(hWnd, msg, wParam, lParam);
}
}
お礼
偶然私の同じような事をオブジェクト指向で行っているころのHPを発見し 参考に第二引数を NULL から (void*)this のように変更してみました。 そしたらどうやらデータがコールバック関数まで行く渡ったようでメモリ警告が出なくなりました。 メモリ関数にはthisという隠れた引数を持っているので クラス定義でstaticを入れるコールバック関数はこのstaticでthisが消えてしまう事までは知っていましたが… 詳しいことはまだわかりません。そのことについては次の質問で聞こうと思います。 どうもご教授ありがとうございました。
補足
これは msdn と DirectSDK のサンプルを参考に書きました。 msdn のチュートリアルでは第三引数をNULLにするように指示されていました。 http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/directx9_c/directx/input/tuts/tut3/step1enumeratingjoysticks.asp また、DirectSDKにあるサンプルにも同じようになっていたのであえてNULLにしたのです。 ちょっと見てみてください。