从C#调用Delphi函数

我有一个下面的DLL源代码。

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. 

我想在C#中使用这样的

 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(); } } } 

但是instance.GetMethodValueAsString方法不起作用。 并退出代码。

我想在c#中使用来自dll函数(GetMethodValueAsString)的返回值。

我不明白。

哪里是我的错?

非常感谢

 [return: MarshalAs(UnmanagedType.AnsiBStr)] 

这是错的。 您没有返回在COM堆上分配的ANSI编码字符串。 您将返回一个普通的C字符串,一个指向以null结尾的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); stdcall; end; 

C#

 [MethodImplAttribute(MethodImplOptions.PreserveSig)] void GetMethodValueAsString([MarshalAs(UnmanagedType.BStr)] out string result); 

COM Interop的C#代码是否可以看到Delphi DLL? 如果没有,最简单的方法是使用“添加现有项”菜单选项将dll附加到C#类库项目。 然后在此dll的属性窗口中将“BuildAction”设置为None,将“Copy to Output Directory”设置为“Copy always”

然后你可以在C#代码中做这样的事情。

 [DllImport("Project1.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)] public static extern string GetMethodValueAsString(); 

然后,只要你需要调用该function,你就可以做到

 var outputMessage = GetMethodValueAsString(); Console.WriteLine(outputMessage);