VBA can't find C# dll entry point

2019-02-26 09:33发布

问题:

I'm creating a dll in C# which runs a simulation when a single function runSimulation() is called. This dll should be called from VBA, as certain parameter values are given as input in Excel. This is the code I use.

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using RGiesecke.DllExport;

namespace Simulation
{
    public static class Simulation
    {
        [ComVisible(true)]
        [DllExport("runSimulation", CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.SysInt)]
        public static int runSimulation()
        {
            // Do simulation

            return 0;
        }
    }
}

The above code is compiled as a Class Library with x64 as Platform Target and returns Simulation.dll.

VBA:

Public Declare Function runSimulation Lib "Simulation.dll" () As Long

Sub Run_DLL()
ChDir (ActiveWorkbook.Path)
Dim returnValue As Long
returnValue = runSimulation()
End Sub

Running the Visual Basic code returns

run-time error 453: 'Can't find DLL entry point runSimulation in Simulation.dll'

when it tries to call runSimulation().

As a reference: I've tried running with

[DllExport("runSimulation", CallingConvention = CallingConvention.StdCall)]

instead, but this also doesn't work. I additionally tried using the advice given in https://www.linkedin.com/grp/post/40949-258782989 but it gives me the same error.

回答1:

I managed to call the 'runSimulation' function in VBA code, by exposing the Simulation class through an interface in C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace NSSimulation
{
    public interface ISimulation
    {
        int runSimulation();
    }

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    public class Simulation : ISimulation
    {
        [ComVisible(true)]
        public int runSimulation()
        {
            return 0;
        }
    }
}

Then re-compile your project and export your rebuilt library with 'tlbexp.exe' from the Visual Studio command prompt:

tlbexp.exe SimulationLib.dll /out:"SimulationLib.tlb" /win64

Then open the Visual Basic editor in Excel and add a reference to 'SimulationLib.tlb' through "Tools->References->Browse". To verify

Public x As New SimulationLib.Simulation

Sub test()
   MsgBox x.runSimulation
End Sub