Why does CreateWindow() take a hInstance as an argument if was already provided when the window class was registered?

c, winapi

Solution

When a window class is registered it can be global (the `CS_GLOBALCLASS` style is set) or local to the module that registers it. For global classes the class names must be unique but for module-local classes the class names can clash - there's nothing stopping two DLLs registering window classes of the same name, and an executable could load both of those DLLs.

You therefore you need to tell the `CreateWindow` function which module's instance of the named class you want to use to create the window.

Problem

When registering a window class, it's necessary to fill in the `WNDCLASS`struct, which has a `hInstance` field: ``` typedef struct { UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; } WNDCLASS ``` Then, the window is created using `CreateWindow()` which takes in these parameters: ``` HWND CreateWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam ); ``` If the `hInstance` was provided with `WNDCLASS` when the class was registered, why is it necessary to provide a `hInstance` to `CreateWindow()`? Is the `hInstance` provided to `WNDCLASS` supposed to be same as the `hInstance` provided to `CreateWindow()`? If the `WNDCLASS` `hInstance` and the `CreateWindow()` `hInstance` are different, what do they mean? Here is a sample program demonstrating class registration / window creation: ``` #include <windows.h> LPSTR szClassName = "MyClass"; HINSTANCE hInstance; LRESULT CALLBACK MyWndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) { WNDCLASS wnd; MSG msg; HWND hwnd; hInstance = hInst; wnd.style = CS_HREDRAW | CS_VREDRAW; //we will explain this later wnd.lpfnWndProc = MyWndProc; wnd.cbClsExtra = 0; wnd.cbWndExtra = 0; wnd.hInstance = hInstance; wnd.hIcon = LoadIcon(NULL, IDI_APPLICATION); //default icon wnd.hCursor = LoadCursor(NULL, IDC_ARROW); //default arrow mouse cursor wnd.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1); wnd.lpszMenuName = NULL; //no menu wnd.lpszClassName = szClassName; if(!RegisterClass(&wnd)) //register the WNDCLASS { MessageBox(NULL, "This Program Requires Windows NT", "Error", MB_OK); return 0; } hwnd = CreateWindow(szClassName, "Window Title", WS_OVERLAPPEDWINDOW, //basic window style CW_USEDEFAULT, CW_USEDEFAULT, //set starting point to default value CW_USEDEFAULT, CW_USEDEFAULT, //set all the dimensions to default value NULL, //no parent window NULL, //no menu hInstance, NULL); //no parameters to pass ShowWindow(hwnd, iCmdShow); //display the window on the screen UpdateWindow(hwnd); //make sure the window is updated correctly while(GetMessage(&msg, NULL, 0, 0)) //message loop { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } ```

Original source