How to call .NET methods from Excel VBA?

前端 未结 4 1851
抹茶落季
抹茶落季 2020-11-27 03:46

I found a way to call .NET 2 code directly from VBA code:

Dim clr As mscoree.CorRuntimeHost
Set clr = New mscoree.CorR         


        
4条回答
  •  情深已故
    2020-11-27 04:06

    I'm not sure if this was just a coincidence or because I posted related question. SO showed me your question and I think I could also contribute something.

    When working with VBA and DLL, most solutions that I've seen so far is telling me to register the DLL and make it com/gac visible. If you are doing this in your PC that's absolutely fine but if you are distributing your VBA application, you don't really want to install DLLs in their system. You might not have permission or you don't really want to go through install/uninstall process or messing with referencing issues.

    However you can load dlls dynamically using some windows APIs.

    DLL

    Now the question is how to access .NET dll from vba? if your clients have mixed os architecture x86 x64 you need to handle this accordingly. Lets assume we are working on 32bit office/Excel.

    If you create a .NET dll and would like to access it from VBA it will throw an error message similar to "Can't find the dll entry point". thankfully Robert Giesecke has created an abstract wrapper which will allow you to create simple DLL consumable via VBA.

    A template can be found here.

    All you have to do

    1. Create a new class project in visual studio
    2. Set the project platform either x86 for 32bit and otherwise
    3. Create your methods within a main class.
    4. create another class which will return your main class as object (is returning to vba)
    5. (follow the template from his website)

    Lets assume you have followed his template and created a test method as following.

    [ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
    public class YOUR_MAIN_CLASS
    {
        [return: MarshalAs(UnmanagedType.BStr)]
        public string FN_RETURN_TEXT(string iMsg)
        {
    
            return "You have sent me: " + iMsg + "...";
        }
    }
    

    and your unmanagedexport class:

    static class UnmanagedExports
    {
        [DllExport]
        [return: MarshalAs(UnmanagedType.IDispatch)]
        static object YOUR_DLL_OBJECT()
        {
            return new YOUR_MAIN_CLASS();
        }
    }
    

    Preparing to access the dll from vba side

    Add the DLL to your root folder:

    #If VBA7 Then 
        Public Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
        Public Declare PtrSafe Function YOUR_DLL_OBJECT Lib "YOUR_DLL.dll" () As Object
    #Else
        Public Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal strFilePath As String) As Long
        Public Declare Function YOUR_DLL_OBJECT Lib "YOUR_DLL.dll" () As Object
    #End If
    

    Now It's all about loading the dll and creating & accessing objects it in vba. that would be:

    LoadLibrary (FN_APP_GET_BASE_PATH & "YOUR_DLL.dll")
    dim mObj as object
    set mObj = YOUR_DLL_OBJECT()
    debug.print mObj.FN_RETURN_TEXT("Testing ..")
    

    the output should be

    "You have sent me: Testing ....."
    

    Advantages I personally don't like installing and referencing dlls. By following above template, you don't need to reference anything, you don't need to install anything just load and work with your the DLL with full freedom.

    NOTE: I assume the dll/.net code is yours and you can compile it again with above templates to.

    I had success with above template and created a .NET non-blocking notifications for vba you can have a look here: non-blocking "toast" like notifications for Microsoft Access (VBA)

提交回复
热议问题