2017年2月4日 星期六

.NET C# 建立 COM元件 (3) --- 再談 Excel VBA 後期綁定元件

從 .NET C# 建立 COM元件 (2) --- 製作 Excel VBA 後期綁定元件 介紹製作 Excel VBA 後期綁定元件,操作過程中 DLL元件需要跟系統註冊後才能使用,這裡就來看看在登錄檔中到底註冊了什麼內容,以及當屬性修改後會造成什麼影響。
還記得以下程式碼內容嗎?
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屬性添加的介紹,後續就交由讀者自行發想了。

相關文章:
參考資料: