在现代软件开发中,跨语言调用和回调机制是实现不同编程语言间交互的重要手段。本文将介绍如何将.NET方法暴露给Delphi应用程序,并实现跨语言的回调功能。
回调是一种编程模式,允许一个较低级别的软件层调用一个在较高级别定义的子程序(或函数)。在.NET中,通常使用委托(delegate)来实现这一概念。但是,如何在原生代码和.NET之间传递回调呢?本文将解答这个问题。
要使.NET方法对原生代码可见,需要将.NET程序集注册为COM对象,并将其放置在全局程序集缓存(GAC)中。以下是一些关键步骤:
将使用Visual Studio 2010和C#来构建.NET部分。首先,添加一个新的类库项目,并将其命名为CSDemoLibrary。在项目属性中,确保设置此库为COM可见。
为了将程序集添加到GAC,需要给程序集一个强名称。在“签名”选项卡中勾选“签名程序集”,然后从下拉列表中选择“新建…”,并命名文件为CSDemoLibrary。
由于需要传递此程序集的指针,因此还有一个额外的步骤,即在构建选项卡中勾选“允许不安全代码”。
首先,定义一个委托来表示回调函数:
public delegate void NativeCallback(Int32 intParam, [MarshalAs(UnmanagedType.LPWStr)] string strParam);
然后,创建一个类并使用ComVisible(true)属性使其COM可见。由于这个方法将处理原生指针(回调指针),还需要使用unsafe关键字标记它:
[ComVisible(true), GuidAttribute("3A65D04A-3F2F-4CB3-B65A-8D402B8C64CE")]
public class MyClass {
public unsafe int Process(int intValue, IntPtr callbackPointer, int intParam, string strParam) {
NativeCallback callbackMethod = (NativeCallback)Marshal.GetDelegateForFunctionPointer(callbackPointer, typeof(NativeCallback));
callbackMethod(intParam, strParam);
// 模拟长时间运行的过程
Thread.Sleep(1000);
return intValue * 10;
}
}
为了避免路径问题,可以使用Visual Studio命令提示符。使用此工具,可以通过以下步骤注册COM程序集:
gacutil -i CSDemoLibrary.dll
regasm CSDemoLibrary.dll
注意:要从GAC中移除.NET程序集,可以使用命令:
gacutil -u CSDemoLibrary
要注销.NET程序集,可以使用命令:
regasm -u CSDemoLibrary.dll
将使用Delphi2010来构建原生部分。在Delphi 2010 IDE中,创建一个新的VCL应用程序。在主表单中添加TLabel、TButton、TGauge控件。
在主表单的代码后面添加ComObj到uses部分。定义一个简单的回调过程,以更新Gauge1进度和lbMessage标题:
procedure callback(intParam: Integer; strParam: pChar); stdcall;
begin
Form2.Gauge1.Progress := intParam;
Form2.lbMessage.Caption := strParam;
Application.ProcessMessages;
end;
在这个示例中,将使用后期绑定。更新btnProcess点击事件处理程序如下:
procedure TForm2.btnProcessClick(Sender: TObject);
var
oleObject: OleVariant;
begin
try
oleObject := CreateOleObject('CSDemoLibrary.MyClass');
ShowMessage('result= ' + IntToStr(oleObject.Process(10, LongInt(@callback), 0, 'initialization')));
except
on E: Exception do
ShowMessage('COM Error: ' + #13 + #10 + e.Message);
end;
end;