2011-03-23 79 views
3

這裏是我的節目在Visual C++ 2010 Express中啓動:C++/Windows的API - 無法找到CreateWindow的

#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++的智能感知告訴我,它無法找到CreateWindowW(即使我看到它查看Winuser.h中的#define,我可以使用F12轉到函數定義)。它也不編譯。

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

不知道發生了什麼?

感謝,

邁克

回答

7

難道是因爲CreateWindowW()真的引用CreateWindowExW()宏?

嘗試使用CreateWindowExW()代替。

+0

這樣做了。非常感謝。所以基本上,在一個API「函數」實際上是另一個函數的簡化宏時,我必須小心。 – MikeRand 2011-03-23 21:55:06

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,或者將其包裝在一組類似的宏定義中。

+0

哇!用幾個宏「修復」A和W接口到Windows的想法隨着時間的推移會變得更糟糕: - ((( – 2011-03-23 21:51:06

+0

@Bo Persson:我完全同意這一點,也許一堆小函數包裝會更好... – xtofl 2011-03-24 08:00:09

0

如果我重複您已經知道的事情,請事先道歉。

由於歷史原因(和便利我想)函數(如CreateWindow),採用字符串參數通常有兩個實現,它們以ASCII編碼的字符串或以Unicode編碼的字符串。按照慣例,它們被命名爲A或W以區別它們(例如,CreateWindowA和CreateWindowW)。

通常裸函數名是#defined是基於宏UNICODE的一個或另一個(你可以通過查看WinUser.h中的CreateWindow的定義來看到)。這就是爲什麼你使用CreateWindow變成對CreateWindowW的引用。

有時,像CreateWindow這樣的函數必須通過添加另一個參數進行擴展。再次按照慣例,這些函數通常通過向原始函數名稱添加Ex後綴來命名。 CreateWindow發生了這種情況。

如果你比較CreateWindowCreateWindowEx的定義,你會發現CreateWindowEx有一個額外的參數 - 在列表中的第一個參數:DWORD dwExStyle參數。

如果您在WinUser.h中查看CreateWindowW的定義,您會看到CreateWindowW擴展爲CreateWindowExW的一個調用,使用0L作爲第一個參數的值,並使用十一個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;