Ander-RL
Ander-RL

Reputation: 13

Win32 Api Access violation

I´m learning Win32 api and trying to make it somewhat object oriented while also learning C++. I have created a BaseWindow class and a MainWindow class that derive from it. I have a menu that creates MessageBoxes and a menu option that creates a DialogBox.

It is when I click on this option when the program crashes.

Exception thrown at 0x00000001 in LearningWin32.exe: 0xC0000005: Access violation executing location 0x00000001.

This exception is thrown in BaseWindow.cpp

if (pBaseWindow)
    {
        OutputDebugString(L"BASE WINDOW pBASEWINDOW\n");

        pBaseWindow->m_hwnd = hwnd;
        lResult = pBaseWindow->HandleMessage(uMsg, wParam, lParam); // --> ExceptionThrown
    }

I´m not sure if it is because I don´t understand the way message flow works, because of not dominating C++ enough or both. Heres is what I have done so far.

Main.cpp

#ifndef UNICODE
#define UNICODE
#endif 

#include "MainWindow.h"


int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
    MainWindow win(hInstance, L"MainWindow", nCmdShow);

    if (!win.Create(L"Notepad --", WS_OVERLAPPEDWINDOW, 0, 1024, 720))
    {
        return 0;
    }

    // Run the message loop.

    MSG msg = { };
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}

BaseWindow.h

#pragma once

#include <Windows.h>


class BaseWindow
{

public:
    BaseWindow();

    ~BaseWindow();

    HWND Window() const;

    static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

protected:

    virtual PCWSTR  GetClassName() const = 0;
    virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;

    HWND m_hwnd;
};

BaseWindow.cpp

#include "BaseWindow.h"

BaseWindow::BaseWindow() : m_hwnd(NULL) { }

BaseWindow::~BaseWindow() { DestroyWindow(m_hwnd); }

HWND BaseWindow::Window() const { return m_hwnd; }

LRESULT CALLBACK BaseWindow::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    OutputDebugString(L"BASE WINDOW WindowProc\n");

    if (uMsg == WM_NCCREATE)
    {
        OutputDebugString(L"BASE WINDOW WindowProc -> WM_NCCREATE\n");

        CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
        BaseWindow* pBaseWindow = (BaseWindow*)pCreate->lpCreateParams;
        SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pBaseWindow);
    }

    BaseWindow* pBaseWindow = reinterpret_cast<BaseWindow*>(GetWindowLongW(hwnd, GWL_USERDATA));

    LRESULT lResult;

    if (pBaseWindow)
    {
        OutputDebugString(L"BASE WINDOW pBASEWINDOW\n");

        pBaseWindow->m_hwnd = hwnd;
        lResult = pBaseWindow->HandleMessage(uMsg, wParam, lParam);
    }
    else
    {
        OutputDebugString(L"BASE WINDOW DefWindowProc\n");

        lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return lResult;
}

MainWindow.h

#pragma once

#include "BaseWindow.h"


class MainWindow : public BaseWindow
{
private:
    HINSTANCE m_hInstance;
    LPCWSTR m_className;
    int m_nCmdShow;

public:
    MainWindow(HINSTANCE hInstance, LPCWSTR ClassName, int nCmdShow);

    //~MainWindow();

    BOOL Create(
        PCWSTR lpWindowName,
        DWORD dwStyle,
        DWORD dwExStyle = 0,
        int nWidth = CW_USEDEFAULT,
        int nHeight = CW_USEDEFAULT,
        int x = CW_USEDEFAULT,
        int y = CW_USEDEFAULT,
        HWND hWndParent = 0,
        HMENU hMenu = 0);

    virtual PCWSTR  GetClassName() const;

    virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
    
    BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
};

MainWindow.cpp

#include "MainWindow.h"
#include "resource/resource.h"

#include <string>

MainWindow::MainWindow(HINSTANCE hInstance, LPCWSTR ClassName, int nCmdShow)
    : m_hInstance(hInstance), m_className(ClassName), m_nCmdShow(nCmdShow)
{
    OutputDebugString(L"MAIN WINDOW CONSTRUCTOR\n");
}

PCWSTR  MainWindow::GetClassName() const { return m_className; }

BOOL MainWindow::Create(
    PCWSTR lpWindowName,
    DWORD dwStyle,
    DWORD dwExStyle,
    int nWidth,
    int nHeight,
    int x,
    int y,
    HWND hWndParent,
    HMENU hMenu)
{
    OutputDebugString(L"MAIN WINDOW CREATE\n");

    WNDCLASS wc = { 0 };

    wc.lpfnWndProc = BaseWindow::WindowProc;
    wc.hInstance = m_hInstance;
    wc.lpszClassName = GetClassName();
    wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
    wc.hIcon = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_ICON1));

    if (RegisterClass(&wc))
    {
        OutputDebugString(L"MAIN WINDOW CREATE CLASS REGISTERED\n");
    }
    else
    {
        OutputDebugString(L"MAIN WINDOW CREATE CLASS UNABLE TO REGISTER\n");
    }

    m_hwnd = CreateWindowEx(
        dwExStyle,
        GetClassName(),
        lpWindowName,
        dwStyle,
        x, y,
        nWidth, nHeight,
        hWndParent,
        hMenu,
        m_hInstance,
        this);

    if (!m_hwnd)
    {
        OutputDebugString(L"--------- Window Creation Failed ---------\n");
        ExitProcess(0);
    }

    // Centering the window in the screen
    RECT rc;

    GetWindowRect(m_hwnd, &rc);

    int xPos = (GetSystemMetrics(SM_CXSCREEN) - rc.right) / 2;
    int yPos = (GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2;

    SetWindowPos(m_hwnd, HWND_TOP, xPos, yPos, 0, 0, SWP_NOZORDER | SWP_NOSIZE);

    ShowWindow(m_hwnd, m_nCmdShow);
    UpdateWindow(m_hwnd);

    return (m_hwnd ? TRUE : FALSE);
}

LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    OutputDebugString(L"MAIN WINDOW HANDLEMESSAGE\n");

    switch (uMsg)
    {
    case WM_COMMAND: // Menu options
    {
        switch (LOWORD(wParam))
        {
        case ID_FILE_NEW:
            MessageBox(m_hwnd, L"New file", L"Menu option New", MB_OK | MB_ICONASTERISK);
            break;

        case ID_FILE_OPEN:
            MessageBox(m_hwnd, L"Menu option Open", L"Open", MB_OK | MB_ICONASTERISK);
            break;

        case ID_FILE_EXIT:
        {
            int msgBoxID = MessageBox(m_hwnd, L"Are you sure you want to exit?", L"Exit", MB_OKCANCEL | MB_ICONHAND);
            if (msgBoxID == IDOK) PostMessage(m_hwnd, WM_CLOSE, 0, 0);
        }
        break;

        case ID_HELP_SHOWDIALOGBOX:
        {
            OutputDebugString(L"MAIN WINDOW SHOWDIALOGBOX\n");

            int ret = DialogBox(
                m_hInstance,
                MAKEINTRESOURCE(IDD_DIALOG1),
                m_hwnd,
                (DLGPROC)AboutDlgProc(m_hwnd, uMsg, wParam, lParam));

            if (ret == IDOK) {
                MessageBox(m_hwnd, L"Dialog exited with IDOK.", L"Notice",
                    MB_OK | MB_ICONINFORMATION);
            }
            else if (ret == IDCANCEL) {
                MessageBox(m_hwnd, L"Dialog exited with IDCANCEL.", L"Notice",
                    MB_OK | MB_ICONINFORMATION);
            }
            else if (ret == -1) {
                MessageBox(m_hwnd, L"Dialog failed!", L"Error",
                    MB_OK | MB_ICONINFORMATION);
            }
        }
        break;
        }
        break;
    }

    case WM_CLOSE:
        OutputDebugString(L"MAIN WINDOW HANDLEMESSAGE -> WM_CLOSE\n");
        DestroyWindow(m_hwnd);
        return 0;

    case WM_DESTROY:
        OutputDebugString(L"MAIN WINDOW HANDLEMESSAGE -> WM_DESTROY\n");
        PostQuitMessage(0);
        return 0;

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(m_hwnd, &ps);
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
        EndPaint(m_hwnd, &ps);
    }
    return 0;

    default:
        OutputDebugString(L"MAIN WINDOW HANDLEMESSAGE -> DefWindowProc\n");
        return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
    }
    return TRUE;
}

BOOL CALLBACK MainWindow::AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
    OutputDebugString(L"MAIN WINDOW AboutDlgProc\n");

    switch (Message)
    {
    case WM_INITDIALOG:
        // Do any process before dialog is shown
        return TRUE;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDOK:
            EndDialog(hwnd, IDOK);
            break;
        case IDCANCEL:
            EndDialog(hwnd, IDCANCEL);
            break;
        }
        break;

    default:
        return FALSE;
    }
    return TRUE;
}

Edit

Solution:

Credit goes to Errorist.

Changed MainWindow.h from

BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);

to

static BOOL CALLBACK AboutDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);

and in MainWindow.cpp changed it from

int ret = DialogBox(
                m_hInstance,
                MAKEINTRESOURCE(IDD_DIALOG1),
                m_hwnd,
                (DLGPROC)AboutDlgProc(m_hwnd, uMsg, wParam, lParam));

to simply

int ret = DialogBox(
                m_hInstance,
                MAKEINTRESOURCE(IDD_DIALOG1),
                m_hwnd,
                (DLGPROC)AboutDlgProc);

Upvotes: 0

Views: 729

Answers (1)

Errorist
Errorist

Reputation: 224

don't call AboutDlgProc
rather pass the address of a valid DLGPROC to be called

    .....
    case ID_HELP_SHOWDIALOGBOX:
        {
            OutputDebugString(L"MAIN WINDOW SHOWDIALOGBOX\n");

            int ret = DialogBox(
                m_hInstance,
                MAKEINTRESOURCE(IDD_DIALOG1),
                m_hwnd,
                (DLGPROC)AboutDlgProc(m_hwnd, uMsg, wParam, lParam)); // <---- BOOL value returned
                // where a valid DLGPROC address should be passed
    ....

Upvotes: 1

Related Questions