VC++中忽略所有默认库纯Win32 API编译及链接 - 计算机软件编程 - Wangye's Space
VC++中忽略所有默認庫純Win32 API編譯及鏈接 - 計算機軟件編程 - Wangye's Space
?
我們在用VC++編寫Windows程序的時候可能會發現一般可執行體(.EXE)的文件體積都比較大,于是非常羨慕那些使用Win32匯編編寫程 序的人,因為他們編寫的可執行文件非常小。其實應用程序的體積是一方面,另外應用程序的部署環境則是需要注意的另一方面,這方面我深有體會,曾經使用 Visual?Studio?2008編譯過一個C++的Win32程序,本地測試正常,但是部署到客戶機時,出現缺少什么動態庫,于是還要安裝Visual?C++?2008可再發行組件包(Visual?C++?2005?Redistributable?Package) ,這給軟件部署帶來了一定的麻煩,另外對于一個功能比較簡單的程序,安裝如此的組件包,可能心里會不好受,我們希望對于一些比較簡單的應用程序可以直接調用系統提供的API,從而降低部署程序的復雜度。
其實對于VC++我們可以采用忽略所有默認庫的方式避免編譯器引入不必要的動態鏈接庫,當然你可以使用如下的預編譯宏。
#pragma?comment(linker,?"/nodefaultlib")?
?
?
#pragma comment(linker, "/nodefaultlib")實 際上,我們還需要在屬性的?連接器->清單文件?將?生成清單?改為?否;然后選擇?清單工具->輸入和輸出?將嵌入清單改為否;在 C/C++中選擇代碼生成將緩沖區安全檢查改為否(/GS-),否則編譯會出現一個錯誤,設定程序的主入口點。注意上述配置一般在Release下,生成 文件也在Release下編譯鏈接,Debug可能無法使用,如果需要防止Debug模式編譯,可以使用如下宏命令:
#ifdef?_DEBUG#error?Debug?is?disabled?
#endif????//????_DEBUG?
#ifdef _DEBUG #error Debug is disabled #endif // _DEBUG
另外對于函數入口的重新定義可以使用如下宏以代替屬性配置。
#pragma?comment(linker,"/ENTRY:wWinMainCRTStartup")?#pragma comment(linker,"/ENTRY:wWinMainCRTStartup")
由 于這里指定使用的寬字符(Unicode)API調用,所以我們將入口點定義為wWinMainCRTStartup,ANSI版建議定義為 WinMainCRTStartup,另外Windows?API有兩個版本的API接口,ANSI版和Unicode版,ANSI版主要是為了兼容 Windows?98等舊系統,一般ANSI?API編譯的程序體積比較小,但由于現在的基于NT的新的操作系統基本使用的Unicode?API,相對 而言,對于這些系統,Unicode?API接口的速度要快于ANSI?接口的速度。
入口點做如下定義
#include?<windows.h>HINSTANCE????g_hInst????=?NULL;
int?WINAPI?SimpleMain(VOID)
{
????return?0;
}
VOID?WINAPI?wWinMainCRTStartup(VOID)
{
????g_hInst?=?GetModuleHandle(NULL);
????ExitProcess(SimpleMain());
}
?
#include <windows.h> HINSTANCE g_hInst = NULL; int WINAPI SimpleMain(VOID) { return 0; } VOID WINAPI wWinMainCRTStartup(VOID) { g_hInst = GetModuleHandle(NULL); ExitProcess(SimpleMain()); }很多朋友可能還需要獲得程序的執行命令行,以獲得所需要的執行參數,我們可以使用GetCommandLine()這個API獲得。這里提供一個我寫的分離命令的函數。
VOID?WINAPI?AnalyseCommandLine(const?LPTSTR?lpOriginal,?LPTSTR?lpParameter)??
{??
????int?i,?j,?k?=?0,?nCmdLen?=?lstrlen(lpOriginal);??
????for(i?=?nCmdLen;?i>0;?i--)??
????{??
????????if(*(lpOriginal?+?i)=='?')??
????????{??
????????????for(j=i+1;?j?<?nCmdLen+1;?j++)??
????????????{??
????????????????*(lpParameter?+?k)?=?*(lpOriginal?+?j);??
????????????????k++;??
????????????}??
????????????break;??
????????}??
????}??
??
????*(lpParameter+k)?=?'\0';??
}?
VOID WINAPI AnalyseCommandLine(const LPTSTR lpOriginal, LPTSTR lpParameter) { int i, j, k = 0, nCmdLen = lstrlen(lpOriginal); for(i = nCmdLen; i>0; i--) { if(*(lpOriginal + i)==' ') { for(j=i+1; j < nCmdLen+1; j++) { *(lpParameter + k) = *(lpOriginal + j); k++; } break; } } *(lpParameter+k) = '\0'; }
具體使用如下:
LPTSTR????lpCommand?=?NULL;??
TCHAR????zCmd[MAX_PATH];??
lpCommand?=?GetCommandLine();??
AnalyseCommandLine(lpCommand,?zCmd);??
LPTSTR?lpCommand?=?NULL;?TCHAR?zCmd[MAX_PATH];?lpCommand?=?GetCommandLine();?AnalyseCommandLine(lpCommand,?zCmd);
理 論上這樣可以編譯鏈接了,實際上還有很多錯誤,主要是鏈接方面的。由于我們使用了純Windows?API,所以不能使用memset,這時可以調用 FillMemory(RtlFillMemory)、ZeroMemory(RtlZeroMemory)等等,這時編譯會出現鏈接錯誤?是關于 _memset符號鏈接的,實際上我們并沒有使用memset,那這個錯誤是怎么產生的呢?其實微軟重新定義了RtlFillMemory等API并使它 們掛接到memset這個函數下,為了我們能夠順利編譯,我們需要在自己的頭文件里做如下處理。
#undef?RtlFillMemory???#undef?RtlZeroMemory??
??
extern?"C"?NTSYSAPI?BOOL?NTAPI???
RtlFillMemory?(?VOID?*Source1,DWORD?Source2,BYTE?Fill?);??
??
extern?"C"?NTSYSAPI?BOOL?NTAPI???
RtlZeroMemory(?PVOID?Destination,?SIZE_T?Length);??
??
#define?memset(Destination,Fill,Length)?RtlFillMemory((Destination),(Length),(Fill))?
#undef RtlFillMemory #undef RtlZeroMemory extern "C" NTSYSAPI BOOL NTAPI RtlFillMemory ( VOID *Source1,DWORD Source2,BYTE Fill ); extern "C" NTSYSAPI BOOL NTAPI RtlZeroMemory( PVOID Destination, SIZE_T Length); #define memset(Destination,Fill,Length) RtlFillMemory((Destination),(Length),(Fill))
下面我們繼續我們的編譯,在鏈接這里又出現錯誤。
error?LNK2001:?無法解析的外部符號?__imp__InitCommonControls@0error?LNK2001:?無法解析的外部符號?__imp__InitCommonControlsEx@4
跟蹤后發現這兩個函數InitCommonControls和InitCommonControlsEx由COMCTL32.dll導出,參考網上的解決方案,加入lib庫。
#include?<commctrl.h>??#pragma?comment(lib,?"comctl32.lib")?
#include <commctrl.h> #pragma comment(lib, "comctl32.lib")
錯誤依舊!經過仔細尋找發現在屬性配置里?鏈接器->輸入?在附加依賴項里填入?comctl32.lib,編譯,通過!
另外對于空間分配建議參考HeapAlloc、HeapFree等等API函數。
如果大家在操作過程中遇到什么問題歡迎討論!
轉載于:https://www.cnblogs.com/Henrya2/archive/2008/12/22/1360012.html
總結
以上是生活随笔為你收集整理的VC++中忽略所有默认库纯Win32 API编译及链接 - 计算机软件编程 - Wangye's Space的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于SSH的宠物管理系统
- 下一篇: C++制作植物大战僵尸