gpt4 book ai didi

c# - 从 C# 调用 Delphi 函数

转载 作者:行者123 更新时间:2023-11-30 14:09:18 24 4
gpt4 key购买 nike

我有下面的 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 字符数组的指针。

你的接口(interface)声明应该是:

[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);

关于c# - 从 C# 调用 Delphi 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30041480/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com