我有一个下面的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
。像这样:
德尔斐
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);
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句