VB6 時代的 CreateObject("ProgID") 讓開發者能輕鬆晚期繫結呼叫 COM 元件。C# 雖可透過 Microsoft.VisualBasic.Interaction.CreateObject 達到同樣效果,但回傳 object 導致無法直接存取成員。本文介紹純 C# 方式:使用 System.Activator.CreateInstance 搭配反射 InvokeMember 完美複製 VB 的晚期繫結行為。
| VB6 | C# 等效 | 說明 |
|---|---|---|
CreateObject("ProgID") | Activator.CreateInstance(Type.GetTypeFromProgID("ProgID")) | 依 ProgID 建立 COM 物件執行個體 |
obj.Method(args) | type.InvokeMember("Method", BindingFlags.InvokeMethod, null, obj, args) | 呼叫方法 |
val = obj.Function(args) | val = type.InvokeMember("Function", BindingFlags.InvokeMethod, null, obj, args) | 呼叫有回傳值的函式 |
val = obj.Property | val = type.InvokeMember("Property", BindingFlags.GetProperty, null, obj, null) | 取得屬性值 |
obj.Property = val | type.InvokeMember("Property", BindingFlags.SetProperty, null, obj, new object[]{val}) | 設定屬性值 |
using System;
using System.Reflection;
public class LateBindingHelper
{
///
/// 建立 COM 物件並回傳 (Type, Instance) 配對,方便後續 InvokeMember
///
public static (Type ComType, object Instance) CreateComObject(string progId)
{
Type t = Type.GetTypeFromProgID(progId, throwOnError: true);
object inst = Activator.CreateInstance(t);
return (t, inst);
}
///
/// 呼叫方法 (無回傳值)
///
public static void InvokeMethod(Type t, object inst, string name, params object[] args)
=> t.InvokeMember(name, BindingFlags.InvokeMethod, null, inst, args);
///
/// 呼叫函式/方法 (有回傳值)
///
public static T InvokeFunction<T>(Type t, object inst, string name, params object[] args)
=> (T)t.InvokeMember(name, BindingFlags.InvokeMethod, null, inst, args);
///
/// 取得屬性值
///
public static T GetProperty<T>(Type t, object inst, string name)
=> (T)t.InvokeMember(name, BindingFlags.GetProperty, null, inst, null);
///
/// 設定屬性值
///
public static void SetProperty(Type t, object inst, string name, object value)
=> t.InvokeMember(name, BindingFlags.SetProperty, null, inst, new object[] { value });
}
public void AutomateWord()
{
var (wordType, wordApp) = LateBindingHelper.CreateComObject("Word.Application");
// 設定可見
LateBindingHelper.SetProperty(wordType, wordApp, "Visible", true);
// 取得 Documents 集合
object docs = LateBindingHelper.GetProperty
InvokeMember 可能拋出 TargetInvocationException,真實錯誤在 InnerException 中。System.Runtime.InteropServices.Marshal.ReleaseComObject 釋放,並建議搭配 GC.Collect()、GC.WaitForPendingFinalizers()。HKEY_CLASSES_ROOT 搜尋,或參考元件的類別庫 (TLB) 文件。| 特性 | 早期繫結 | 晚期繫結 |
|---|---|---|
| 開發體驗 | IntelliSense、編譯期型別檢查 | 純字串、執行期才發現錯誤 |
| 部署相依性 | 需目標機安裝相同版本 COM 元件 | 僅需 ProgID 存在,版本彈性較大 |
| 效能 | 直接虛擬函式呼叫,極快 | 反射呼叫,有額外負擔 |
| 適用場景 | 核心高頻自動化流程 | 動態載入、外掛架構、版本不固定環境 |
掌握 Activator.CreateInstance + InvokeMember 模式,即可在 C# 中靈活操作任何 COM 元件,無需專案加入參考,特別適合動態擴充、外掛式架構或跨版本相容情境。