簡體   English   中英

與C#和VBA並排COM互操作

[英]Side-By-Side COM Interop with C# and VBA

我不是在談論從C#調用VBA COM ......反過來說!

我想要做的是在MS Access中使用VBA調用C#庫而不注冊DLL。 我一直在玩並排互操作一段時間沒有成功,我終於想到一個mdb.manifest可能不是exe.manifest的可接受的替代品(可能很明顯,我知道,但我我試圖保持樂觀。

我的問題:是否有可能讓VBA加載並排的COM組件?

或者,是否有另一種方法在Access中使用未注冊的C#庫?

(在您提出問題之前,我的理由是:我絕對無法訪問我的客戶端的Windows注冊表 - 這就是為什么它首先在Access中編寫。而且,我需要在一個實現相同的功能。 C#應用程序很快,而不是做兩次)。

要添加到現有的答案: 使用 .NET 4.0 ,在VBA項目中使用C#dll而不注冊COM實際上非常簡單。

編輯 :我剛剛嘗試使用C:\\windows\\Microsoft.NET\\Framework\\v2.0.50727mscorlib.tlbmscoree.tlb - 加載在3.5中編譯的程序集 - 它工作得很好。 顯然你不需要.NET 4.0。

以下是如何在VBA項目中使用C#dll的示例。 這個答案略有修改。

1)添加對以下類型庫的引用您的VBA項目(工具 - >引用):

C:\windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb
C:\windows\Microsoft.NET\Framework\v4.0.30319\mscoree.tlb

(如果您運行的是64位Office,請使用Framework64文件夾)

2)在C#項目中,確保將[ComVisible(true)]屬性添加到類中:

using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace VB6FuncLib
{
    [ComVisible(true)]
    public class VB6FuncLib
    {
        public VB6FuncLib()
        { }
        public void test()
        {
            MessageBox.Show("Test Successful");
        }
    }
}

並不需要檢查選項“注冊為COM Interop”。 這只是用於構建標准COM對象。 您不必檢查“使程序集COM可見”,除非您希望整個程序集可見(這也將消除對COMVisible屬性的需要)。

3)在您的VBA代碼中,添加一個包含以下代碼的新模塊:

Sub Test()
    Dim Host As mscoree.CorRuntimeHost
    Set Host = New CorRuntimeHost
    Host.Start
    Dim Unk As IUnknown
    Host.GetDefaultDomain Unk
    Dim AppDomain As AppDomain
    Set AppDomain = Unk
    Dim ObjHandle As ObjectHandle
    Set FS = CreateObject("Scripting.FileSystemObject")
    Path = FS.GetParentFolderName(CurrentDb().Name)
    Set ObjHandle = AppDomain.CreateInstanceFrom(Path & "\VB6 Function Library.dll", "VB6FuncLib.VB6FuncLib")
    Dim ObjInstance As Object
    Set ObjInstance = ObjHandle.Unwrap
    ObjInstance.test
    Host.Stop
End Sub

4)將DLL復制到Office項目所在的文件夾中,然后在VBA中運行Test()子。

筆記:

應該注意的是,該技術的一個限制是,如果.DLL存儲在遠程網絡共享上,它將不起作用。 一個簡單的解決方案是將其復制到正在使用它的每台PC上的同一本地文件夾中。 另一種解決方案是在Access app / VBA項目中包含二進制文件,並讓MS-Access導出它們。 可以實現的一種方法是將它們存儲在Base64中的表或電子表格中,然后轉換它們並將它們導出為二進制。

我能夠通過創建一個類型庫來使用DLL(通過使用tlbexp),並在我的VBA項目中添加對TLB的引用來獲得早期綁定(以及Microsoft IntelliSense),但它確實使事情變得復雜因為它需要您的VBA應用程序知道DLL和TLB文件的位置(並且還需要有人確保它們在那里)。

您不必擁有使用SxS的exe,SxS是激活上下文的另一個詞。 如果您可以將相關的win32調用導入vba(並且可以),則可以使用激活上下文api來加載清單文件。

有關該主題的更多信息,可以在此處找到一些示例。

問題是要使用SxS,您需要擁有exe來設置配置以加載SxS程序集。 您沒有“擁有”Access,雖然您可以放棄正確的配置以使其加載您的.NET COM內容沒有注冊,但這不是一個“好公民”的舉動。

如果你使用shimming變得棘手,你可以設置一個非托管DLL(或帶有dllexport的黑客C#類庫,例如看到這個 ),導出將加載.NET框架,創建一個COMVisible DispInterface管理的實例輸入並返回它(該方法應該返回IDispatch)。 然后寫一個VBA聲明到你的DLL導出函數(聲明為返回Object)。 如果這沒有意義,你可能不應該嘗試... :)我之前在類似的情況下做過這個,它確實有效,但我沒有一個樣本指向你。

C#庫不是常規DLL。 它們更像是在使用之前需要注冊的COM庫(就像ActiveX控件一樣); 特別是從非.NET代碼調用時。

(當然,除非事情發生了變化......)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM