我正在尝试使用本机 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,这意味着它失败了。这会触发错误消息“Oh shi- [error code]”。最令人困惑的部分是错误消息打印到控制台:
Oh shi- 0
GetLastError()返回的错误码为0,即ERROR_SUCCESS!
我完全不知所措;怎么了?我很困惑......
附言 我在 Windows 7 32 位上使用 Visual C++ Express 2010。我在别处写了一个 Windows 程序,但它在所有情况下都只返回 0。但是,如果有人想看它,我会很乐意展示它。
我已将我的 Visual C++ 项目的项目默认字符集更改为“未设置”。我不需要在我的东西前加上 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;
}
我也有这个问题。尝试初始化窗口类的所有成员\属性。换句话说,设置剩余的成员。例如;
//Initialize the window class.
winclass.lpfnWndProc = WinProc1;
winclass.hInstance = hInstance;
winclass.hbrBackground = CreateSolidBrush(RGB(250,250,250));
winclass.lpszClassName = "mwClass";
winclass.lpszMenuName = NULL;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.style = CS_DBLCLKS | CS_OWNDC | \
CS_HREDRAW | CS_VREDRAW;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
希望这有帮助。
我有同样的问题。
就我而言,只是我使用了没有管理员权限的 visual sutdio。 我发现在这种情况下我无法调试我的应用程序。 在没有管理员权限的调试模式下,CreateWindowEx 会像您一样返回 null,错误代码结果为 0。 但是如果你去你的构建目录,你可以使用你的应用程序(不是在调试模式下)。 因此,如果您也是这种情况,只需以管理员权限启动 visula studio 即可完成。
我认为几乎有一种方法可以使用具有管理员权限的visual studio调试模式,而无需每次都使用管理员密码启动visual stuido。我不知道该怎么做,但我认为这可能是可能的。
在我的例子中,我不得不手动处理 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);
}