简体   繁体   English

CreateWindowEx函数失败,但GetLastError()返回ERROR_SUCCESS

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

I am trying to create a simple window with C/C++ using the native Windows message queue system (without .NET). 我正在尝试使用本机Windows消息队列系统(没有.NET)使用C / C ++创建一个简单的窗口。 I followed the MSDN tutorial and wrote some basic code that creates an empty window: 我按照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 );
}

When I run/debug the program, CreateWindowEx returns 0 which means it failed. 当我运行/调试程序时,CreateWindowEx返回0表示失败。 This triggers the error message "Oh shi- [error code]". 这会触发错误消息“哦shi- [错误代码]”。 The most confusing part is that the error message prints to console: 最令人困惑的部分是错误消息打印到控制台:

Oh shi- 0 哦shi- 0

The error code returned by GetLastError() is 0, which is ERROR_SUCCESS! GetLastError()返回的错误代码为0,即ERROR_SUCCESS!

I am at a total loss; 我完全失去了; what is happening? 怎么了? I am so confuse... 我很困惑......

PS I am using Visual C++ Express 2010 on Windows 7 32-bit. PS我在Windows 7 32位上使用Visual C ++ Express 2010。 I have written a Windows Procedure elsewhere but it simply returns 0 for all cases. 我已在其他地方编写过Windows程序,但它只是为所有情况返回0。 If, however, anyone wants to see it, I will be happy to show it. 但是,如果有人想看到它,我将很乐意展示它。

I have changed the Project Default character set of my Visual C++ project to "Not Set". 我已将Visual C ++项目的Project Default字符集更改为“Not Set”。 I should not need to prefix L to my things. 我不应该把L加到我的东西上。

Edit: added wnd.hInstance = hinst; 编辑:添加了wnd.hInstance = hinst;

Edit: removed the unnecessary (WNDPROC) cast 编辑:删除不必要的(WNDPROC)强制转换

Edit: added error checking for RegisterClassEx 编辑:为RegisterClassEx添加了错误检查

It turns out that the problem was with Visual C++ Express (or at least not with the code itself). 事实证明问题出在Visual C ++ Express上(或者至少不是代码本身)。 I copied the code to another project and it worked. 我将代码复制到另一个项目,它工作。

wnd.lpfnWndProc = (WNDPROC) MainWProc;

We can't see the real reason you need to use the cast but it is very fishy. 我们无法看到您需要使用演员表的真正原因,但它非常可疑。 Windows returns 0 from GetLastError() if it didn't see anything going wrong. 如果没有看到任何错误,Windows会从GetLastError()返回0。 Which can happen if the window procedure is broken. 如果窗口过程被破坏,可能会发生这种情况。 Like this one: 像这个:

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

Windows sends the WM_NCCREATE message to ask for the window to be created. Windows发送WM_NCCREATE消息以请求创建窗口。 If that message doesn't get processed then there will be no window. 如果该消息未得到处理,则将没有窗口。 And no error. 没有错误。 Fix: 固定:

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

Tweak as necessary to customize the window. 根据需要调整以自定义窗口。 Just make sure that DefWindowProc() gets called for every message that you don't want to handle yourself. 只需确保为您不想自己处理的每条消息调用DefWindowProc()。 And keep Petzold close at hand to avoid the simple mistakes. 让Petzold近在咫尺以避免简单的错误。 And lose the cast. 失去了演员。

All modern versions of Windows use Unicode internally, and by default, Visual Studio projects #define _UNICODE / UNICODE , which causes your application to link to the Unicode versions of the Windows headers. 所有现代版本的Windows都在内部使用Unicode,默认情况下,Visual Studio会生成#define _UNICODE / UNICODE ,这会导致应用程序链接到Windows标头的Unicode版本。

When you're compiling an application as Unicode, however, the character (and thus "string") types are different. 但是,当您将应用程序编译为Unicode时,字符(以及“字符串”)类型是不同的。 Instead of char , they're now wchar_t . 而不是char ,他们现在是wchar_t That means that you have to explicitly declare your string literals as long strings by prefixing them with an L . 这意味着您必须通过在前面加上L来明确地将字符串文字声明为长字符串。

Alternatively, the Windows headers hide all of this behind macros, but it's no longer necessary because Windows has been Unicode for a long time and that's very unlikely to change. 或者,Windows标头隐藏了所有这些后面的宏,但不再需要它,因为Windows已经使用了很长时间的Unicode,并且不太可能改变。

Beyond that, you're missing several things in your initialization of the WNDCLASSEX structure, like the hInstance member. 除此之外,在初始化WNDCLASSEX结构时,你会遗漏几件事,比如hInstance成员。 These things all have to be set perfectly, or things will fail. 这些都必须完美设置,否则事情就会失败。 As well, the RegisterClass(Ex) and CreateWindow(Ex) functions must be passed the exact same string values corresponding to the name of the window class, otherwise they will assume you're talking about two different things. 同样, RegisterClass(Ex)CreateWindow(Ex)函数必须传递与窗口类名称对应的完全相同的字符串值,否则它们将假设您正在讨论两个不同的事情。 Typos are not forgiven! 错别字是不可原谅的!

I highly recommend that you use the Visual Studio wizards to create a blank (but working!) project template. 我强烈建议您使用Visual Studio向导来创建一个空白(但工作!)项目模板。

The correct boilerplate code goes something like this: 正确的样板代码如下所示:

#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;
}

In my case i had to handle WNC_NCCREATE manually. 在我的情况下,我必须手动处理WNC_NCCREATE。 DefWindowProc returned zero for WNC_NCCREATE, i fixed that with: 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);
}

I had the same problem. 我有同样的问题。

In my case its just that i used visual sutdio without admin rights. 在我的情况下,它只是我使用没有管理员权限的视觉sutdio。 And i discovered that in this case i cant debug my application. 我发现在这种情况下我无法调试我的应用程序。 In debug mode without admin right, CreateWindowEx return null with error code result to 0 like you. 在没有管理员权限的调试模式下,CreateWindowEx返回null,错误代码结果为0,就像你一样。 But if you go to your build directory you can use your app (not in debug mode). 但是如果你去你的构建目录,你可以使用你的应用程序(不是在调试模式下)。 So if this the case fro you too, just start visula studio with admin right and its done. 所以如果这个案例也是你的话,那就开始使用管理员权限并完成它的visula工作室。

I think there is almost a way to use visual studio debug mode with admin right without start visual stuido with admin password each time. 我认为几乎有一种方法可以使用带有管理员权限的visual studio调试模式,而无需每次使用管理员密码启动visual stuido。 i dont know how to do that, but i think it may be possible. 我不知道该怎么做,但我认为这可能是可能的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM