c# - 将结构传递给非托管代码,从 C# DLL 到 VB6

标签 c# dll vb6 marshalling

我有一些客户使用 VB6 和其他一些语言的应用程序。该代码使用 OLE (COM) 运行良好,但客户更喜欢使用 native DLL 以避免注册库并将它们部署到现场。

当我注册 DLL 并在 VB6 (OLE) 中进行测试时,它工作正常。当我调用一个返回 Strutc 的方法时,它与 OLE 一起工作正常,但是,如果我使用 Declare 在 VB6 中访问,我在应该返回相同类型结构的方法中遇到 fatal error (方法“EchoTestData”见下文)。

代码在 C# 中编译,以在非托管代码中使用 OLE 或通过入口点>我用 VB6 测试过。

namespace TestLib
{
  [ClassInterface(ClassInterfaceType.AutoDual)]
  [ProgId("TestClass")]
  public class TestClass : System.EnterpriseServices.ServicedComponent
  {

    /* 
     * NOTE:
     * ExportDllAttribut: a library that I have used to publish the Entry Points,
     * I had modified that project and it works fine. After complile, the libray
     * make the entry points...
     * http://www.codeproject.com/Articles/16310/How-to-Automate-Exporting-NET-Function-to-Unmanage 
     */

    /* 
     * System.String: Converts to a string terminating in a null 
     * reference or to a BSTR 
     */
    StructLayout(LayoutKind.Sequential)]
    public struct StructEchoData
    {
        [MarshalAs(UnmanagedType.BStr)]
        public string Str1;
        [MarshalAs(UnmanagedType.BStr)]
        public string Str2;
    }

    /*
     * Method static: when I use this method, the Vb6 CRASH and the EVENT VIEWER
     * show only: System.Runtime.InteropServices.MarshalDirectiveException
     * HERE IS THE PROBLEM in VB6 with declare...
     * Return: struct of StructEchoData type
     */
    [ExportDllAttribute.ExportDll("EchoTestStructure", CallingConvention.StdCall)]
    public static StructEchoData EchoTestStructure(string echo1, string echo2)
    {
        var ws = new StructEchoData
        {
            Str1 = String.Concat("[EchoTestData] Retorno String[1]: ", echo1),
            Str2 = String.Concat("[EchoTestData] Retorno String[1]: ", echo2)
        };
        return ws;
    }

    /*
     * Method NOT static: it is used as COM (OLE) in VB6
     * In VB6 it returns very nice using with COM.
     * Note that returns the StructEchoData without problems...
     * Return: struct of StructEchoData 
     */
    [ExportDllAttribute.ExportDll("EchoTestStructureOle", CallingConvention.StdCall)]
    public StructEchoData EchoTestStructureOle(string echo1, string echo2)
    {
        var ws = new StructEchoData
        {
            Str1 = String.Concat("[EchoOle] Return StringOle[1]: ", echo1),
            Str2 = String.Concat("[EchoOle] Return StringOle[2]: ", echo2),
        };
        return ws;
    }

    /*
     * Method static: It works very nice using 'Declare in VB6'
     * Return: single string
     */
    [ExportDllAttribute.ExportDll("EchoS", CallingConvention.StdCall)]
    // [return: MarshalAs(UnmanagedType.LPStr)]
    public static string EchoS(string echo)
    {
        return "[TestClass::EchoS from TestLib.dll]" + echo;
    }


    /*
     * Method NOT static: it is used as COM (OLE) in VB6 
     * In VB6 it returns very nice
     * Return: single string
     */
    [ExportDllAttribute.ExportDll("EchoSOle", CallingConvention.StdCall)]
    // [return: MarshalAs(UnmanagedType.LPStr)]
    public string EchoSOle(string echo)
    {
        return "[TestClass::EchoS from TestLib.dll]: " + echo;
    }
  }
}

现在,在 VB6 中,我无法使用 Declare 或将 TestLib.Dll 注册为 COM 进行测试

在 VB6 中使用 DECLARE:

Private Declare Function EchoS Lib "C:\Temp\_run.dll\src.app.vb6\TestLib.dll"_
     (ByVal echo As String) As String

Private Type StructEchoData
    Str1 As String
    Str2 As String
End Type

Private Declare Function EchoTestStructure Lib  "C:\Temp\_run.dll\src.app.vb6\TestLib.dll"_
    (ByVal echo1 As String, ByVal echo2 As String) As StructEchoData

// ERROR - CRASH VB6
Private Sub EchoData_Click()
    Dim ret As StructEchoData
    ret = EchoTestStructure("echo1 Vb6", "echo2 vb6")
    TextBox.Text = ret.Str1
End Sub

// WORKS Fine, returns a string
Private Sub btRunEchoTestLib_Click()
    TextBox.Text = EchoS("{Run from VB6}")
End Sub

并在 OLE 中使用 VB6:

1圣。注册 DLL:C:\Windows\Microsoft.NET\Framework\v4.0.30319\regsvcs.exe TestLib.dll/tlb:Test.tlb

第二。在项目中添加引用。程序运行,我得到了一个字符串的响应,并在也有一个结构时收到了响应。

Private Sub Echo_Click()
    Dim ResStr As String
    Dim obj As TestLib.TestClass
    Set obj = New TestClass
    ResStr = obj.EchoSOle(" Test message")
    MsgBox "Msg Echo: " & ResStr, vbInformation, "ResStr"
    Beep
End Sub

Private Sub EchoDataOle_Click()
    Dim obj As TestLib.TestClass
    Set obj = New TestClass       
    // Here I define the struct and works fine!!
    Dim ret As TestLib.StructEchoData       
    ret = obj.EchoTestStructureOle("test msg1", "test msg2")       
    TextStr1.Text = ret.Str1
    TextStr2.Text = ret.Str2
    Debug.Print ret.Str1
    Debug.Print ret.Str2
   Beep
End Sub

因此,StructEchoData 使用 COM 包装得很好,但如果我想使用 Declare 并通过入口点获得访问权限,则行不通。有没有人可以提出任何建议?

最佳答案

VB6 Declare Lib 仅适用于未管理的 DLL 导出函数。 C# 不会将其函数公开为非托管函数,因为它是托管代码。从 C# 导出类的唯一支持方法是使用 COM。因此,您不能使用 Declare Lib 从 VB6 访问 C# 方法。

有一个库可以从您的 C# 代码中创建不受管理的导出;罗伯特·吉塞克的 Unmanaged Exports .我个人从未使用过它;我只在 Stack Overflow 上看到过它。

有一种支持从 .Net 程序集导出非托管函数的方法,它使用 C++/CLR,因为它允许混合托管代码和非托管代码。您可以创建一个 C++/CLR 包装器,该包装器导出调用 C# DLL 的非托管函数。这就是我要走的路。

关于c# - 将结构传递给非托管代码,从 C# DLL 到 VB6,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27725139/

相关文章:

.net - .NET Framework 安装是否会干扰现有的 VB6 运行时或 COM 安装?

c# - Xamarin Forms 错误 => "jarsigner.exe"以代码 1 退出

c# - 将 Moq C# 代码转换为等效的 c# Microsoft Fakes 以进行单元测试

java - Microsoft 或 Widcomm Stack 上的 Windows Mobile 蓝牙访问

windows - 在 VB6 中使用自定义 MouseIcon

sql-server - 将 Picturebox 中的图像与 SQL Image 数据类型进行比较

C++继承的C#接口(interface)

c# - 怎么求两个三角形相交的面积

python - 如何为 DLL 库创建 Python 包装器

c# - 是否可以调用 R 统计函数来优化 C# 函数