如同所有入門教程,我也以「Hello, World!」起步,再逐步深入剖析 ATL 版本的必要資訊,並介紹 Win32 中鮮為人知的細節:WinMain 的 _t 相容性、如何在 MessageBox 加入自訂圖示等。
#include <stdio.h>
int main() { printf( "Hello, World!\n" ); return 0; }
對應特徵:main 為入口、printf 輸出、函數為基本單位、需 include 頭文件、\n 為跳脫字元。
#include <windows.h>
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
{ MessageBox( NULL, TEXT("Hello, World!"), TEXT("Hello"), 0 ); return 0; }
揭示:需 windows.h、入口為 WinMain、MessageBox 為常用輸出、WINAPI 即 __stdcall、HINSTANCE/LPSTR 為 Win32 型別、TEXT 宏保證 ANSI/Unicode 相容。
#include <windows.h>
#include <tchar.h>
int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
{ MessageBox( NULL, _T("Hello, World!"), _T("Hello"), 0 ); return 0; }
差異:tchar.h 提供 CRT 層級 ANSI/Unicode 相容、_tWinMain 相容命令列參數、_T 宏比 TEXT 更簡短。
請建立 Win32 Application 專案(非 ATL/COM Wizard):
//////////////////////////////////////////////////////////////////////////
// ATL GUI 程式設計配套原始碼
// 第一章 不能免俗的 "Hello, World!"
// 專案名稱:HelloWorld
// 作者:李馬
// https://www.titilima.cn
//////////////////////////////////////////////////////////////////////////
#include <atlbase.h>
CComModule _Module;
int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
{
_Module.Init( NULL, hInstance );
MessageBox( NULL, _T("Hello, World!"), _T("Hello"), 0 );
_Module.Term();
return 0;
}
atlbase.h:ATL 核心頭文件,相當於 SDK 的 windows.h。CComModule _Module:模組類實例,貫穿 ATL 框架。_Module.Init/Tem:模組初始化與卸載。atlbase.h 為 ATL 必含頭文件。CComModule 為模組類,_Module 為實例。WinMain 未變。Init 初始化模組,Term 結束處理。return 結尾。完全正確!
windows.h、tchar.h 等)。CComModule 定義:GUI 視角可視為 HINSTANCE 封裝。CComPtr、CComBSTR);ATL 7.0 (VS2003) 另含 CRegKey、CHandle 等。HRESULT Init( _ATL_OBJMAP_ENTRY* p, HINSTANCE h, const GUID* plibid = NULL );
void Term();
HINSTANCE GetModuleInstance(); // 取得 m_hInst
HINSTANCE GetResourceInstance(); // 取得 m_hInstResource,預設等於 m_hInst
全域變數 _Module 貫穿 ATL 框架。需用模組實例句柄時(如 LoadIcon),調用:
extern CComModule _Module;
HICON hIcon = ::LoadIcon( _Module.GetResourceInstance(), MAKEINTRESOURCE( IDI_YOURICON ) );
#include <atlbase.h>
CComModule _Module;
int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd )
{
_Module.Init( NULL, hInstance );
_Module.m_hInstResource = LoadLibrary( _T("shell32.dll") );
MSGBOXPARAMS mbp; ZeroMemory( &mbp, sizeof(mbp) );
mbp.cbSize = sizeof(mbp);
mbp.dwLanguageId = GetSystemDefaultLangID();
mbp.dwStyle = MB_USERICON;
mbp.hInstance = _Module.GetResourceInstance();
mbp.lpszCaption = _T("Hello");
mbp.lpszIcon = MAKEINTRESOURCE( 44 );
mbp.lpszText = _T("Hello, World!");
MessageBoxIndirect( &mbp );
FreeLibrary( _Module.m_hInstResource );
_Module.m_hInstResource = NULL;
_Module.Term();
return 0;
}

此範例展示修改 m_hInstResource 使用外部資源。WTL 繼承 CComModule 派生 CAppModule,更適合應用程式開發,詳見 WTL atlapp.h。
CComModule 直接繼承 _ATL_MODULE。CComModule 經歷繼承鏈,更具 COM 風味(ModuleInstance/ResourceInstance 可作 COM 屬性用 get/put)。atlbase.h 含更多 COM 開發工具類,與本書無關,略過。