簡體   English   中英

CreateWindowEx函數失敗,但GetLastError()返回ERROR_SUCCESS

[英]CreateWindowEx function fails but GetLastError() returns ERROR_SUCCESS

我正在嘗試使用本機Windows消息隊列系統(沒有.NET)使用C / C ++創建一個簡單的窗口。 我按照MSDN教程編寫了一些創建空窗口的基本代碼:

void main()
    {
    HINSTANCE hinst;
    HWND hwndMain;
    WNDCLASSEX wnd;
    MSG msg;

    hinst = GetModuleHandle( NULL );
    memset( &wnd, 0, sizeof( wnd ) );
    wnd.cbSize = sizeof( wnd );
    wnd.lpszClassName = "MainWClass";
    wnd.lpfnWndProc = MainWProc;
    wnd.hInstance = hinst;
    int result = RegisterClassEx( &wnd );
    if( !result )
    {
        printf("RegisterClassEx error: %d\r\n", GetLastError() );
    }

    hwndMain = CreateWindowEx
        (
        0, //extended styles
        wnd.lpszClassName, //class name
        "Main Window", //window name
        WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL | WS_MINIMIZEBOX, //style tags
        CW_USEDEFAULT, //horizontal position
        CW_USEDEFAULT, //vertical position
        CW_USEDEFAULT, //width
        CW_USEDEFAULT, //height
        (HWND) NULL, //parent window
        (HMENU) NULL, //class menu
        (HINSTANCE) wnd.hInstance, //some HINSTANCE pointer
        NULL //Create Window Data?
        );

    if( !hwndMain )
    {
        printf("Oh shi- %d\n", GetLastError() );
    }
    ShowWindow( hwndMain, SW_SHOWDEFAULT );
    UpdateWindow( hwndMain );
}

當我運行/調試程序時,CreateWindowEx返回0表示失敗。 這會觸發錯誤消息“哦shi- [錯誤代碼]”。 最令人困惑的部分是錯誤消息打印到控制台:

哦shi- 0

GetLastError()返回的錯誤代碼為0,即ERROR_SUCCESS!

我完全失去了; 怎么了? 我很困惑......

PS我在Windows 7 32位上使用Visual C ++ Express 2010。 我已在其他地方編寫過Windows程序,但它只是為所有情況返回0。 但是,如果有人想看到它,我將很樂意展示它。

我已將Visual C ++項目的Project Default字符集更改為“Not Set”。 我不應該把L加到我的東西上。

編輯:添加了wnd.hInstance = hinst;

編輯:刪除不必要的(WNDPROC)強制轉換

編輯:為RegisterClassEx添加了錯誤檢查

事實證明問題出在Visual C ++ Express上(或者至少不是代碼本身)。 我將代碼復制到另一個項目,它工作。

wnd.lpfnWndProc = (WNDPROC) MainWProc;

我們無法看到您需要使用演員表的真正原因,但它非常可疑。 如果沒有看到任何錯誤,Windows會從GetLastError()返回0。 如果窗口過程被破壞,可能會發生這種情況。 像這個:

LRESULT CALLBACK MainWProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    return 0;
}

Windows發送WM_NCCREATE消息以請求創建窗口。 如果該消息未得到處理,則將沒有窗口。 沒有錯誤。 固定:

LRESULT CALLBACK MainWProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

根據需要調整以自定義窗口。 只需確保為您不想自己處理的每條消息調用DefWindowProc()。 讓Petzold近在咫尺以避免簡單的錯誤。 失去了演員。

所有現代版本的Windows都在內部使用Unicode,默認情況下,Visual Studio會生成#define _UNICODE / UNICODE ,這會導致應用程序鏈接到Windows標頭的Unicode版本。

但是,當您將應用程序編譯為Unicode時,字符(以及“字符串”)類型是不同的。 而不是char ,他們現在是wchar_t 這意味着您必須通過在前面加上L來明確地將字符串文字聲明為長字符串。

或者,Windows標頭隱藏了所有這些后面的宏,但不再需要它,因為Windows已經使用了很長時間的Unicode,並且不太可能改變。

除此之外,在初始化WNDCLASSEX結構時,你會遺漏幾件事,比如hInstance成員。 這些都必須完美設置,否則事情就會失敗。 同樣, RegisterClass(Ex)CreateWindow(Ex)函數必須傳遞與窗口類名稱對應的完全相同的字符串值,否則它們將假設您正在討論兩個不同的事情。 錯別字是不可原諒的!

我強烈建議您使用Visual Studio向導來創建一個空白(但工作!)項目模板。

正確的樣板代碼如下所示:

#include <windows.h>
#include <tchar.h>

// Define these here to minimize typos, or preferably, load them from a
// resource file at the top of the main function
#define MYCLASSNAME    TEXT("MainWndClass")
#define MYWINDOWNAME   TEXT("Main Window")

// Global variable to keep track of your hInstance
HINSTANCE g_hInstance;

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   // If you don't process any of the messages yourself, you
   // must pass them to DefWindowProc for default handling.
   return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                       LPTSTR lpCmdLine, int nCmdShow)
{     
    // Save the instance handle in a global variable.
    g_hInstance = hInstance;

    // Register your window class.
    // (A full-featured app will probably want to set additional members.)
    WNDCLASSEX wcex = {0};
    wcex.cbSize = sizeof(wcex);
    wcex.lpfnWndProc = WndProc;
    wcex.hInstance = hInstance;
    wcex.lpszClassName = MYCLASSNAME;
    if (!RegisterClassEx(&wcex))
    {
        MessageBox(NULL, TEXT("Call to RegisterClassEx failed!"), NULL, MB_OK);
        return 1;
    }

    // Create your main window.
    HWND hwndMain = CreateWindowEx(0, MYCLASSNAME, MYWINDOWNAME, WS_OVERLAPPEDWINDOW,
                                   CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL,
                                   hInstance, NULL);
    if (!hwndMain)
    {
        MessageBox(NULL, TEXT("Call to CreateWindowEx failed!"), NULL, MB_OK);
        return 1;
    }

    // Show your main window.
    ShowWindow(hwndMain, nCmdShow);
    UpdateWindow(hwndMain);

    // Run the main message loop.
    BOOL bRetVal;
    MSG msg;
    while ((bRetVal = GetMessage(&msg, NULL, 0, 0)) != 0)
    {
        if (bRetVal == -1)
        {
            MessageBox(NULL, TEXT("Error encountered in message loop!"), NULL, MB_OK);
            return 1;
        }
        else
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

在我的情況下,我必須手動處理WNC_NCCREATE。 DefWindowProc為WNC_NCCREATE返回零,我修復了:

LRESULT CALLBACK MainWProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg == WNC_NCCREATE) 
        return true;
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

我有同樣的問題。

在我的情況下,它只是我使用沒有管理員權限的視覺sutdio。 我發現在這種情況下我無法調試我的應用程序。 在沒有管理員權限的調試模式下,CreateWindowEx返回null,錯誤代碼結果為0,就像你一樣。 但是如果你去你的構建目錄,你可以使用你的應用程序(不是在調試模式下)。 所以如果這個案例也是你的話,那就開始使用管理員權限並完成它的visula工作室。

我認為幾乎有一種方法可以使用帶有管理員權限的visual studio調試模式,而無需每次使用管理員密碼啟動visual stuido。 我不知道該怎么做,但我認為這可能是可能的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM