WIN32对话框抛出异常[重复]

Posted

技术标签:

【中文标题】WIN32对话框抛出异常[重复]【英文标题】:WIN32 Dialogue Box Throws exception [duplicate] 【发布时间】:2020-11-23 04:57:13 【问题描述】:

我正在尝试使用 Microsoft 文档来学习 win32 api。我已经到了第 4 章,我似乎遇到了一个我正在努力调试的问题。 about按钮触发的对话框抛出异常:

在 practice.exe 中在 0x773BDCFF (ntdll.dll) 处引发异常:0xC0000005:访问冲突读取位置 0x00905A4C。

这里是 WndProc 和 About 回调的声明:

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);

这里是 WndProc 和 About 回调的实现代码:

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;

我希望错误出现在这些 sn-ps 中。如果没有,我很乐意提供更多代码。我做过研究,我真的不知道问题是什么。我知道 about 函数的回调必须是静态的,我相信它是静态的。除此之外,我不知道什么会导致它抛出异常。谢谢你能给我的任何帮助。

【问题讨论】:

在此处设置断点DialogBox(pApp-&gt;getInstance()pApp 很可能是空指针或无效指针 由于About是静态的,你甚至可以在调用DialogBox函数时使用App::About而不是pApp-&gt;About。甚至pApp-&gt;getInstance() 也可以替换为默认为当前应用程序的NULL “我希望错误在这些 sn-ps 中”。在调试器下运行程序。当抛出异常时,检查调用堆栈,如果需要,切换到你的最后一个函数。检查所有指针。 PtrToUlong 在 64 位模式下会损坏指针。 把整个项目放在某个地方,这样会更容易检查。 【参考方案1】:

使用您提供的代码无法重现此问题。以下是基于您的代码片段的示例,它适用于我。可以参考一下。

应用程序.h

class App

public:
    App(HINSTANCE hInstance, CONST WCHAR* clsName);
private:
    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);
    ATOM MyRegisterClass(HINSTANCE hInstance, CONST WCHAR* clsName);
;

应用程序.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;

创建主窗口:

   App pApp = App(hInst, szWindowClass);
   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, &pApp);

   if (!hWnd)
   
      return FALSE;
   

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

【讨论】:

@DanielSęk 的comment 也适用于此,PtrToUlong(pApp) 将截断指针并破坏 64 位编译中的代码。安全的演员将改为ULONG_PTR @dxiv 对。更新。谢谢。

以上是关于WIN32对话框抛出异常[重复]的主要内容,如果未能解决你的问题,请参考以下文章

为啥我们不能只抛出异常/可抛出而不是有多个异常[重复]

抛出啥异常? (Python)[重复]

c#程序vs2010中,teechart5.ocx win7 64位注册成功后,调试仍然抛出异常

对话框片段已添加异常未抛出

HttpURLConnection 抛出异常 [重复]

为啥 JPA 重复持久方法不抛出异常?