从C#调用Delphi函数 [英] Call Delphi Function From C#
问题描述
我有一个以下的DLL源代码。
library Project1;
使用
System.SysUtils,
System.Classes;
type
IStringFunctions = interface
['{240B567B-E619-48E4-8CDA-F6A722F44A71}']
函数GetMethodValueAsString():PAnsiChar;标准
结束
TStringFunctions = class(TInterfacedObject,IStringFunctions)
public
函数GetMethodValueAsString():PAnsiChar;标准
结束
{$ R * .res}
函数TStringFunctions.GetMethodValueAsString():PAnsiChar;标准
begin
结果:='test';
结束
程序GetImplementation(out instance:IStringFunctions);标准出口;
begin
instance:= TStringFunctions.Create;
结束
export GetImplementation;
begin
end。
我想在C#中使用这样
使用系统;
使用System.Runtime.CompilerServices;
使用System.Runtime.InteropServices;
命名空间ConsoleApplication1
{
[ComVisible(true)]
[ComImport,InterfaceType(ComInterfaceType.InterfaceIsIUnknown),Guid(240B567B-E619-48E4-8CDA- F6A722F44A71)
public interface IStringFunctions
{
[MethodImplAttribute(MethodImplOptions.PreserveSig)]
[return:MarshalAs(UnmanagedType.AnsiBStr)]
string GetMethodValueAsString() ;
}
类程序
{
[DllImport(kernel32.dll,EntryPoint =LoadLibrary,CallingConvention = CallingConvention.StdCall)]
static extern int LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName);
[DllImport(kernel32.dll,EntryPoint =GetProcAddress,CallingConvention = CallingConvention.StdCall,CharSet = CharSet.Ansi)]
static extern IntPtr GetProcAddress(int hModule,[MarshalAs (UnmanagedType.LPStr)] string lpProcName);
[DllImport(kernel32.dll,EntryPoint =FreeLibrary,CallingConvention = CallingConvention.StdCall)]
static extern bool FreeLibrary(int hModule);
[UnmanagedFunctionPointer(CallingConvention.StdCall,CharSet = CharSet.Ansi)]
delegate void GetImplementation([MarshalAs(UnmanagedType.Interface)] out IStringFunctions instance);
static void Main(string [] args)
{
const string dllName =Project1.dll;
const string functionName =GetImplementation;
int libHandle = LoadLibrary(dllName);
if(libHandle == 0)throw new异常(string.Format(无法加载库\{0} \,dllName));
var delphiFunctionAddress = GetProcAddress(libHandle,functionName);
if(delphiFunctionAddress == IntPtr.Zero)throw new Exception(string.Format(can not find function \{0} \in library \{1} \,functionName ,dllName));
GetImplementation getImplementation =(GetImplementation)Marshal.GetDelegateForFunctionPointer(delphiFunctionAddress,typeof(GetImplementation));
if(getImplementation!= null)
{
IStringFunctions instance = null;
getImplementation(out instance);
if(instance!= null)
{
// !!!不要返回值!!!
String result = instance.GetMethodValueAsString();
Console.WriteLine(result);
}
}
Console.ReadLine();
}
}
}
但是instance.GetMethodValueAsString方法没有不工作并退出代码。
我想在c#中使用dll函数(GetMethodValueAsString)的返回值。
I不明白
我的错误在哪里?
非常感谢你
[return:MarshalAs(UnmanagedType.AnsiBStr)]
pre>
这是错误的。您不返回在COM堆上分配的ANSI编码字符串。你正在返回一个纯C字符串,一个指向空字符的ANSI字符数组的指针。
你的接口声明应该是:
[MethodImplAttribute(MethodImplOptions.PreserveSig)]
IntPtr GetMethodValueAsString();
调用方法必须这样:
IntPtr ptr = instance.GetMethodValueAsString();string result = Marshal.PtrToStringAnsi(ptr);
当然,当您需要返回动态分配的字符串时,您的界面设计变得不切实际。你也需要出口一个发放者。处理这种情况的干净方法是使用
BSTR
。像这样:
Delphi
IStringFunctions = interface
['{240B567B-E619-48E4-8CDA-F6A722F44A71}']
procedure GetMethodValueAsString(out value:WideString);标准
结束
C#
[MethodImplAttribute(MethodImplOptions.PreserveSig)]
void GetMethodValueAsString([MarshalAs(UnmanagedType.BStr)] out string result);
I have a below DLL source code.
library Project1; uses System.SysUtils, System.Classes; type IStringFunctions = interface ['{240B567B-E619-48E4-8CDA-F6A722F44A71}'] function GetMethodValueAsString():PAnsiChar; stdcall; end; TStringFunctions = class(TInterfacedObject, IStringFunctions) public function GetMethodValueAsString():PAnsiChar; stdcall; end; {$R *.res} function TStringFunctions.GetMethodValueAsString():PAnsiChar; stdcall; begin Result := 'test'; end; procedure GetImplementation(out instance:IStringFunctions); stdcall; export; begin instance := TStringFunctions.Create; end; exports GetImplementation; begin end.
I want to using in C# like this
using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace ConsoleApplication1 { [ComVisible(true)] [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("240B567B-E619-48E4-8CDA-F6A722F44A71")] public interface IStringFunctions { [MethodImplAttribute(MethodImplOptions.PreserveSig)] [return: MarshalAs(UnmanagedType.AnsiBStr)] string GetMethodValueAsString(); } class Program { [DllImport("kernel32.dll", EntryPoint = "LoadLibrary", CallingConvention = CallingConvention.StdCall)] static extern int LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpLibFileName); [DllImport("kernel32.dll", EntryPoint = "GetProcAddress", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] static extern IntPtr GetProcAddress(int hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName); [DllImport("kernel32.dll", EntryPoint = "FreeLibrary", CallingConvention = CallingConvention.StdCall)] static extern bool FreeLibrary(int hModule); [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Ansi)] delegate void GetImplementation([MarshalAs(UnmanagedType.Interface)] out IStringFunctions instance); static void Main(string[] args) { const string dllName = "Project1.dll"; const string functionName = "GetImplementation"; int libHandle = LoadLibrary(dllName); if (libHandle == 0) throw new Exception(string.Format("Could not load library \"{0}\"", dllName)); var delphiFunctionAddress = GetProcAddress(libHandle, functionName); if (delphiFunctionAddress == IntPtr.Zero) throw new Exception(string.Format("Can't find function \"{0}\" in library \"{1}\"", functionName, dllName)); GetImplementation getImplementation = (GetImplementation)Marshal.GetDelegateForFunctionPointer(delphiFunctionAddress, typeof(GetImplementation)); if (getImplementation != null) { IStringFunctions instance = null; getImplementation(out instance); if (instance != null) { //!!! don't return value !!!! String result = instance.GetMethodValueAsString(); Console.WriteLine(result); } } Console.ReadLine(); } } }
But instance.GetMethodValueAsString method doesn't working. And exit code.
I want to use returning value from dll function(GetMethodValueAsString) in c#.
I don't understand.
Where's my fault?
Thank you so much
解决方案[return: MarshalAs(UnmanagedType.AnsiBStr)]
This is wrong. You are not returning an ANSI encoded string, allocated on the COM heap. You are returning a plain C string, a pointer to null-terminated array of ANSI characters.
Your interface declaration should be:
[MethodImplAttribute(MethodImplOptions.PreserveSig)] IntPtr GetMethodValueAsString();
Calling the method must be done like this:
IntPtr ptr = instance.GetMethodValueAsString(); string result = Marshal.PtrToStringAnsi(ptr);
Of course, your interface design becomes rather impractical when you need to return a dynamically allocated string. You'd need to export a deallocator too. The clean way to deal with this is to use a
BSTR
. Like this:Delphi
IStringFunctions = interface ['{240B567B-E619-48E4-8CDA-F6A722F44A71}'] procedure GetMethodValueAsString(out value: WideString); stdcall; end;
C#
[MethodImplAttribute(MethodImplOptions.PreserveSig)] void GetMethodValueAsString([MarshalAs(UnmanagedType.BStr)] out string result);
这篇关于从C#调用Delphi函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!