[英]Compile on WIN32 without Windows.h
As a learning exercise I've written a standard Windows program that registers and creates a window without explicitly including Windows.h
. 作为学习练习,我编写了一个标准Windows程序,该程序注册并创建一个窗口,但未明确包含
Windows.h
。 All header symbols from Windows.h
have been extracted and placed into a custom header which I include into the source. Windows.h
所有标头符号均已被提取并放入自定义标头中,我将其包含在源代码中。 The custom header has type definitions like CreateWindow
and WNDCLASSEX
. 自定义标头具有类型定义,例如
CreateWindow
和WNDCLASSEX
。
The program is compiled with cl.exe
with a command line like so: 该程序使用
cl.exe
和如下命令行进行编译:
cl main.cpp /link opengl32.lib gdi32.lib kernel32.lib user32.lib
It is my understanding that these .lib files are import libs which do setup work for loading in function addresses from the associated DLLs upon process startup. 据我了解,这些.lib文件是导入库,它们可以进行设置工作,以便在进程启动时从关联的DLL加载函数地址。 The above command line will work perfectly fine if
main.cpp
includes Windows.h
directly. 如果
main.cpp
直接包含Windows.h
则上面的命令行将完全正常工作。 However, when including the custom header cl.exe
fails to link all function calls made into the Windows API, despite having specified the associated import libs on the command line (unresolved external symbol errors). 但是,即使在命令行中指定了关联的导入库,
cl.exe
包含自定义标头后, cl.exe
无法将所有函数调用链接到Windows API中(未解决的外部符号错误)。
Is there some kind of special-case magic cl.exe
performs specifically for Windows.h
? 是否有某种特殊情况下的魔术
cl.exe
专为Windows.h
执行? What steps are necessary to ensure proper linking in this scenario? 在这种情况下,需要什么步骤来确保正确的链接?
Here is the smallest example I could construct: 这是我可以构造的最小示例:
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;
}
Compiled with: 编译:
@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%
No, the tools don't do anything especially for windows.h. 不,这些工具没有任何作用,尤其是对于Windows.h。
I'd guess you've gotten your header wrong. 我猜你把标题弄错了。 It's hard to guess what the problem might be without seeing the header, but one possibility sticks out.
在没有看到标题的情况下很难猜测可能是什么问题,但是仍然存在一种可能性。
For most functions, Windows has both "ANSI" and "Wide" versions, so what you see as CreateWindow
is really two functions CreateWindowA
and CreateWindowW
. 对于大多数功能,Windows都有“ ANSI”和“ Wide”两个版本,因此您看到的
CreateWindow
实际上是两个函数CreateWindowA
和CreateWindowW
。 CreateWindow
exists only as a macro that maps to either the *A
or *W
name, depending upon whether UNICODE
is defined. CreateWindow
仅作为映射到*A
或*W
名称的宏存在,这取决于是否定义了UNICODE
。
So, if you've provided a prototype/declaration for a function named CreateWindow
, it's not going to link--what exists in the library are CreateWindowA
and CreateWindowW
, not CreateWindow
. 因此,如果您为名为
CreateWindow
的函数提供了原型/声明,则不会链接-库中存在的是CreateWindowA
和CreateWindowW
,而不是CreateWindow
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.