.NET 與 COM 互操作時,建立 COM 物件有四種主要方式,各有適用場景與優缺點。本文系統比較:匯入類型庫 (TLB)、反射晚期繫結、P/Invoke CoCreateInstance、自訂 ComImport 類別。
Interop.XXX.dll (或內嵌型別資訊),提供強型別包裝。
Type t = Type.GetTypeFromCLSID(new Guid("DE88C160-FF2C-11D1-BB6F-00C04FAE22DA")); // JetEngine
// 或 Type.GetTypeFromProgID("JRO.JetEngine");
object comObj = Activator.CreateInstance(t);
// 呼叫方法
t.InvokeMember("CompactDatabase", BindingFlags.InvokeMethod, null, comObj, new object[] { src, dest });
[DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false)]
static extern void CoCreateInstance(ref Guid clsid, IntPtr punkOuter, uint context, ref Guid iid, out IntPtr ppv);
Guid clsid = new Guid("DE88C160-FF2C-11D1-BB6F-00C04FAE22DA");
Guid iid = new Guid("9F63D980-FF25-11D1-BB6F-00C04FAE22DA"); // IJetEngine
CoCreateInstance(ref clsid, IntPtr.Zero, 1 /*CLSCTX_INPROC_SERVER*/, ref iid, out IntPtr pJet);
// 需手動 Marshal.GetObjectForIUnknown(pJet) 轉 RCW
[ComImport, Guid("DE88C160-FF2C-11D1-BB6F-00C04FAE22DA")]
class JetEngineClass { } // 空類別,僅作建立入口
[ComImport, CoClass(typeof(JetEngineClass)), Guid("9F63D980-FF25-11D1-BB6F-00C04FAE22DA")]
interface IJetEngine
{
void CompactDatabase([In, MarshalAs(UnmanagedType.BStr)] string src,
[In, MarshalAs(UnmanagedType.BStr)] string dest);
void RefreshCache([In, MarshalAs(UnmanagedType.Interface)] object conn);
}
// 使用
JetEngineClass engine = new JetEngineClass(); // CLR 依 Guid 建立 COM 物件
IJetEngine jet = engine as IJetEngine; // 查詢介面
jet.CompactDatabase("src.mdb", "dest.mdb");
Word.ApplicationClass)System.__ComObject (晚期繫結 RCW)但同一 COM 物件的不同介面查詢結果,皆為同一 RCW 實例 (CLR 內部快取)。
| 場景 | 推薦方式 |
|---|---|
| Office 自動化、複雜型別庫、團隊開發 | 方式一 (匯入 TLB) + 內嵌互操作類型 |
| 簡單 COM、無型別庫、版本不固定、輕量部署 | 方式四 (ComImport) |
| 動態載入未知 COM、外掛架構 | 方式二 (反射) |
| 需精確控制 CLSCTX、聚合、特定介面指標 | 方式三 (CoCreateInstance) |