The Pianist
The Pianist

Reputation: 556

Access Violation Error while calling CreateWindowEx Function

I want to create a window using winAPI:

    int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,
        int nShowCmd)
 {
WNDCLASSEX wClass;
HWND hWnd;


wClass.cbClsExtra=NULL;
wClass.cbSize=sizeof(WNDCLASSEX);
wClass.cbWndExtra=NULL;
wClass.hbrBackground=(HBRUSH)COLOR_WINDOW;
wClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wClass.hIcon=NULL;
wClass.hIconSm=NULL;
wClass.hInstance=hInst;
wClass.lpfnWndProc=(WNDPROC)WinProc;
wClass.lpszClassName=TEXT("Window Class");
wClass.lpszMenuName=NULL;
wClass.style=CS_HREDRAW|CS_VREDRAW|CS_DROPSHADOW ;

if(!RegisterClassEx(&wClass))
{
    int nResult=GetLastError();
    MessageBox(NULL,
        TEXT("Window class creation failed"),
        TEXT("Window Class Failed"),
        MB_ICONERROR);
}

hWnd=CreateWindowEx(NULL,
        TEXT("Window Class"),
        TEXT("My Process Explorer"),
        WS_OVERLAPPEDWINDOW,
        200,
        20,
        800,
        630,
        NULL,
        NULL,
        hInst,
        NULL);
  }

but I get Access Violation Error. Why?

Upvotes: 1

Views: 3550

Answers (1)

Cody Gray
Cody Gray

Reputation: 244742

Tenfour already points this out in the comments, but it bears repeating again about 6 or 8 more times: Never cast the pointer to your window procedure function to WNDPROC. In fact, don't cast anything unless you know exactly why you need to cast it. Your answer to his comment asking why you're casting is telling:

For not getting Warnings!

In fact, that's precisely the problem! All a cast does is tell the compiler "Shut up, I know what I'm doing!" You aren't getting warnings anymore because you pressed the "override" button. But those warnings were there for a reason—they were trying to tell you that your code was broken. The compiler is there to help you. You won't get very far by ignoring it, or worse, flipping the override bit and telling it to shut up. As the prolific Win32 blogger Raymond Chen puts it, A function pointer cast is a bug waiting to happen. (This is such a common mistake that he also writes about it here and here.)

The most common reason that people will feel compelled to cast function pointers is because the compiler is trying to warn them that their function signature is incorrect. The correct signature for a window procedure function is documented here on MSDN and looks like this:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

You can, of course, name the function anything you choose. But the number of parameters, their types, and the return value all need to match that signature.

If they don't, the compiler will issue an error. If you flip the override bit and cast away the error, then the code will fail at runtime, which is exactly the symptoms you're experiencing now. The CreateWindowEx function is saying "hey, whoa, I don't recognize that window procedure you tried to pass me!"

When I write a valid window procedure stub, remove the spurious cast, and then run your code, it works fine with no errors. For example:

LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    return DefWindowProc(hWnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
                   LPSTR lpCmdLine, int nShowCmd)
{
    WNDCLASSEX wClass;
    HWND hWnd;

    wClass.cbClsExtra=NULL;
    wClass.cbSize=sizeof(WNDCLASSEX);
    wClass.cbWndExtra=NULL;
    wClass.hbrBackground=(HBRUSH)COLOR_WINDOW;
    wClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wClass.hIcon=NULL;
    wClass.hIconSm=NULL;
    wClass.hInstance=hInst;
    wClass.lpfnWndProc=WinProc;
    wClass.lpszClassName=TEXT("Window Class");
    wClass.lpszMenuName=NULL;
    wClass.style=CS_HREDRAW|CS_VREDRAW|CS_DROPSHADOW ;

    if(!RegisterClassEx(&wClass))
    {
        int nResult=GetLastError();
        MessageBox(NULL,
            TEXT("Window class creation failed"),
            TEXT("Window Class Failed"),
            MB_ICONERROR);
    }

    hWnd=CreateWindowEx(NULL,
            TEXT("Window Class"),
            TEXT("My Process Explorer"),
            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
            200,
            20,
            800,
            630,
            NULL,
            NULL,
            hInst,
            NULL);
}

However, a couple of other things to note:

  • You're using the ANSI entry point, WinMain, which is incorrect since in the year 2012, you should definitely be compiling for Unicode. You're already using the TEXT() macro to ensure that your string literals are wide strings when UNICODE is defined, but you need to do the same thing with your entry point function. Change the definition to:

     int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                          LPTSTR lpCmdLine, int nCmdShow);
    
  • You're correctly checking the return value of the RegisterClassEx function, and if it fails, calling GetLastError as a debugging aid. You should be doing the same thing with the CreateWindowEx function. The documentation for that function does indicate that it sets the last error:

    If the function fails, the return value is NULL. To get extended error information, call GetLastError.

    So you can change your code to:

    hWnd=CreateWindowEx(NULL,
            TEXT("Window Class"),
            TEXT("My Process Explorer"),
            WS_OVERLAPPEDWINDOW,
            200,
            20,
            800,
            630,
            NULL,
            NULL,
            hInst,
            NULL);
    if (!hWnd)
    {
       int nResult = GetLastError();
       MessageBox(NULL,
            TEXT("Window creation failed"),
            TEXT("Window Failed"),
            MB_ICONERROR);
    }
    

Upvotes: 6

Related Questions