2013-05-21 2 views
-2

Редактировать - Добавлен код для использования 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)) закончится катастрофой, но почему это имеет значение в этом случае? Для m_hWndFrame нет необходимости содержать что-либо, прежде чем вызывать «CreateWindowEx» (по крайней мере, согласно справкой в ​​VS2010), так почему это должно повлиять на результат «CreateWindowEx»?

+2

Невозможно знать наверняка, не видя полного кода, но я предполагаю, что вы передаете другой неинициализированный дескриптор в качестве родительского окна. И, случается, имеет место NULL тогда и только тогда, когда предыдущее предложение является заданием «NULL». – rodrigo

+5

Я предполагаю, что оконная процедура пытается использовать 'm_hWndFrame' внутри своего обработчика' WM_CREATE'. Поскольку это выполняется до того, как 'CreateWindowEx' вернется, он использует неинициализированную переменную. 'CreateWindowEx' не заботится о' m_hWndFrame', но может потребоваться и другие части вашего кода, которые выполняются как часть создания окна. –

+0

@RaymondChen: Но даже если он это сделает, 'CreateWindowEx' не будет терпеть неудачу, если он не вернет что-то'! = 0' из 'WM_CREATE' ... – rodrigo

ответ

1

Проблема заключается не в том, что m_hWndFrame является или не является NULL, а является ли m_hWndClient значением или не является NULL.

В обработчике WM_CREATE в WndProc создается клиентское клиентское окно MDI и ручка для него хранится в m_hWndClient. Любые необработанные сообщения проходят через линию в конце WndProc:

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

WM_CREATE Однако это не первое сообщение посылается окно (WM_NCCREATE отправляется до того WM_CREATE). Поэтому, когда получено сообщение доWM_CREATE, m_hWndClient по-прежнему не инициализировано и является недействительной оконной ручкой, как указано сообщением об ошибке.

Таким образом, инициализация m_hWndFrame технически не нужна в этом случае, но инициализация m_hWndClient в противном случае вызов DefFrameProc получает мусор для дескриптора окна клиента.