作为学习练习,我编写了一个标准Windows程序,该程序注册并创建一个窗口而没有显式包含Windows.h
。Windows.h
提取了所有标头符号,并将其放置到自定义标头中,我将其包含到源代码中。自定义标头具有类似CreateWindow
和的类型定义WNDCLASSEX
。
该程序cl.exe
使用如下命令行编译:
cl main.cpp /link opengl32.lib gdi32.lib kernel32.lib user32.lib
据我了解,这些.lib文件是导入库,它们可以进行设置工作,以便在进程启动时从关联的DLL加载函数地址。如果直接main.cpp
包含上述命令行,则可以很好地工作Windows.h
。但是,cl.exe
即使在命令行中指定了关联的导入库时,包含自定义标头时也无法将所有函数调用链接到Windows API中(未解决的外部符号错误)。
是否有某种特殊情况下的魔术cl.exe
专门为表演Windows.h
?在这种情况下,需要什么步骤来确保正确的链接?
这是我可以构造的最小示例:
typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
typedef __int64 LONG_PTR, *PLONG_PTR;
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
typedef LONG_PTR LRESULT;
typedef int INT;
typedef unsigned int UINT;
typedef char CHAR;
typedef unsigned short WORD;
#define CONST const
#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name
DECLARE_HANDLE(HWND);
DECLARE_HANDLE(HINSTANCE);
DECLARE_HANDLE(HICON);
DECLARE_HANDLE(HCURSOR);
DECLARE_HANDLE(HBRUSH);
DECLARE_HANDLE(HMODULE);
typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
typedef CHAR *NPSTR, *LPSTR, *PSTR;
typedef CONST CHAR *LPCSTR, *PCSTR;
#define CALLBACK __stdcall
#define WINAPI __stdcall
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
#define DECLSPEC_IMPORT __declspec(dllimport)
#define WINUSERAPI DECLSPEC_IMPORT
#define WINBASEAPI DECLSPEC_IMPORT
#define CS_VREDRAW 0x0001
#define CS_HREDRAW 0x0002
#define CS_OWNDC 0x0020
#define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))
#define MAKEINTRESOURCE MAKEINTRESOURCEA
#define IDC_ARROW MAKEINTRESOURCE(32512)
#define NULL 0
typedef WORD ATOM; //BUGBUG - might want to remove this from minwin
typedef struct tagWNDCLASSEXA {
UINT cbSize;
/* Win 3.x */
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
/* Win 4.0 */
HICON hIconSm;
} WNDCLASSEXA, *PWNDCLASSEXA, *NPWNDCLASSEXA, *LPWNDCLASSEXA;
WINUSERAPI LRESULT CALLBACK DefWindowProcA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
WINBASEAPI HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName);
WINUSERAPI HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR lpCursorName);
WINUSERAPI ATOM WINAPI RegisterClassExA(CONST WNDCLASSEXA *);
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
return DefWindowProcA( hWnd, message, wParam, lParam );
}
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, INT sw )
{
// register window class
WNDCLASSEXA wcex = { 0 };
wcex.cbSize = sizeof( WNDCLASSEXA );
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = (HINSTANCE)GetModuleHandleA( NULL );
wcex.hIcon = NULL;
wcex.hCursor = LoadCursorA( NULL, IDC_ARROW );
wcex.lpszClassName = "Title";
RegisterClassExA( &wcex );
return 0;
}
编译:
@echo off
call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x64
set CONSOLE= -subsystem:windows
set CFLAGS= -Zi -nologo
set CFLAGS= -D__WINDOWS__ -D_CRT_SECURE_NO_WARNINGS %CFLAGS%
set LFLAGS= -incremental:no -opt:ref
set LFLAGS= user32.lib kernel32.lib %LFLAGS%
cl %CFLAGS% main.cpp -Fegame.exe /link %LFLAGS% %CONSOLE%
不,这些工具没有任何作用,尤其是对于Windows.h。
我猜你把标题弄错了。很难看到没有标题就可能是什么问题,但是一种可能性仍然存在。
对于大多数功能,Windows同时具有“ ANSI”和“ Wide”两个版本,因此您看到CreateWindow
的实际上是两个功能CreateWindowA
和CreateWindowW
。CreateWindow
仅以映射到*A
或*W
名称的宏形式存在,具体取决于是否UNICODE
定义。
因此,如果您为名为的函数提供了原型/声明CreateWindow
,则不会链接-库中存在的CreateWindowA
and和CreateWindowW
not CreateWindow
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句