简体   繁体   English

在没有Windows.h的WIN32上编译

[英]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 . 自定义标头具有类型定义,例如CreateWindowWNDCLASSEX

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实际上是两个函数CreateWindowACreateWindowW 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的函数提供了原型/声明,则不会链接-库中存在的是CreateWindowACreateWindowW ,而不是CreateWindow

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM