2008-11-20 41 views
7

我想在不使用CRT的情況下構建控制檯應用程序,或者在任何情況下都不使用kernel32.lib以外的任何其他導入。我讓我的代碼編譯,但不能環繞的幾個問題鏈接:建立控制檯應用程序沒有CRT&默認標題?

unresolved external symbol @[email protected] 
unresolved external symbol "int __cdecl FreeLibrary(void *)" ([email protected]@[email protected]) 
unresolved external symbol "void * __cdecl LoadLibraryW(wchar_t *)" ([email protected]@[email protected]) 
unresolved external symbol "int (__cdecl*__cdecl GetProcAddress(void *,char *))(void)" ([email protected]@[email protected]) 
unresolved external symbol _wmainCRTStartup 

FreeLibrary則,LoadLibraryW和GetProcAddress我帶來的明確程序,而不是使用WINDOWS.H:

#pragma comment(lib, "kernel32.lib") 

typedef int(*FARPROC)(); 

void* LoadLibraryW(wchar_t* lpLibFileName); 
FARPROC GetProcAddress(void* hModule, char* lpProcName); 
int FreeLibrary(void* hLibModule); 

我想我的原型有些問題。 但是,更大的問題是__security_check_cookie_wmainCRTStartup,這顯然與CRT有關。 所以我想知道如何重寫入口點的默認int wmain(int argc, wchar_t* argv[])以及如何擺脫安全cookie。

回答

4

_wmainCRTStartup是調用wmain()的函數

IIRC它應該是在一些.o文件將您可以用鏈接,看看你的lib目錄中。

也許這是非常有用的閱讀太:Reduce EXE and DLL Size with LIBCTINY.LIB(和馬特·皮特里克岩石:-)

1

您可以在Windows.h中查看您的kernel32導入所需的原型。通常,窗口函數被定義爲WINAPI,其實際上是__stdcall而不是__cdecl。至少可以解決這個問題。

至於你的其他問題,你需要探索鏈接器命令行參數,看看是否有辦法讓它不從CRT中尋找東西。我不知道是否有辦法做到這一點。但是你必須找到一種方式或者定義你自己的功能(你可能不想這麼做)。

我建議只使用不同的編譯器/鏈接器。

+0

其實我已經試過它們作爲stdcalls,它並沒有解決問題。 – anon6439 2008-11-20 12:31:56

0

正確的入口點是main()而不是wmain()(因爲您正在編譯控制檯應用程序)。 安全Cookie代碼可以從CRT源代碼中切出;沒有必要在其鏈接。

+0

wmain是unicode的控制檯入口點。 – anon6439 2008-11-20 12:21:51

1

需要聲明WINDOWS.H功能爲extern「C」。

+0

謝謝!這解決了它。 – anon6439 2008-11-20 12:54:10

3

那麼,回答自己在這裏總結一下,以防別人發現這個網頁尋找信息。

正如MSalters建議的那樣,可以從CRT源盜取安全Cookie代碼,但這樣做後,我發現/GS-編譯器標誌可用於完全避免安全問題。

正如SoapBox所說,API函數需要是__stdcall,以及入口點。 我使用鏈接器命令行標誌/entry:wmain修復了入口點問題。

最後,正如Tomek指出的那樣,API函數必須在extern C中!

所以:

#pragma comment(lib, "kernel32.lib") 

typedef int(*FARPROC)(); 

extern "C" { 
    void* __stdcall LoadLibraryW(wchar_t* lpLibFileName); 
    FARPROC __stdcall GetProcAddress(void* hModule, char* lpProcName); 
    int __stdcall FreeLibrary(void* hLibModule); 
    typedef int (__stdcall *f_MessageBoxW_t)(unsigned long hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned long uType); 
    f_MessageBoxW_t fnMsg; 
    void* hUser; 
}; 

int __stdcall wmain(int argc, wchar_t* argv[]) 
{ 
    hUser = LoadLibraryW(L"user32.dll"); 
    fnMsg = (f_MessageBoxW_t)GetProcAddress(hUser, "MessageBoxW"); 
    fnMsg(0, L"foo", L"bar", 0); 
    FreeLibrary(hUser); 
    return 0; 
} 
+1

我只是寫了一個答案,包括`/ entry`選項,當我注意到你的自我回答幾乎所有的東西除外:1.包括`windows.h`不會傷害你的可執行文件的大小一點。如果你想真的確定,使用`#define WIN32_LEAN_AND_MEAN`和`#define WIN32_EXTRA_LEAN`。 Win32頭文件不包含CRT頭文件,所以這裏沒有問題。 2.您可能已經這樣做了,但將`/ NODEFAULTLIB`傳遞給鏈接器並手動鏈接到kernel32.lib等。這確實使得可執行文件的大小下降了很多。 – rubenvb 2012-09-14 13:02:58

2

更正確的入口點聲明是:

int __stdcall wmain(PVOID ThreadParam) 

沒有CRT的BaseThreadInitThunk直接調用入口點。它的傳遞指向某些東西,但不是argc + argv。

相關問題