C++ WIN32对话框引发异常
我正在尝试使用Microsoft文档学习win32 api。我已经读到了第4章,我似乎遇到了一个我正在努力调试的问题。“关于”按钮触发的对话框引发异常: practice.exe中0x773BDCFF(ntdll.dll)处引发异常:0xC0000005:访问冲突读取位置0x00905A4C 以下是WndProc的声明和关于回调的声明:C++ WIN32对话框引发异常,c++,winapi,dialog,C++,Winapi,Dialog,我正在尝试使用Microsoft文档学习win32 api。我已经读到了第4章,我似乎遇到了一个我正在努力调试的问题。“关于”按钮触发的对话框引发异常: practice.exe中0x773BDCFF(ntdll.dll)处引发异常:0xC0000005:访问冲突读取位置0x00905A4C 以下是WndProc的声明和关于回调的声明: static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK App::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
App* pApp;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
pApp = (App*)pcs->lpCreateParams;
::SetWindowLongPtrW(hWnd, GWLP_USERDATA, PtrToUlong(pApp));
return TRUE;
}
else
{
pApp = reinterpret_cast<App*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)));
if (!pApp)
return DefWindowProc(hWnd, message, wParam, lParam);
}
int wmld, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(pApp->getInstance(), MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, pApp->About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK App::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
以下是实现WndProc和回调的代码:
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK App::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
App* pApp;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
pApp = (App*)pcs->lpCreateParams;
::SetWindowLongPtrW(hWnd, GWLP_USERDATA, PtrToUlong(pApp));
return TRUE;
}
else
{
pApp = reinterpret_cast<App*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)));
if (!pApp)
return DefWindowProc(hWnd, message, wParam, lParam);
}
int wmld, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(pApp->getInstance(), MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, pApp->About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK App::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
LRESULT回调应用程序::WndProc(HWND-HWND,UINT消息,WPARAM-WPARAM,LPARAM-LPARAM)
{
App*pApp;
如果(消息==WM_创建)
{
LPCREATESTRUCT pcs=(LPCREATESTRUCT)lpram;
pApp=(应用程序*)pcs->lpCreateParams;
::SetWindowLongPtrW(hWnd、GWLP_用户数据、PtrToUlong(pApp));
返回TRUE;
}
其他的
{
pApp=reinterpret_cast(静态_cast(::GetWindowLongPtrW(hWnd,GWLP_USERDATA));
if(!pApp)
返回DefWindowProc(hWnd、message、wParam、lParam);
}
int wmld,wmEvent;
PAINTSTRUCT-ps;
HDC-HDC;
开关(信息)
{
case WM_命令:
{
int wmId=低ORD(wParam);
//解析菜单选项:
交换机(wmId)
{
案例IDM_关于:
对话框(pApp->getInstance(),MAKEINTRESOURCE(IDD_ABOUTBOX),hWnd,pApp->About);
打破
案例IDM_退出:
窗口(hWnd);
打破
违约:
返回DefWindowProc(hWnd、message、wParam、lParam);
}
}
打破
案例WM_油漆:
{
PAINTSTRUCT-ps;
HDC HDC=开始喷漆(hWnd和ps);
//TODO:在此处添加任何使用hdc的图形代码。。。
端漆(hWnd和ps);
}
打破
案例WM_销毁:
PostQuitMessage(0);
打破
违约:
返回DefWindowProc(hWnd、message、wParam、lParam);
}
返回0;
}
//关于框的消息处理程序。
INT_PTR回调应用程序::About(HWND hDlg、UINT消息、WPARAM WPARAM、LPARAM LPARAM)
{
未引用的_参数(lpram);
开关(信息)
{
案例WM_初始化对话框:
返回(INT_PTR)TRUE;
case WM_命令:
if(LOWORD(wParam)==IDOK | | LOWORD(wParam)==IDCANCEL)
{
EndDialog(hDlg、LOWORD(wParam));
返回(INT_PTR)TRUE;
}
打破
}
返回(INT_PTR)FALSE;
我希望错误在这些代码段中。如果不是,我很乐意提供更多的代码。我已经做了研究,我真的不知道问题出在哪里。我知道about函数的回调必须是静态的,我相信它是静态的。除此之外,我不知道是什么导致它抛出异常。感谢您的帮助elp您可以给我。无法使用您提供的代码重现此问题。以下是基于您的代码片段的示例,对我有效。您可以参考 附录h App.cpp
#include "App.h"
App::App(HINSTANCE hInstance, CONST WCHAR* clsName)
{
App::MyRegisterClass(hInstance, clsName);
}
ATOM App::MyRegisterClass(HINSTANCE hInstance, CONST WCHAR* clsName)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = App::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DIALOGBOXEXCEPTION));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_DIALOGBOXEXCEPTION);
wcex.lpszClassName = clsName;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
LRESULT CALLBACK App::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
App* pApp;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
pApp = (App*)pcs->lpCreateParams;
::SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pApp);
return TRUE;
}
else
{
pApp = reinterpret_cast<App*>(static_cast<LONG_PTR>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)));
if (!pApp)
return DefWindowProc(hWnd, message, wParam, lParam);
}
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(NULL, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, pApp->About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK App::About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
在这里放置一个断点
DialogBox(pApp->getInstance()
,pApp
很可能是一个空的或无效的点。如果About
是静态的,您甚至可以在调用DialogBox
函数时使用App::About
而不是pApp->About
。甚至pApp->getInstance()
可以替换为默认为当前应用程序的NULL
。“我希望错误在这些代码片段中”。在调试器下运行程序。当抛出异常时,检查调用堆栈,如果需要,切换到您的最后一个函数。检查所有指针。PtrToUlong
可以在64位模式下损坏指针。将整个项目放在某个地方,这样更容易检查。@DanielSęk的方法也适用于这里,PtrToUlong(pApp)
将截断指针并在64位编译中中断代码。安全转换将改为ULONG\u PTR
。@dxiv Right。已更新。谢谢。