C ++ / Windows API - 无法找到CreateWindow

时间:2011-03-23 21:20:25

标签: c++ c winapi detours

这是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 ++的IntelliSense告诉我它找不到CreateWindowW(即使我看到它在Winuser.h中查看#define而我可以在F12中找到函数定义)。它也没有编译。

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

知道发生了什么事吗?

谢谢,

麦克

3 个答案:

答案 0 :(得分:8)

可能是因为CreateWindowW()实际上是引用CreateWindowExW()的宏吗?

请尝试使用CreateWindowExW()

答案 1 :(得分:3)

这是预处理的代码,最终得到CreateWindow的符号(来自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

预处理器将用标识符“CreateWindowW”替换符号“CreateWindow”,它会碰到它。

接下来,虽然“CreateWindowW”是一个宏,但它无法扩展,因为它没有参数。

这就是找不到CreateWindowW的原因。您可能希望直接使用CreateWindowExW,或将其包装在一组类似的宏定义中。

答案 2 :(得分:0)

如果我重复你已经知道的事情,请提前道歉。

由于历史原因(以及我认为方便),采用字符串参数的函数(如CreateWindow)通常有两个实现,它们采用ASCII编码的字符串或Unicode编码的字符串。按照惯例,它们以A或W命名以区分它们(例如,CreateWindowA和CreateWindowW)。

通常,基于宏UNICODE(参见WinUser.h中CreateWindow的定义,您可以看到),将函数名称#defined设置为一个或另一个。这就是你使用CreateWindow变成对CreateWindowW的引用的原因。

有时,必须通过添加另一个参数来扩展CreateWindow之类的函数。按照惯例,这些函数通常通过在原始函数名称中添加Ex后缀来命名。这就发生在CreateWindow上。

如果你比较CreateWindowCreateWindowEx的定义,你会发现CreateWindowEx有一个额外的参数 - 列表中的第一个参数:DWORD dwExStyle。

如果你看一下WinUser.h中CreateWindowW的定义,你会看到CreateWindowW扩展为CreateWindowExW上的调用,使用0L作为第一个参数的值,并使用11个CreateWindowW参数作为第二个到第十二个CreateWindowExW参数

正如@Jonathan Wood已经建议的那样,您可以使用CreateWindowEx而不是CreateWindow来编译代码。为此,您还必须将dwExStyle参数添加到声明中。例如

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;

一个潜在的“问题”是你使用LPCWSTR而不是LPCTSTR声明了像lpClassName这样的参数。这意味着在非Unicode版本中,CreateWindowEx将扩展为ASCII版本CreateWindowExA,但您的字符串参数类型仍将扩展为W版本,因此您将出现不匹配。

为了保持一致,您应该将LPCWSTR参数更改为LPCTSTR,或者在声明中明确使用CreateWindowExW。为了避免将来混淆,重命名指针以匹配参数列表和实现

也是一件好事
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;