从C#调用Delphi函数 [英] Call Delphi Function From C#

查看:327
本文介绍了从C#调用Delphi函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个以下的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆