Access Violation when calling Class Function from WndProc

Greetings,

I receive an access violation error when calling a Class Function from WM_MOVE in the WindowProc function.

If I instead call this Class Function from WinMain, or certain other WM_* in WindowProc, I do not get the error.

An explanation for this error would be much appreciated. My source with comment is below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <Windows.h>
#define WINDOW_NAME L"Application"
#define WINDOW_CLASSNAME L"WindowClass1"
LRESULT WINAPI WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

class CTestClass
{
private:
    int Number;
public:
    CTestClass();
    virtual ~CTestClass();
    void TestFunction();
};

CTestClass::CTestClass()
{
    Number = 100;
}

CTestClass::~CTestClass()
{
}

void CTestClass::TestFunction()
{
    if (Number == 100) // Access violation here, after calling this function from WindowProc
    {
        MessageBox(NULL, L"Test", NULL, NULL);
    }
}

CTestClass* g_TestClass;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASS WindowClass;
    ZeroMemory(&WindowClass, sizeof(WNDCLASS));
    WindowClass.style = CS_DBLCLKS;
    WindowClass.lpfnWndProc = WindowProc;
    WindowClass.cbClsExtra = 0;
    WindowClass.cbWndExtra = 0;
    WindowClass.hInstance = hInstance;
    WindowClass.hIcon = NULL;
    WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    WindowClass.lpszMenuName = NULL;
    WindowClass.lpszClassName = WINDOW_CLASSNAME;

    RegisterClass(&WindowClass);

    HWND hWnd;

    hWnd = CreateWindow(WINDOW_CLASSNAME, WINDOW_NAME, WS_OVERLAPPEDWINDOW,
                        10, 10, 800, 600, NULL, NULL, hInstance, NULL);

    ShowWindow(hWnd, nCmdShow);

    g_TestClass = new CTestClass(); // Initialize the Test Class

    MSG Message;
    Message.message = NULL;

    while (Message.message != WM_QUIT)
    {
        if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&Message);
            DispatchMessage(&Message);
        }
    }

    delete g_TestClass;

    return Message.wParam;
}

LRESULT WINAPI WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    case WM_MOVE:
        g_TestClass->TestFunction(); // Call the Test Function --> Leads to Access Violation
        return DefWindowProc(hWnd, message, wParam, lParam);    
        break;
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}


The value of "Number" variable is unknown in the debugger output.
Last edited on
The problem is that g_TestClass is still NULL when WM_MOVE is called.
The easiest solution is not to use a pointer, it works without pointer.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <Windows.h>
#define WINDOW_NAME L"Application"
#define WINDOW_CLASSNAME L"WindowClass1"
LRESULT WINAPI WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

class CTestClass
{
private:
  int Number;
public:
  CTestClass();
  virtual ~CTestClass();
  void TestFunction();
};

CTestClass::CTestClass()
{
  Number = 100;
}

CTestClass::~CTestClass()
{
}

void CTestClass::TestFunction()
{
  if (Number == 100) // Access violation here, after calling this function from WindowProc
  {
    MessageBox(NULL, L"Test", NULL, NULL);
  }
}

CTestClass g_TestClass;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASS WindowClass;
  ZeroMemory(&WindowClass, sizeof(WNDCLASS));
  WindowClass.style = CS_DBLCLKS;
  WindowClass.lpfnWndProc = WindowProc;
  WindowClass.cbClsExtra = 0;
  WindowClass.cbWndExtra = 0;
  WindowClass.hInstance = hInstance;
  WindowClass.hIcon = NULL;
  WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
  WindowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  WindowClass.lpszMenuName = NULL;
  WindowClass.lpszClassName = WINDOW_CLASSNAME;

  RegisterClass(&WindowClass);

  HWND hWnd;

  hWnd = CreateWindow(WINDOW_CLASSNAME, WINDOW_NAME, WS_OVERLAPPEDWINDOW,
    10, 10, 800, 600, NULL, NULL, hInstance, NULL);

  ShowWindow(hWnd, nCmdShow);

  MSG Message;
  Message.message = NULL;

  while (Message.message != WM_QUIT)
  {
    if (PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
    {
      TranslateMessage(&Message);
      DispatchMessage(&Message);
    }
  }
  return Message.wParam;
}

LRESULT WINAPI WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message)
  {
  case WM_DESTROY:
    PostQuitMessage(0);
    break;

  case WM_MOVE:
    g_TestClass.TestFunction(); // Call the Test Function --> Leads to Access Violation
    return DefWindowProc(hWnd, message, wParam, lParam);
    break;
  }

  return DefWindowProc(hWnd, message, wParam, lParam);
}
Thx. I previously thought that the WM_MOVE could only happen after the DispatchMessage call but I was mistaken.
If you are so enamored of using a pointer and manual memory management for your class, move g_TestClass = new CTestClass(); BEFORE your ShowWindow call.

When an app's window is created and shown for the first time there are multiple messages sent to the message queue, one of those messages sent is WM_MOVE.
An alternative to using a global variable pointer is to use the either of the cbClsExtra or cbWndExtra struct members to store the pointer to your allocate heap memory. Instead of initializing both to zero use one to reserve extra space for holding the pointer. Assign the member with new in WinMain before registering the window class, retrieve the pointer in WndProc with GetClassLongPtr.

Or set the pointer to heap memory with SetClassLongPtr before showing the window in WinMain.

You could then free the heap memory allocated either when your message pump ends WinMain as you are currently doing, or in your WM_DESTROY case in WndProc.

After all that is what those two data members are for, potentially reserving extra space for class or individual window instance custom uses.

https://stackoverflow.com/questions/13330225/cbclsextra-and-cbwndextra

Do remember the size of a pointer can be different when compiled for a 32-bit target vs. 64-bit.
cbClsExtra or cbWndExtra could conceivably be used to hold an instance of your custom class, no need to use heap memory. No heap memory, no need to delete, the extra assigned memory goes buh-bye when the app is destroyed.
I previously thought that the WM_MOVE could only happen after the DispatchMessage call but I was mistaken.



Messages are queued as soon as any API is used that can generate a message. They are only processed once the message loop is running and processing messages.
Topic archived. No new replies allowed.