還記得以下程式碼內容嗎?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace TestVBA { [Guid("6EE994BA-95B5-4548-98CB-B87663557880"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IVBAFunc { //[DispId(1)] int Multiply(int a, int b); } [ComVisible(true)] [Guid("A4F15491-8F1B-49C3-B626-589ECBCC60E7")] [ClassInterface(ClassInterfaceType.None)] public class VBAFunc : IVBAFunc { public int Multiply(int a, int b) { return a * b; } } }第9行:在登錄檔以下的路徑可以找到 {6EE994BA-95B5-4548-98CB-B87663557880} 機碼。
(1) HKEY_CLASSES_ROOT\Interface\
(2) HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\
點選 HKEY_CLASSES_ROOT\Interface\{6EE994BA-95B5-4548-98CB-B87663557880} 路徑下的 「TypeLib」會見系統幫我們產生一組新GUID。
用這組新的GUID:{BA353C64-FFD5-439D-8C0C-1DBEEE5B8CA6} 再搜尋一次登錄檔,會在HKEY_CLASSES_ROOT\TypeLib\{BA353C64-FFD5-439D-8C0C-1DBEEE5B8CA6} 下見到關於 TestVBA專案相關內容。
第18行:在登錄檔以下的路徑可以找到 {A4F15491-8F1B-49C3-B626-589ECBCC60E7} 機碼。
(1) HKEY_CLASSES_ROOT\CLSID\,並且在該路徑下會找到TestVBA專案相關內容。
(2) HKEY_CLASSES_ROOT\TestVBA.VBAFunc\CLSID\
(3) HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\
以上介紹到這裡大家心裡應該有個底了,在C#程式碼中添加的GUID屬性內容,透過Regasm.exe 註冊,就會被寫入到登錄檔中,如果沒有使用GUID屬性,Regasm.exe會自動隨機產生一組GUID來填 入到登錄檔中。
把 .NET C# 建立 COM元件 (2) --- 製作 Excel VBA 後期綁定元件 Excel VBA程式碼拿來修改,透過GUID來執行,看看會有什麼變化?
Sub TestVBA() Dim tool As Object Set tool = CreateObject("new:{A4F15491-8F1B-49C3-B626-589ECBCC60E7}") MsgBox tool.Multiply(2, 3) Set tool = Nothing End Sub執行結果:
有沒有發現 CreateObject 使用 GUID去建立物件,一樣可物件呼叫到Multiply函數執行,所以得到一個結論,COM元件的函數或模組可由指定 GUID來呼叫。
接著來看看在 HKEY_CLASSES_ROOT\CLSID\{A4F15491-8F1B-49C3-B626-589ECBCC60E7} 路徑下有多了一個「Progid」機碼內容,這內容也是DLL透過 Regasm.exe 註冊時被寫進去,預設內容為專案「命名空間.類別名稱」即「namespace.class」,這個屬性影響 CreateObject 建立物件。我們可以試著在C#中添加 「Progid("iInfo.Amin")」 屬性,來看看 CreateObject 其中的變化。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace TestVBA { [Guid("6EE994BA-95B5-4548-98CB-B87663557880"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface IVBAFunc { //[DispId(1)] int Multiply(int a, int b); } [ComVisible(true)] [Guid("A4F15491-8F1B-49C3-B626-589ECBCC60E7")] [ClassInterface(ClassInterfaceType.AutoDual)] [ProgId("iInfo.Amin")] public class VBAFunc : IVBAFunc { public int Multiply(int a, int b) { return a * b; } } }添加「 Progid 」屬性後重建DLL,記得先移除註冊系統中前一次註冊的DLL,再重新註冊新建好的DLL,這樣才看得出修改效果。
以下修改Excel VBA 程式碼中 CreateObject 的內容。
Sub TestVBA() Dim tool As Object Set tool = CreateObject("iInfo.Amin") MsgBox tool.Multiply(2, 3) Set tool = Nothing End Sub
執行結果:
有聰明的讀者有發現什麼了嗎?
沒錯,在指定「Progid」屬性內容後,會直接影響 Excel VBA 程式碼中 CreateObject 的內容。如果沒有添加「Progid」屬性,則 CreateObject 呼叫的方法就是以「namespace.class」即「TestVBA.VBAFunc」。
以上介紹完C# COM DLL屬性添加的介紹,後續就交由讀者自行發想了。
相關文章:
參考資料:
- InterOp: Using a .NET based component from a non .NET platform by creating Isolated Application
- Writing a custom tool to generate code for Visual Studio .NET
- UNDERSTANDING ASCOM DRIVER REGISTRATION
- 32-bit and 64-bit COM Servers
- 在COM應用程序中使用.NET組件