[英]Extracting Method Names from an unmanaged DLL(VB Dll) through c# Code
[英]Passing Structures to unmanaged code from C# DLL to VB6
我有一些使用VB6和其他语言的应用程序的客户。 该代码可以使用OLE(COM)正常运行,但是客户更喜欢使用本机DLL以避免注册库并将其部署在现场。
当我注册DLL并在VB6(OLE)中进行测试时,它工作正常。 当我调用返回Strutc的方法时,它可以很好地与OLE配合使用,但是,如果我使用Declare在VB6中进行访问,则该方法应返回致命错误,该错误应返回相同类型的结构(方法“ 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:
1st。 注册DLL:C:\\ Windows \\ Microsoft.NET \\ Framework \\ v4.0.30319 \\ regsvcs.exe TestLib.dll /tlb:Test.tlb
2号 在项目中添加参考。 程序运行后,我得到了一个字符串的响应,并且在具有结构时也收到了响应。
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#代码创建未管理的导出。 罗伯特·吉塞克(Robert Giesecke)的不受管制的出口 。 我个人从未使用过它。 我只在堆栈溢出中看到它。
有一种受支持的方法可以从.Net程序集中导出非管理函数,该方法使用C ++ / CLR,因为它允许混合托管和非管理代码。 您可以创建一个C ++ / CLR包装器,该包装器可以导出调用C#DLL的未管理函数。 那就是我要走的路。
您不能使用c#创建动态链接库。
但是,使用少量C ++,您可以利用CLR托管API为.Net dll创建引导程序。
您可以使用称为“ LoadPlugins”之类的方法在C ++中创建动态链接库。
编写LoadPlugins来加载CLR(或CLR的特定版本),然后使用反射来加载一些.net DLL。
同样使用相同的C ++代码,您可以将C ++ dll中的.net方法公开为c ++中的导出本机函数,这些函数可以与VB6的声明一起使用...
c ++中的每个函数都必须检查以确保已加载CLR,并且已加载了正在调用的.net代码,然后使用反射对其进行了调用。
感谢您的答复,
如果代码中有入口点,则C#仅适用于非托管DLL。 语句'ExportDllAttribut'在代码中使用的声明会生成非管理代码必须使用的各个入口点。
问题是将导出与“数据结构”一起使用,这是我的问题。 我已经毫无问题地使用了返回字符串或整数值的方法,例如本文中的EchoS。 我在VB6中使用了这个示例(TestLib.DLL),并且在VB6中与“ Declare”一起使用时效果很好:
Private Declare Function EchoS Lib "C:\Temp\_run.dll\src.app.vb6\TestLib.dll"_
(ByVal echo As String) As String
// WORKS Fine, returns a string
Private Sub btRunEchoTestLib_Click()
TextBox.Text = EchoS("{Run from VB6}")
End Sub
我在C#代码的开头写了一个便条,但是不清楚,抱歉。 解释了更多。 编译库后,在“项目属性”,“构建事件”中使用以下命令:
"$(ProjectDir)libs\ExportDll.exe" "$(TargetPath)" /Debug
该指令[ExportDllAttribute.ExportDll(“ NameOfEntryPoint”]取消了DLL(使用ilasm.exe和ildasm.exe)并编写了export指令来创建Entry Point,再次编译并生成DLL。
如果我在DLL中应用dumpbin命令,则结果是发布的入口点,因此,可以与非托管代码(如VB6)一起使用,但可以在Vb6中使用正确的编组类型或语句。 例:
dumpbin.exe /exports TestLib.dll
ordinal hint RVA name
2 0 0000A70E EchoC
5 1 0000A73E EchoSOle
3 2 0000A71E EchoTestStructure
6 3 0000A74E EchoTestStructureOle
使用方法EchoS(带有Delare)或EchoSOle(COM)测试了此代码,在两种情况下都可以。 当DLL在应用程序中用作OLE时,该结构可以视为Type且运行良好,但是在带有声明的VB6中,我仅在返回Structure的情况下遇到了MarshalDirectiveException错误,像字符串C#或整数之类的单打类型,我没有有问题。
我认为问题是如何通过静态方法EchoTestStructure来编排Structure,或者如何在VB6中声明它。 可能是VB6中使用的错误方法(我不是专家)或静态方法“ EchoTestStructure”中的任何编组参数,这才是真正的问题和帮助。
PS:如果无法解决,我会在答复中看到链接以尝试其他方法。
再次感谢,还有其他想法吗?
它已解决,但是通过另一种方式...这可能不是最新的技术,但它可以工作。
首先,需要将结构中的封送处理类型从BStr更改为LPStr。
我不知道动机是什么,因为有些Microsoft帮助和其他链接,他们说:“ System.String:转换为以空引用结尾的字符串或BSTR。”
如果在结构的Str1中设置“ Hello”,则会在DLL中收到“效汬㉯映潲䉖⸶⸮”。 如果我从DLL返回固定的字符串“ Hello”,则VB6仅显示第一个字符“ H”,因此,我更改为ANSI(LPStr)并解决了它。 使用OLE,BSTR可以正常工作,但本机DLL不能正常工作。 该代码已更改为:
StructLayout(LayoutKind.Sequential)]
public struct StructEchoData
{
[MarshalAs(UnmanagedType.BStr)]
public string Str1;
[MarshalAs(UnmanagedType.BStr)]
public string Str2;
}
在方法“ EchoTestStructureOle”的声明中,更改为使用引用并将传递结构的地址并返回一个结构。 在代码之前是:
public StructEchoData EchoTestStructure(string echo1, string echo2)
{
// It Works only wtih OLE the return of the type StructEchoData
var ws = new StructEchoData
{
Str1 = String.Concat("[EchoTestData] Return from DLL String[1]: ", echo1),
Str2 = String.Concat("[EchoTestData] Return from DLL String[2]: ", echo2)
};
return ws;
}
现在我正在使用interger通过引用返回状态(1 OK,-1错误)和参数结构类型,方法已更改为:
public static int EchoTestStructure(ref StructEchoData inOutString)
{
// used to test the return of values only, data 'in' not used
var ws = new StructEchoData
{
Str1 = String.Concat("[EchoTestData] Return from DLL String[1]: ", inOutString.Str1),
Str2 = String.Concat("[EchoTestData] Return from DLL String[2]: ", inOutString.Str2)
};
inOutString = ws;
return 1;
}
通过参考,我可以毫无问题地从VB6接收值并返回到VB6。 我认为必须有一种返回结构的方法,但是,这种方法现在解决了。
在VB6方面:代码已更改为:
Private Type StructEchoData // Same type, do not change...
Str1 As String
Str2 As String
End Type
Private Declare Function EchoTestData Lib "C:\Temp\_run.dll\src.app.vb6\TestLib.dll" (ByRef strcData As StructEchoData) As Long
Private Sub ShowMessage_Click()
Dim res As Long
Dim strcData As StructEchoData
strcData.Str1 = "Str1 from VB6..."
strcData.Str2 = "Str2 from VB6..."
res = EchoTestData(strcData)
/*
strcData.Str1 --> Data Received from DLL:
[EchoTestData] Return from DLL String[1]: Str1 from VB6...
strcData.Str2 --> Data Received from DLL
[EchoTestData] Return from DLL String[2]: Str2 from VB6...
*/
...
End Sub
感谢您的提示。 如果您有任何建议,将非常欢迎。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.