Active Template Library (ATL) 是微軟提供的輕量級 C++ 範本庫,專為建構高效能、小體積的 COM 元件而設計。相較 MFC:
MFC42.DLL 等大型 DLL,控制項體積通常 < 100KB (MFC 同功能常 > 300KB)。ATLSam (自動產生類別 CATLSam、介面 IATLSam、事件 _IATLSamEvents)。☑ Apartment Threaded (單元模型,最通用)
☑ Support ISupportErrorInfo (豐富錯誤資訊)
☑ Support Connection Points (事件支援)
☑ Free Threaded Marshaler (可選,提升跨執行緒效能)
☐ Support IObjectSafety (網頁安全標記,視需求勾選)
OLEMISC_ACTIVATEWHENVISIBLE 等)。ATL 以 IDL (Interface Definition Language) 為核心,介面定義與實作分離。
ATLSam.idl 新增方法interface IATLSam : IDispatch
{
[id(1), helpstring("設定標題")] HRESULT SetCaption([in] BSTR pszCaption);
[id(2), helpstring("取得標題長度")] HRESULT GetCaptionLength([out, retval] long* pLen);
};
[in]:呼叫端傳入參數 (BSTR 需由呼叫端 SysAllocString,被呼叫端用完 SysFreeString)。[out, retval]:傳回值,自動映射為 COM 標準 HRESULT 回傳,實際值經由指標回傳。_IATLSamEvents_CP.h、Proxy/Stub 碼Visual Studio 建置專案時自動執行。
CATLSam 類別實作方法// ATLSam.h
class ATL_NO_VTABLE CATLSam :
public CComObjectRootEx,
public CComCoClass,
public IConnectionPointContainerImpl,
public IDispatchImpl,
// ... 其他繼承
{
public:
// 成員變數
CComBSTR m_bstrCaption; // 智慧指標自動管理 BSTR 生命週期
// 方法宣告
STDMETHOD(SetCaption)(BSTR pszCaption);
STDMETHOD(GetCaptionLength)(long* pLen);
};
// ATLSam.cpp
STDMETHODIMP CATLSam::SetCaption(BSTR pszCaption)
{
if (!pszCaption) return E_POINTER;
m_bstrCaption = pszCaption; // CComBSTR 自動複製字串內容
FireViewChange(); // 通知容器重繪 (若支援 IViewObjectEx)
return S_OK;
}
STDMETHODIMP CATLSam::GetCaptionLength(long* pLen)
{
if (!pLen) return E_POINTER;
*pLen = m_bstrCaption.Length(); // CComBSTR::Length() 回傳字元數 (不含結束符)
return S_OK;
}
OnDraw 覆寫ATL 控制項繼承 CComControl (透過 IOleObjectImpl、IViewObjectExImpl),需覆寫 OnDraw:
HRESULT CATLSam::OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
HDC hdc = di.hdcDraw;
// 1. 準備 GDI 物件
HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
COLORREF crOldText = SetTextColor(hdc, RGB(0,0,0));
int nOldMode = SetBkMode(hdc, TRANSPARENT);
// 2. 繪製標題文字
USES_CONVERSION; // ATL 巨集:轉換字串編碼
LPCTSTR pszText = OLE2CT(m_bstrCaption); // BSTR -> TCHAR* (視 _UNICODE 定義)
if (pszText && *pszText)
TextOut(hdc, rc.left, rc.top, pszText, lstrlen(pszText));
else
TextOut(hdc, rc.left, rc.top, _T(""), 14);
// 3. 還原 DC
SetTextColor(hdc, crOldText);
SetBkMode(hdc, nOldMode);
SelectObject(hdc, hOldFont);
return S_OK;
}
勾選 Support Connection Points 後,Wizard 在 _IATLSamEvents_CP.h 產生事件介面 Proxy 類別。觸發事件範例:
// 定義事件介面 (在 .idl 中)
dispinterface _IATLSamEvents
{
properties:
methods:
[id(1)] void OnCaptionChange(BSTR newCaption);
};
// 觸發程式碼 (在 CATLSam 方法中)
void CATLSam::FireOnCaptionChange(BSTR newCaption)
{
CComVariant varResult;
DISPPARAMS params = { &CComVariant(newCaption), NULL, 1, 0 };
// 透過 Connection Point 容器廣播
FireEvent(1, ¶ms, &varResult); // 1 為 DISPID
}
.rgs) 與部署ATL 使用 Registrar Script (.rgs) 宣告式註冊資訊,建置時自動編譯為資源並由 DllRegisterServer 執行。關鍵區段:
HKCR
{
NoRemove CLSID
{
ForceRemove {YOUR_CLSID} = s 'ATLSam Control'
{
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
ProgID = s 'ATLLib.ATLSam.1'
VersionIndependentProgID = s 'ATLLib.ATLSam'
TypeLib = s '{YOUR_LIBID}'
Control = s ''
Version = s '1.0'
// 關鍵:標記為安全 (視需求)
// Implemented Categories
// {
// {7DD95801-9882-11CF-9FA9-00AA006C42C4} = s '' // CATID_SafeForScripting
// {7DD95802-9882-11CF-9FA9-00AA006C42C4} = s '' // CATID_SafeForInitializing
// }
}
}
}
| 維度 | ATL | MFC |
|---|---|---|
| 二進位大小 | 極小 (~50-100KB) | 較大 (~300KB+ 需 MFC DLL) |
| 載入速度 | 極快 | 較慢 (載入 MFC DLL) |
| 開發效率 | 需手寫 IDL、映射表、COM 樣板碼 | Wizard/ClassWizard 高度自動化 |
| 視窗/無視窗支援 | 完整支援,手動控制 | 封裝完善,COleControl 統一處理 |
| 適用場景 | 網頁下載控制項、高效能元件、無 MFC 環境 | 企業內部豐富 UI 控制項、快速原型、MFC 既有專案 |
若專案主體為 MFC,但需開發極小型控制項:可在 MFC 專案中加入 ATL 類別 (#include <atlbase.h>),但需注意:
AfxGetModuleState) 與 ATL 模組 (_Module) 共存需小心管理資源句柄。.ocx,MFC 專案透過 #import 或動態建立方式使用。ATL 是開發高效能、輕量級 ActiveX 控制項的利器。雖起步需較深 COM 功力,但掌握 CComObjectRootEx、IDispatchImpl、IConnectionPointContainerImpl、CComControl 等核心範本類別,配合 IDL 定義介面、.rgs 註冊、OnDraw 繪圖、FireEvent 觸發事件,即可打造出體積極小、效能極佳、符合 COM 標準的專業級控制項。