首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Windows 程序入口點:自定義 WinMainCRTStartup 實驗

     編輯:關於C語言

Windows 程序入口點:自定義 WinMainCRTStartup 實驗

標準 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
}

關鍵技術點

  1. 入口點簽名:extern "C" void WinMainCRTStartup(),extern "C" 防止 C++ 名稱修飾,鏈接器識別此符號作為入口。
  2. 無 CRT 依賴:不調用任何 CRT 函數(printf、malloc 等),直接呼叫 Win32 API。
  3. 獲取螢幕 DC:GetDC(NULL) 返回整個顯示設備上下文,可直接繪圖。
  4. 字體創建:CreateFont 參數詳解:高度(負值按邏輯單位)、寬度 0、斜體/底線/刪除線、字重、字符集、輸出/剪裁精度、品質、間距、字體名。
  5. 文本對齊:TA_CENTER | TA_BASELINE 使 (x,y) 為字符串基線中心。
  6. 鏈接器指令:#pragma comment(linker, "-merge:rdata=.text") 將唯讀數據段合併到代碼段,生成極小 EXE(約 2-3 KB)。
  7. 退出:ExitProcess(0) 終止進程,不執行 CRT 清理(因為沒有 CRT)。

編譯鏈接命令 (MSVC)

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 確認入口點符號。
  • 教育意義

    • 理解 Windows 可執行文件加載流程:PE 頭 → 入口點 → 進程初始化。
    • CRT 做了什麼:堆初始化、atexit 登記、全域對象構造、argc/argv 解析、stdin/stdout/stderr 打開。
    • 嵌入式/啟動器/保護模式開發中常需自定義入口點。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved