La boîte de dialogue WIN32 lève une exception [duplicate]

Nov 22 2020

J'essaye d'apprendre l'API win32 en utilisant la documentation Microsoft. Je suis arrivé au chapitre 4, et je semble avoir rencontré un problème que j'ai du mal à déboguer. La boîte de dialogue déclenchée par le bouton about lève une exception:

Exception levée à 0x773BDCFF (ntdll.dll) dans practice.exe: 0xC0000005: violation d'accès à l'emplacement de lecture 0x00905A4C.

Voici la déclaration des callbacks WndProc et 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);

Voici le code pour l'implémentation des rappels WndProc et 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;

J'espère que l'erreur se trouve dans ces extraits. Sinon, je serais heureux de fournir plus de code. J'ai fait des recherches, et j'ai vraiment très peu d'idée du problème. Je sais que le rappel de la fonction about doit être statique, ce que je pense. En dehors de cela, je ne sais pas ce qui lui ferait lever une exception. Merci pour toute aide que vous pouvez me donner.

Réponses

1 RitaHan-MSFT Nov 23 2020 at 09:11

Échec de la reproduction de ce problème à l'aide de votre code présenté. Ce qui suit est un exemple basé sur votre morceau de code et cela fonctionne pour moi. Vous pouvez vous référer à.

App.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);
};

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

Créez la fenêtre principale:

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