Managed C++ (MC++) 連結原生 C++ 與 .NET 執行環境,本文彙整四大實務主題:托管物件刪除語意、原生庫封裝為 .NET 元件、String ↔ TCHAR* 雙向轉換、Tab 控制項背景色自訂。
__gc class ManagedClass {
public:
ManagedClass() { Console::WriteLine("ctor"); }
~ManagedClass() { Console::WriteLine("dtor"); } // 解構子 = Finalize
};
delete obj:立即呼叫解構子 (相當於 IDisposable::Dispose),但不釋放記憶體Finalize (同解構子)delete 觸發即時解構,未 delete 者在主程式結束時由 GC 清理Dispose() 供 C#/VB.NET 呼叫delete,跨語言庫必須實作 IDisposablestruct NativeNode {
int a, b;
TCHAR* str;
NativeNode* next;
};
NativeNode* AllocateList(int count);
void FreeList(NativeNode* head);
public __gc class ManagedNode {
public:
int a, b;
String* str;
// 無 next,改用 ArrayList 管理集合
};
public __gc class ListWrap {
public:
static ArrayList* CreateList(int count) {
NativeNode* native = AllocateList(count); // 呼叫原生 DLL
ArrayList* managed = new ArrayList();
for (NativeNode* n = native; n != 0; n = n->next) {
ManagedNode* m = new ManagedNode();
m->a = n->a;
m->b = n->b;
m->str = n->str; // TCHAR* → String* 隱性轉換
managed->Add(m);
}
FreeList(native); // 立即釋放原生記憶體
return managed;
}
};
ArrayList list = ListWrap.CreateList(7);
foreach (ManagedNode n in list) {
Console.WriteLine("{0}, {1}, {2}", n.a, n.b, n.str);
}
| 策略 | 優點 | 缺點 |
|---|---|---|
| 薄包裝 + 客戶端呼叫 FreeList | 單一轉換函數通用 | 洩漏原生細節,客戶端需記得釋放 |
| 厚包裝 (本文採用) | 完全隱藏原生記憶體管理,.NET 風格 API | 每個建立函數需個別包裝 |
原則:能轉為托管物件盡量轉,讓 GC 管理記憶體,除非效能極度敏感。
String __gc* s = S"Hello";
const wchar_t __pin* p = PtrToStringChars(s); // 釘住托管記憶體
// 現可安全傳給原生 API
// ANSI 版本:wcstombs 或 ATL W2A 宏
PtrToStringChars 回傳 __gc wchar_t*,指向 String 內部緩衝區__pin:防止 GC 移動記憶體導致指標失效CString 直接支援 char*/wchar_t* 指派,無需手動轉換String* s = new String("Hello"); // 或 S"Hello"
s = "World"; // 隱性轉換 char* → String*
CTabCtrl,設定 TCS_OWNERDRAWFIXED 模式DrawItem:FillSolidRect 背景、SetTextColor、DrawTextSetColor(COLORREF bg, COLORREF fg) 設定顏色class CMyPropSheet : public CPropertySheet {
CColorTabCtrl m_tabCtrl;
// OnInitDialog:
HWND hTab = (HWND)SendMessage(PSM_GETTABCONTROL);
m_tabCtrl.SubclassDlgItem(::GetDlgCtrlID(hTab), this);
m_tabCtrl.SetColor(RGB(255,255,255), RGB(255,0,0)); // 白底紅字
};
BOOL CColorPropertyPage::OnEraseBkgnd(CDC* pDC) {
CRect rc; GetClientRect(&rc);
pDC->FillSolidRect(rc, m_clrBackground);
return TRUE; // 抑制預設擦除
}
WM_CTLCOLOR 統一子控制項背景色WM_PAINT,工程量大ctl.BackColor = Color.Aquamarine; — 考慮遷移Managed C++ 是跨越原生與托管世界的橋樑。理解 delete 與 GC 的分工、善用 __pin 安全互操、封裝原生庫時優先轉換為托管集合、UI 客製化權衡成本與收益,是高效開發混合模式應用的關鍵。