ActiveX 控件是微軟提供的強大元件開發技術,屬於 COM 元件技術的核心部分。作為 OLE 的第三個版本,它最大的擴展在於增加了 Internet 功能——不僅可在支援 OLE 的容器中使用,更能直接嵌入網頁成為網頁元件。ActiveX 控件作為可重用元件,相當於封裝良好的程式碼模組,透過方法、屬性、事件與應用程式通訊。其與開發語言無關的特性,使得任何支援 ActiveX 的平台皆可使用,實現了軟體生產的工業化,大幅降低開發成本、提高生產效率,達到資源共享。
ATL (Active Template Library) 是一套 C++ 模板庫。使用 ATL 能快速開發出高效、精簡的程式碼,同時對 COM 元件開發提供最大程度的程式碼自動生成與視覺化支援。自 Visual C++ 5.0 起,微軟將 ATL 整合進 VC++ 開發環境,現已成為標準開發工具的重要成員。
| 開發方式 | 優點 | 缺點 |
|---|---|---|
| COM SDK 直接開發 | 最基礎、最靈活 | 難度大、工作量大、需深入理解 COM、大量重複勞動 |
| MFC COM 支援 | 提高自動化程度、縮短開發時間、面向物件封裝 | 程式碼冗余大、必須依賴 MFC 執行庫 |
| ATL 技術 | 高效精簡、自動生成程式碼、視覺化支援、無額外執行庫依賴 | 學習曲線稍陡峭 |
ATL 核心技術包括:COM 技術、C++ 模板類技術、C++ 多重繼承技術。
CircleCircleCtl,其餘自動生成在生成的 CircleCtl.cpp 中實作 OnDraw 方法:
HRESULT CircleCtl::OnDraw(ATL_DRAWINFO& di) {
RECT& rc = *(RECT*)di.prcBounds;
HDC hdc = di.hdcDraw;
// 建立筆刷與畫筆
HBRUSH hBrush = CreateSolidBrush(TranslateColor(m_clrFillColor));
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
// 繪製圓形
int cx = (rc.left + rc.right) / 2;
int cy = (rc.top + rc.bottom) / 2;
int radius = min((rc.right - rc.left), (rc.bottom - rc.top)) / 2 - 2;
Ellipse(hdc, cx - radius, cy - radius, cx + radius, cy + radius);
// 恢復並清理
SelectObject(hdc, hOldBrush);
SelectObject(hdc, hOldPen);
DeleteObject(hBrush);
DeleteObject(hPen);
return S_OK;
}
透過類別檢視,在 ICircleCtl 介面加入:
Radius (long)、BorderColor (OLE_COLOR)Reset()、Animate(BOOL enable)Click()、DblClick()、RadiusChanged(long newRadius)實作範例(屬性存取):
STDMETHODIMP CircleCtl::get_Radius(long* pVal) {
*pVal = m_nRadius;
return S_OK;
}
STDMETHODIMP CircleCtl::put_Radius(long newVal) {
if (newVal < 0) return E_INVALIDARG;
m_nRadius = newVal;
Fire_RadiusChanged(newVal); // 觸發事件
InvalidateControl(); // 重繪
return S_OK;
}
CircleCtl 測試屬性、方法、事件<html>
<body>
<object id="circle1" classid="clsid:YOUR_CLSID_HERE" width="200" height="200">
<param name="FillColor" value="#FF0000">
<param name="Radius" value="50">
</object>
<script>
circle1.Animate(true);
circle1.Radius = 80;
</script>
</body>
</html>
.ocx 檔案註冊到目標機器:regsvr32 CircleCtl.ocxclassid(可從註冊表或 .idl 檔獲取)ATL 透過 IConnectionPointContainer 實作事件。定義事件介面 _ICircleCtlEvents,在 .idl 中宣告:
dispinterface _ICircleCtlEvents {
properties:
methods:
void Click();
void DblClick();
void RadiusChanged([in] long newRadius);
};
觸發事件使用 ATL 產生的 Fire_* 方法,如 Fire_RadiusChanged(newVal)。
實作 IPersistStreamInit、IPersistStorage、IPersistPropertyBag 介面,覆寫 Load/Save 方法,將屬性值序列化儲存。
| 問題 | 可能原因 | 解決方案 |
|---|---|---|
| 控件不顯示 | OnDraw 未正確繪製、尺寸為 0 | 檢查 OnDraw 邏輯、確保 InvalidateControl() 調用 |
| 屬性不保存 | 未實作持久化介面 | 加入 IPersist* 介面並實作 Load/Save |
| 事件不觸發 | 連接點未正確建立 | 檢查 .idl 事件定義、確認 Fire_* 調用 |
| 網頁無法載入 | classid 錯誤、OCX 未註冊、安全性設定 | 驗證 classid、執行 regsvr32、調整 IE 安全等級 |
ATL 提供了高效、輕量的 ActiveX 控件開發框架。掌握專案建立、介面定義、繪製邏輯、屬性方法事件實作、持久化與部署流程,即可開發出專業級的可重用控件。結合網頁嵌入能力,ActiveX 控件仍是特定企業級應用的重要技術選擇。