模仿 Windows 工作管理員效能頁籤,開發一個 CPU 使用率視覺化 ActiveX 控制項 (OCX),支援 VB、Delphi、VC++ 等多種開發環境呼叫。使用 MFC ActiveX 控制項專案範本,GDI 雙緩衝繪圖防閃爍。
// IDL 介面定義
interface I_CPURateControl : IDispatch {
[id(1)] void SetFreeColor(OLE_COLOR color); // 閒置區塊顏色
[id(2)] void SetUsedColor(OLE_COLOR color); // 使用區塊顏色
[id(3)] void RestoreDefaultColor(); // 還原預設配色
[id(4)] void SetUsedRate(short rate); // 設定使用率 0-100
[id(5)] void SetBKColor(OLE_COLOR color); // 背景顏色
[id(6)] void SetFontColor(OLE_COLOR color); // 文字顏色
};
void CCPURateControlCtrl::ReDrawControl()
{
CClientDC dc(this);
CDC memDC; memDC.CreateCompatibleDC(&dc);
CBitmap memBmp; memBmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
CBitmap* pOldBmp = memDC.SelectObject(&memBmp);
// 背景填充
memDC.FillSolidRect(&rc, m_BackColor);
// 建立畫筆
CPen freePen(PS_SOLID, 2, m_FreeColor);
CPen usedPen(PS_SOLID, 2, m_UsedColor);
CPen* pOldPen = memDC.SelectObject(&freePen);
// 繪製 6 條基準線 (閒置區塊)
for (int i = 0; i <= 15; i += 3) {
memDC.MoveTo(rc.left + 15, rc.top + 15 + i);
memDC.LineTo(rc.Width()/2 - 2, rc.top + 15 + i);
memDC.MoveTo(rc.Width()/2 + 2, rc.top + 15 + i);
memDC.LineTo(rc.right - 15, rc.top + 15 + i);
}
// 繪製百分比文字
CString strRate; strRate.Format(_T("%3d%%"), m_iUsedRate);
CFont font; font.CreateFont(14, 5, 0, 0, FW_NORMAL, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Arial"));
CFont* pOldFont = memDC.SelectObject(&font);
memDC.SetTextColor(m_FontColor);
memDC.SetBkMode(TRANSPARENT);
memDC.TextOut(rc.Width()/2 - 12, rc.bottom - 20, strRate);
// 根據使用率計算填充段數 (共 6 段,每段約 16.6%)
int nSegments = 0;
if (m_iUsedRate > 5) nSegments = 1;
if (m_iUsedRate > 20) nSegments = 2;
if (m_iUsedRate > 33) nSegments = 3;
if (m_iUsedRate > 50) nSegments = 4;
if (m_iUsedRate > 70) nSegments = 5;
if (m_iUsedRate > 90) nSegments = 6;
// 繪製使用率區塊 (紅線)
memDC.SelectObject(&usedPen);
int yOffset[] = {0, -3, -6, -9, -12, -16}; // 各段 Y 軸偏移
for (int j = 0; j >= yOffset[nSegments-1]; j -= 3) {
memDC.MoveTo(rc.left + 15, rc.top + 30 + j);
memDC.LineTo(rc.Width()/2 - 2, rc.top + 30 + j);
memDC.MoveTo(rc.Width()/2 + 2, rc.top + 30 + j);
memDC.LineTo(rc.right - 15, rc.top + 30 + j);
}
// 雙緩衝輸出
dc.BitBlt(rc.left, rc.top, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);
// 清理
memDC.SelectObject(pOldBmp);
memDC.SelectObject(pOldPen);
memDC.SelectObject(pOldFont);
memDC.DeleteDC(); memBmp.DeleteObject();
}
控制項本身只負責顯示,資料採集由獨立 DLL 提供:
// CPUMonitor.dll 導出函式
extern "C" __declspec(dllexport) UINT GetCpuUsage(); // 回傳 0-100
extern "C" __declspec(dllexport) UINT GetMemUsage(); // 回傳 0-100
// 容器程式 Timer 事件中呼叫
void CTestDlg::OnTimer(UINT_PTR nIDEvent)
{
m_ctrlCPU.SetUsedRate(GetCpuUsage());
m_ctrlMem.SetUsedRate(GetMemUsage());
CDialog::OnTimer(nIDEvent);
}

測試程式包含兩個控制項實例 (CPU/記憶體),配合 Timer 每秒更新數值。
// 編譯產生 CPURateControl.ocx
// 註冊命令
regsvr32 CPURateControl.ocx
// 解除註冊
regsvr32 /u CPURateControl.ocx
CPURateControl/
├── CPURateControlCtrl.h/cpp // ActiveX 控制項核心類別
├── CPURateControlPropPage.h/cpp // 屬性頁 (設計時設定)
├── CPUMonitor/ // 系能監控 DLL 專案
│ ├── CPUMonitor.cpp // PDH/WMI 取得計數器資料
│ └── CPUMonitor.def // 導出函式定義
└── TestContainer/ // MFC 對話式測試程式