为什么未初始化的返回值会导致CreateWindowEx中的无效窗口句柄错误?

问题描述:

编辑 - 添加了m_hWndClient和最初未包含的WndProc的代码。为了简洁起见,我错误地认为它是不相关的。为什么未初始化的返回值会导致CreateWindowEx中的无效窗口句柄错误?

以下运行之后

HWND m_hWndFrame; 
HWND m_hWndClient; // added in Edit2 
... 
m_hWndFrame = CreateWindowEx(...) 

m_hWndFrame是NULL和GetLastError给 “错误1400 - 无效的窗口句柄”,但能正常工作:

HWND m_hWndFrame = NULL; 
HWND m_hWndClient = NULL; // added in Edit2 
... 
m_hWndFrame = CreateWindowEx(...) 

WndProc看起来是这样的:

LRESULT CALLBACK ProgramManager::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    CLIENTCREATESTRUCT clientCreate; 
    HINSTANCE hInstance = GetModuleHandle(NULL); 
    RECT clientRect; 

    switch (uMsg) 
    { 
    case WM_CREATE:   
     clientCreate.hWindowMenu = NULL; 
     clientCreate.idFirstChild = IDM_FIRSTCHILD ; 
     GetClientRect(hwnd,&clientRect); 

     s_instance->m_hWndClient = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT ("MDICLIENT"), NULL, 
      WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, clientRect.right, 
      clientRect.bottom, hwnd, (HMENU)ID_MDI_CLIENT, hInstance, 
      (LPVOID)&clientCreate); 

     return 0 ; 

    case WM_CLOSE: 
     DestroyWindow(hwnd); 
     break; 
    case WM_DESTROY: 
     PostQuitMessage(0); 
     break; 
    } 

    return DefFrameProc(hwnd,m_hWndClient,uMsg,wParam,lParam); 
} 

我的项目现在工作(经过很多头发撕裂),但我不明白为什么初始化只用于保存返回值的变量应该很重要。

显然假设变量为NULL或0而没有初始化,然后使用或测试内容(例如if (!m_unitialisedVariable))将在灾难中结束,但为什么在这种情况下它应该重要?在调用'CreateWindowEx'(至少根据VS2010中的帮助)之前,没有要求m_hWndFrame包含任何内容,那么为什么它会影响'CreateWindowEx'的结果?

+2

如果没有看到完整的代码是不可能知道的,但我的猜测是你将另一个未经初始化的句柄作为父窗口传递。当且仅当前面的句子是'NULL'赋值时,它才会保持NULL。 – rodrigo

+5

我的猜测是窗口过程试图在'WM_CREATE'处理程序中使用'm_hWndFrame'。由于它在'CreateWindowEx'返回之前执行,它使用一个未初始化的变量。 'CreateWindowEx'不关心'm_hWndFrame',但作为窗口创建一部分运行的代码的其他部分可能会关心。 –

+0

@RaymondChen:但即使他这样做,CreateWindowEx也不会失败,除非他从'WM_CREATE'返回'!= 0' ... – rodrigo

问题不在于m_hWndFrame是或不是NULL,而是m_hWndClient是否为NULL。

WndProcWM_CREATE处理程序中,创建了一个MDI客户端窗口,并为其存储m_hWndClient的句柄。任何未处理的消息通过所述线在WndProc结束:

return DefFrameProc(hwnd,m_hWndClient,uMsg,wParam,lParam); 

然而WM_CREATE不是发送到一个窗口,所述第一消息(WM_NCCREATEWM_CREATE获取之前发送)。所以当收到一条消息之前WM_CREATE,m_hWndClient仍然是未初始化的,并且是错误消息所指示的无效窗口句柄。

因此初始化m_hWndFrame在这个实例中在技术上并不是必需的,但是初始化m_hWndClient否则DefFrameProc调用会为客户端窗口的句柄获取垃圾。