標準 C 運行庫 (CRT) 提供 WinMainCRTStartup 作為真正入口點:初始化堆、線程局部存儲、全域構造函數、命令行解析,最後調用用戶 WinMain。本文展示如何繞過 CRT,直接編寫裸機風格的 WinMainCRTStartup 繪製「Hello world」到螢幕中心。
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
#include <assert.h>
void CenterText(HDC hDC, int x, int y, LPCTSTR szFace, LPCTSTR szMsg, int pt) {
HFONT hFont = CreateFont(-pt * GetDeviceCaps(hDC, LOGPIXELSY)/72, 0,0,0,
FW_BOLD, TRUE, FALSE, FALSE, ANSI_CHARSET,
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
VARIABLE_PITCH, szFace);
assert(hFont);
HGDIOBJ hOld = SelectObject(hDC, hFont);
SetTextAlign(hDC, TA_CENTER | TA_BASELINE);
SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, RGB(0,0,0xFF));
TextOut(hDC, x, y, szMsg, _tcslen(szMsg));
SelectObject(hDC, hOld);
DeleteObject(hFont);
}
const TCHAR szMessage[] = _T("Hello world");
const TCHAR szFace[] = _T("Times New Roman");
#pragma comment(linker, "-merge:rdata=.text") // 合併段,減小體積
// #pragma comment(linker, "-align:512") // 可選:指定文件對齊
extern "C" void WinMainCRTStartup() {
HDC hDC = GetDC(NULL); // 獲取整個螢幕 DC
assert(hDC);
CenterText(hDC,
GetSystemMetrics(SM_CXSCREEN)/2,
GetSystemMetrics(SM_CYSCREEN)/2,
szFace, szMessage, 72);
ReleaseDC(NULL, hDC);
ExitProcess(0); // 直接退出,不返回 CRT
}
extern "C" void WinMainCRTStartup(),extern "C" 防止 C++ 名稱修飾,鏈接器識別此符號作為入口。printf、malloc 等),直接呼叫 Win32 API。GetDC(NULL) 返回整個顯示設備上下文,可直接繪圖。CreateFont 參數詳解:高度(負值按邏輯單位)、寬度 0、斜體/底線/刪除線、字重、字符集、輸出/剪裁精度、品質、間距、字體名。TA_CENTER | TA_BASELINE 使 (x,y) 為字符串基線中心。#pragma comment(linker, "-merge:rdata=.text") 將唯讀數據段合併到代碼段,生成極小 EXE(約 2-3 KB)。ExitProcess(0) 終止進程,不執行 CRT 清理(因為沒有 CRT)。cl /c /O1 /GS- custom_entry.cpp
link /ENTRY:WinMainCRTStartup /SUBSYSTEM:WINDOWS /NODEFAULTLIB kernel32.lib user32.lib gdi32.lib custom_entry.obj
/GS- 關閉緩衝區安全檢查(需 CRT 支持)。/NODEFAULTLIB 拒絕默認庫,手動指定 kernel32/user32/gdi32。/ENTRY 確認入口點符號。atexit 登記、全域對象構造、argc/argv 解析、stdin/stdout/stderr 打開。