2008-11-20 85 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。

相关问题