2012-11-15 165 views
1

我想顯示3個窗口,但它無法創建窗口2,我不知道爲什麼。它創建了第一個窗口,我爲其他兩個窗口完成了相同的工作。WIN32多個窗口

下面是代碼:

#include <Windows.h> 

// Store handles to the main window and application instance globally. 
HWND  ghMainWnd = 0; 
HWND  ghSecdWnd = 0; 
HWND  ghThrdWnd = 0; 
HINSTANCE ghAppInst = 0; 

//======================================================================================== 
// WINDOW 1 
// Step 1: Define and implement the window procedure. 
LRESULT CALLBACK 
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 

    switch(msg) 
    { 
    // Handle left mouse button click message. 
    case WM_LBUTTONDOWN: 
     MessageBox(hWnd, "Left Mouse Button Click", "Message", MB_OK); 
     return 0; 

    // Handle key down message. 
    case WM_KEYDOWN: 
     if(wParam == VK_ESCAPE) 
      if(MessageBox(hWnd, "Are you sure?", "Quit", MB_YESNO) == IDYES) 
       DestroyWindow(ghMainWnd); 
     return 0; 

    // Handle destroy window message. 
    case WM_DESTROY: 
     PostQuitMessage(0); 
     return 0; 
    } 

    // Forward any other messages we didn't handle to the default window procedure. 
    return DefWindowProc(hWnd, msg, wParam, lParam); 

} 
//======================================================================================== 
// WINDOW 2 
//======================================================================================== 
LRESULT CALLBACK 
WndProc2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 

    switch(msg) 
    { 
    // Handle down arrow pressed. 
    case WM_KEYDOWN: 
     if(wParam == VK_DOWN) 
      MessageBox(hWnd, "Down arrow pressed 2.", "Information", MB_OK); 
     return 0; 
    case WM_LBUTTONDOWN: 
     MessageBox(hWnd, "Window 2", "Window 2", MB_OK); 
     return 0; 
    case WM_DESTROY: 
     PostQuitMessage(0); 
     return 0; 
    } 

    return DefWindowProc(hWnd, msg, wParam, lParam); 
} 
//======================================================================================== 
// WINDOW 3 
//======================================================================================== 
LRESULT CALLBACK 
WndProc3(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 

    switch(msg) 
    { 
    // Handle down arrow pressed. 
    case WM_KEYDOWN: 
     if(wParam == VK_DOWN) 
      MessageBox(hWnd, "Down arrow pressed 3.", "Information", MB_OK); 
     return 0; 
    case WM_LBUTTONDOWN: 
     MessageBox(hWnd, "Window 3", "Window 3", MB_OK); 
     return 0; 
    case WM_DESTROY: 
     PostQuitMessage(0); 
     return 0; 
    } 

    return DefWindowProc(hWnd, msg, wParam, lParam); 
} 

// WinMain: Entry point for windows application. 
int WINAPI 
    WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR cmdLine, int showCmd) 
{ 

    // Save handle to application instance. 
    ghAppInst = hInstance; 

    // Step 2: Fill out a WNDCLASS instance. 
    WNDCLASS wc; 
    wc.style   = CS_HREDRAW | CS_VREDRAW; 
    wc.lpfnWndProc = WndProc; 
    wc.cbClsExtra = 0; 
    wc.cbWndExtra = 0; 
    wc.hInstance  = ghAppInst; 
    wc.hIcon   = ::LoadIcon(0, IDI_APPLICATION); 
    wc.hCursor  = ::LoadCursor(0, IDC_ARROW); 
    wc.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); 
    wc.lpszMenuName = 0; 
    wc.lpszClassName = "MyWndClassName"; 

    // Window 2 
    WNDCLASS wc2; 
    wc2.style   = CS_HREDRAW | CS_VREDRAW; 
    wc2.lpfnWndProc = WndProc2; 
    wc2.cbClsExtra = 0; 
    wc2.cbWndExtra = 0; 
    wc2.hInstance  = ghAppInst; 
    wc.hIcon   = ::LoadIcon(0, IDI_APPLICATION); 
    wc2.hCursor  = ::LoadCursor(0, IDC_ARROW); 
    wc2.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); 
    wc2.lpszMenuName = 0; 
    wc2.lpszClassName = "MyWndClassTwo"; 

    // Window 3 
    WNDCLASS wc3; 
    wc3.style   = CS_HREDRAW | CS_VREDRAW; 
    wc3.lpfnWndProc = WndProc3; 
    wc3.cbClsExtra = 0; 
    wc3.cbWndExtra = 0; 
    wc3.hInstance  = ghAppInst; 
    wc3.hIcon   = ::LoadIcon(0, IDI_APPLICATION); 
    wc3.hCursor  = ::LoadCursor(0, IDC_ARROW); 
    wc3.lpszMenuName = 0; 
    wc3.lpszClassName = "MyWndClassThree"; 


    // Step 3: Register with WNDCLASS instance with windows. 
    RegisterClass(&wc); 
    RegisterClass(&wc2); 
    RegisterClass(&wc3); 

    // Step 4: Create the window, and save the handle in global window handle variable ghMainWnd. 
    ghMainWnd = ::CreateWindow("MyWndClassName", "Window 1", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 0, 0, 500, 500, 0, 0, ghAppInst, 0); 
    ghSecdWnd = ::CreateWindow("MyWndClassTwo", "Window 2", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 510, 0, 500, 500, 0, 0, ghAppInst, 0); 
    ghThrdWnd = ::CreateWindow("MyWndClassThree", "Window 3", WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, 0, 510, 500, 500, 0, 0, ghAppInst, 0); 

    if(ghMainWnd == 0) 
    { 
     ::MessageBox(0, "Create Window 1 - Failed", 0, 0); 
     return false; 
    } 

    if(ghSecdWnd == 0) 
    { 
     ::MessageBox(0, "Create Window 2 - Failed", 0, 0); 
     return false; 
    } 

    if(ghThrdWnd == 0) 
    { 
     ::MessageBox(0, "Create Window 3 - Failed", 0, 0); 
     return false; 
    } 

    // Step 5: Show and update the window. 
    ShowWindow(ghMainWnd, showCmd); 
    UpdateWindow(ghMainWnd); 

    ShowWindow(ghSecdWnd, showCmd); 
    UpdateWindow(ghSecdWnd); 

    ShowWindow(ghThrdWnd, showCmd); 
    UpdateWindow(ghThrdWnd); 

    // Step 6: Enter the message loop and don't quit until a WM_QUIT message is received. 
    MSG msg; 
    ZeroMemory(&msg, sizeof(MSG)); 

    while(GetMessage(&msg, 0, 0, 0)) 
    { 
     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 

    // Return exit code back to operating system. 
    return (int)msg.wParam; 

} 

它不會引發任何錯誤,但在ghSecdWnd == 0它會顯示錯誤消息。

+3

你有沒有在第二次'CreateWindow'調用之後嘗試調用'GetLastError'?它可能會揭示它爲什麼失敗的原因。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360(v=vs.85).aspx – atkretsch

+0

無法弄清楚如何? – Cypras

+0

@Cypras,我在答案中有所解釋。你必須查看函數的行爲,並根據行爲採取行動。你應該儘可能檢查錯誤。 – chris

回答

5

有兩個問題:您遇到的一個,和一個與窗口3.

創建第二個窗口後調用GetLastError()(但建立第三前)在"Cannot find the window class."結果。縱觀類設置,你已經做了以下內容:

wc.hIcon = ::LoadIcon(0, IDI_APPLICATION); 

你真正需要的是設定的wc2的圖標。即使在註冊第二類時檢查RegisterClass的返回值也會導致"The parameter is incorrect."的錯誤,表明wc2存在問題。它也是您的代碼中的一個早期位置,用於捕獲錯誤,這總是一件好事。


其次,第三個窗口有問題。你還沒有設置背景畫筆。該行添加到wc3設置:

wc3.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH); 

您應經常檢查文件,以瞭解他們失敗時什麼功能做的,並採取適當的行動。例如,如果CreateWindow失敗,返回值爲NULL,您可以撥打GetLastError以獲取更多信息。你應該在每個功能的基礎上做到這一點。以下是Window 2的兩個主要功能的示例。請記住,其他人(例如GetStockObject)也可能會失敗。

if (!RegisterClass(&wc2)) { //returns 0 if failed 
    std::cout << "Failed to register class: "; 
    std::cout << GetLastError() << '\n'; //or however you want to show it 
} 

if (!(ghSecdWnd = CreateWindow(/*...*/)) { //or ghSecdWnd = ...; if (!ghSecdWnd) 
    std::cout << "Failed to create window: "; 
    std::cout << GetLastError() << '\n'; //look at FormatMessage for a message 
} 

首先,看看RegisterClass,你看到下返回值,它失敗則返回0,表示您可以撥打GetLastError()的錯誤信息,所以我輸出。 CreateWindow說的相同,但它是NULL而不是因爲HWND是一個指針。您可以獲取您收到的錯誤代碼,並根據MSDN System Error Codes文章檢查它們,或使用FormatMessageFORMAT_MESSAGE_FROM_SYSTEM爲您做這件事。

+0

你是怎麼調用GetLastError函數的?我無法弄清楚。 – Cypras

+0

可能值得注意的是,在Visual Studio 2012中,我有一個名爲Error Lookup的工具,我可以輸入錯誤代碼來獲取字符串。我不記得它是否與VS2012一起出現,或者我添加了它,但是當我不想設置FormatMessage時它非常有用。 – chris