我想使用 winAPI 创建一个窗口:
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,
int nShowCmd)
{
WNDCLASSEX wClass;
HWND hWnd;
wClass.cbClsExtra=NULL;
wClass.cbSize=sizeof(WNDCLASSEX);
wClass.cbWndExtra=NULL;
wClass.hbrBackground=(HBRUSH)COLOR_WINDOW;
wClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wClass.hIcon=NULL;
wClass.hIconSm=NULL;
wClass.hInstance=hInst;
wClass.lpfnWndProc=(WNDPROC)WinProc;
wClass.lpszClassName=TEXT("Window Class");
wClass.lpszMenuName=NULL;
wClass.style=CS_HREDRAW|CS_VREDRAW|CS_DROPSHADOW ;
if(!RegisterClassEx(&wClass))
{
int nResult=GetLastError();
MessageBox(NULL,
TEXT("Window class creation failed"),
TEXT("Window Class Failed"),
MB_ICONERROR);
}
hWnd=CreateWindowEx(NULL,
TEXT("Window Class"),
TEXT("My Process Explorer"),
WS_OVERLAPPEDWINDOW,
200,
20,
800,
630,
NULL,
NULL,
hInst,
NULL);
}
但我收到访问冲突错误。 为什么?
最佳答案
Tenfour 已经在评论中指出了这一点,但值得再次重复大约 6 或 8 次:永远不要将指向窗口过程函数的指针转换为 WNDPROC
。事实上,不要投任何东西,除非你知道确切的原因你需要投它。你对他问你为什么选角的评论的回答是:
For not getting Warnings!
事实上,这正是问题所在! Actor 所做的就是告诉编译器“闭嘴,我知道我在做什么!”您不再收到警告,因为您按下了“覆盖”按钮。但这些警告是有原因的——它们试图告诉你你的代码被破坏了。编译器可以帮助你。忽略它不会走得太远,或者更糟的是,翻转覆盖位并告诉它闭嘴。正如多产的 Win32 博主 Raymond Chen 所说,A function pointer cast is a bug waiting to happen . (这是一个如此常见的错误,他还写了关于它的 here 和 here 。)
人们感到被迫强制转换函数指针的最常见原因是因为编译器试图警告他们他们的函数签名不正确。记录了窗口过程函数的正确签名 here on MSDN看起来像这样:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
当然,您可以命名您选择的函数。但是参数的数量、类型和返回值都需要与该签名匹配。
如果他们不这样做,编译器将发出错误。如果您翻转覆盖位并丢弃错误,则代码将在运行时失败,这正是您现在遇到的症状。 CreateWindowEx
函数说“嘿,哇,我不认识你试图传递给我的那个窗口过程!”
当我编写一个有效的窗口过程 stub 、删除虚假转换,然后运行您的代码时,它工作正常,没有错误。例如:
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, message, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX wClass;
HWND hWnd;
wClass.cbClsExtra=NULL;
wClass.cbSize=sizeof(WNDCLASSEX);
wClass.cbWndExtra=NULL;
wClass.hbrBackground=(HBRUSH)COLOR_WINDOW;
wClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wClass.hIcon=NULL;
wClass.hIconSm=NULL;
wClass.hInstance=hInst;
wClass.lpfnWndProc=WinProc;
wClass.lpszClassName=TEXT("Window Class");
wClass.lpszMenuName=NULL;
wClass.style=CS_HREDRAW|CS_VREDRAW|CS_DROPSHADOW ;
if(!RegisterClassEx(&wClass))
{
int nResult=GetLastError();
MessageBox(NULL,
TEXT("Window class creation failed"),
TEXT("Window Class Failed"),
MB_ICONERROR);
}
hWnd=CreateWindowEx(NULL,
TEXT("Window Class"),
TEXT("My Process Explorer"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
200,
20,
800,
630,
NULL,
NULL,
hInst,
NULL);
}
但是,还有一些需要注意的事情:
您使用的是 ANSI 入口点
WinMain
,这是不正确的,因为在 2012 年,您绝对应该针对 Unicode 进行编译。您已经在使用TEXT()
宏来确保在定义UNICODE
时您的字符串文字是宽字符串,但是您需要对入口点执行相同的操作功能。将定义更改为:int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow);
您正在正确检查
RegisterClassEx
函数的返回值,如果失败,则调用GetLastError
作为调试辅助。您应该使用CreateWindowEx
函数做同样的事情。 The documentation for that function确实表明它设置了最后一个错误:If the function fails, the return value is
NULL
. To get extended error information, callGetLastError
.因此您可以将代码更改为:
hWnd=CreateWindowEx(NULL, TEXT("Window Class"), TEXT("My Process Explorer"), WS_OVERLAPPEDWINDOW, 200, 20, 800, 630, NULL, NULL, hInst, NULL); if (!hWnd) { int nResult = GetLastError(); MessageBox(NULL, TEXT("Window creation failed"), TEXT("Window Failed"), MB_ICONERROR); }
关于c - 调用 CreateWindowEx 函数时出现访问冲突错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10869240/