2016-06-01 13 views
1

Als Lernübung habe ich ein Standard-Windows-Programm geschrieben, das ein Fenster registriert und erstellt, ohne explizit Windows.h einzuschließen. Alle Header-Symbole von Windows.h wurden extrahiert und in einen benutzerdefinierten Header platziert, den ich in die Quelle einfüge. Der benutzerdefinierte Header verfügt über Typdefinitionen wie CreateWindow und WNDCLASSEX.Kompilieren auf WIN32 ohne Windows.h

Das Programm ist wie so mit cl.exe mit einer Befehlszeile kompiliert:

cl main.cpp /link opengl32.lib gdi32.lib kernel32.lib user32.lib

Es ist mein Verständnis, dass diese LIB-Dateien importieren Libs sind, die von dem zugehörigen in Funktionsadressen zum Laden von Setup-Arbeit zu tun DLLs beim Start des Prozesses. Die obige Befehlszeile funktioniert einwandfrei, wenn main.cpp direkt Windows.h enthält. Wenn Sie jedoch den benutzerdefinierten Header cl.exe einfügen, können alle Funktionsaufrufe, die in der Windows-API vorgenommen wurden, nicht verknüpft werden, obwohl die zugehörigen Import-Bibliotheken in der Befehlszeile angegeben wurden (ungelöste externe Symbolfehler).

Gibt es eine Art Sonderfall Magie cl.exe führt speziell für Windows.h? Welche Schritte sind erforderlich, um in diesem Szenario eine ordnungsgemäße Verknüpfung sicherzustellen?

Hier ist das kleinste Beispiel, das ich bauen konnte:

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; 
} 

Zusammengestellt mit:

@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% 
+1

Würde es Ihnen etwas ausmachen, ein [minimales, vollständiges und überprüfbares Beispiel] (http://stackoverflow.com/help/mcve) zu veröffentlichen. – MikeCAT

+0

@MikeCAT Okay sicher! Gib mir bitte ein paar Minuten. – Cecil

+1

@RandyGaul Behalte das ** minimal ** im Hinterkopf. –

Antwort

4

Nein, die Werkzeuge etwas nicht tun, besonders für windows.h.

Ich nehme an, Sie haben Ihre Kopfzeile falsch verstanden. Es ist schwer zu erraten, was das Problem sein könnte, ohne den Header zu sehen, aber eine Möglichkeit ragt heraus.

Für die meisten Funktionen hat Windows sowohl "ANSI" als auch "Wide" -Versionen. Was Sie als CreateWindow sehen, sind also wirklich zwei Funktionen CreateWindowA und CreateWindowW. CreateWindow existiert nur als Makro, das entweder dem *A oder dem *W Namen entspricht, abhängig davon, ob UNICODE definiert ist.

Also, wenn Sie einen Prototyp/Deklaration für eine Funktion namens CreateWindow zur Verfügung gestellt haben, es wird nicht verbinden - was in der Bibliothek vorhanden sind CreateWindowA und CreateWindowW, nicht CreateWindow.

+0

Ich würde auch in den Prototypen den passenden Calling Convention Modifier angeben und sie in einen 'extern C' Bereich stellen. –

+0

Ok, ich habe ein Beispiel hinzugefügt! @MarkRansom Eigentlich habe ich noch nicht versucht, die 'extern C' Sektion hinzuzufügen. Das brauche ich definitiv ... – Cecil

+0

@MarkRansom Ja, das war genau das Problem. Ich habe das 'externe C' vergessen, wenn hinzugefügt, mein Beispiel-Code kompiliert vollkommen in Ordnung. – Cecil