MikeRand
MikeRand

Reputation: 4838

C++/Windows API - Unable to find CreateWindow

Here's the start of my program in Visual C++ 2010 Express:

#pragma comment(lib, "detoured.lib")
#pragma comment(lib, "detours.lib")

#include <Windows.h>
#include <detours.h>

HWND (WINAPI *pCreateWindow)(LPCWSTR lpClassName,
                             LPCWSTR lpWindowName, DWORD dwStyle,
                             int x, int y, int nWidth, int nHeight,
                             HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
                             LPVOID lpParam) = CreateWindow;

Visual C++'s IntelliSense is telling me that it can't find CreateWindowW (even though I see it looking at the #define in Winuser.h and I can F12 to go to the function definition). It doesn't compile, either.

dllmain.cpp(11): error C2065: 'CreateWindowW' : undeclared identifier

Any idea what's happening?

Thanks,

Mike

Upvotes: 3

Views: 3556

Answers (3)

Frank Boyne
Frank Boyne

Reputation: 4580

Apologies in advance if I'm repeating things you already know.

For historical reasons (and convenience I suppose) functions (like CreateWindow) that take string parameters often have two implementations that take strings encoded in ASCII or strings encoded in Unicode. By convention they are named with an A or W to distinguish them (e.g., CreateWindowA and CreateWindowW).

Usually the bare function name is #defined to be one or the other based on the macro UNICODE (you can see that by looking at the definition of CreateWindow in WinUser.h). That's why your use of CreateWindow is turning into a reference to CreateWindowW.

Sometimes, functions like CreateWindow have to be extended by adding another parameter. Again by convention these functions are often named by adding an Ex suffix to the original function name. That has happened with CreateWindow.

If you compare the definitions of CreateWindow and CreateWindowEx you'll find that CreateWindowEx has an additional parameter - the first parameter in the list: DWORD dwExStyle.

If you look at the definition for CreateWindowW in WinUser.h, you'll see that CreateWindowW expands into a call on CreateWindowExW using 0L as the value for the first parameter and using the eleven CreateWindowW parameters as the second through twelfth CreateWindowExW parameters.

As @Jonathan Wood already suggested, you can get the code to compile by using CreateWindowEx instead of CreateWindow. To do that you'll also have to add the dwExStyle parameter to your declaration. For example

HWND (WINAPI *pCreateWindow)(DWORD dwExStyle, LPCWSTR lpClassName,
    LPCWSTR lpWindowName, DWORD dwStyle,
    int x, int y, int nWidth, int nHeight,
    HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
    LPVOID lpParam) = CreateWindowEx;

One potential "gotcha" is that you've declared parameters like lpClassName using LPCWSTR rather than LPCTSTR. That means in non-Unicode builds CreateWindowEx will expand to the ASCII version CreateWindowExA but your string parameters types will still expand to the W version so you'll have a mismatch.

To be consistent you should really either change the LPCWSTR parameters to be LPCTSTR or else explicitly use CreateWindowExW in your declaration. To avoid future confusion it would also be good to rename the pointer to match the parameter list and implementation

HWND (WINAPI *pCreateWindowExW)(DWORD dwExStyle, LPCWSTR lpClassName,
    LPCWSTR lpWindowName, DWORD dwStyle,
    int x, int y, int nWidth, int nHeight,
    HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
    LPVOID lpParam) = CreateWindowExW;

Upvotes: 0

Jonathan Wood
Jonathan Wood

Reputation: 67345

Could it be because CreateWindowW() is really a macro that references CreateWindowExW()?

Try using CreateWindowExW() instead.

Upvotes: 8

xtofl
xtofl

Reputation: 41519

This is the code being preprocessed to end up with a symbol for CreateWindow (from WinUser.h):

WINUSERAPI
HWND
WINAPI
CreateWindowExW(
    __in DWORD dwExStyle,
    ... params
    __in_opt LPVOID lpParam);

#define CreateWindowEx  CreateWindowExW

#define CreateWindowW(lpClassName, ... parameters )\
  CreateWindowExW(0L, lpClassName, ... parameters )

#define CreateWindow  CreateWindowW

The preprocessor will replace the symbol "CreateWindow" by the identifier "CreateWindowW" where it bumps into it.

Next, although "CreateWindowW" is a macro, it can not expanded because there are no arguments to it.

That is why CreateWindowW is not found. You may want to use CreateWindowExW directly, or wrap it in a similar bunch of macro definitions.

Upvotes: 3

Related Questions