使用回调从 Inno 安装程序调用 C# DLL
本文关键字:程序 调用 DLL 安装 Inno 回调 | 更新日期: 2023-09-27 18:34:40
我有一个正在运行的Inno Setup脚本,其中我使用Sherlock Software的innocallback.dll。
此 DLL 包装了我的一个过程,以便可以将其传递给 C# DLL。
我不想使用此 DLL,我想直接调用导出的 C# 方法并将回调过程传递给它。
我的问题是:
如何将我的 Inno 安装程序 ( @mycallback
( 传递给我的 C# DLL,以便我可以将其用作我的delegate
/UnmanagedFunctionPointer
?
正如我所说,这段代码有效,但我想尽可能少地使用外部 DLL。
这是我的代码:
创新设置脚本
type
TTimerProc=procedure();
TProgressCallback=procedure(progress:Integer);
function WrapProgressProc(callback:TProgressCallback; paramcount:integer):longword;
external 'wrapcallback@files:innocallback.dll stdcall';
function Test(callback:longword): String;
external 'Test@files:ExposeTestLibrary.dll stdcall';
var
endProgram : Boolean;
procedure mycallback(progress:Integer);
begin
MsgBox(IntToStr(progress), mbInformation, MB_OK);
if progress > 15 then
begin
endProgram := True;
end
end;
function InitializeSetup:boolean;
var
progCallBack : longword;
callback : longword;
msg : longword;
msg2 : widestring;
begin
endProgram := False;
progCallBack:= WrapProgressProc(@mycallback,1); //Our proc has 1 arguments
Test(progCallBack);
result:=true;
end;
这是我的 C# 代码
public class TestClass
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void ReportProgress(uint progress);
public static ReportProgress m_reportProgess;
static uint m_iProgress;
[DllExport("Test", CallingConvention = CallingConvention.StdCall)]
static int Test(ReportProgress rProg)
{
m_iProgress = 0;
m_reportProgess = rProg;
System.Timers.Timer pTimer = new System.Timers.Timer();
pTimer.Elapsed += aTimer_Elapsed;
pTimer.Interval = 1000;
pTimer.Enabled = true;
GC.KeepAlive(pTimer);
return 0;
}
static void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
m_iProgress++;
m_reportProgess(m_iProgress);
}
}
此答案在 Inno Setup 6 中不再有效。有关最新解决方案,请参阅其他答案。
<小时 />无法放弃包装 InnoCallback 库的使用,因为您根本无法在 Inno Setup 中使用您选择的调用约定定义回调过程,也无法使用 C# 库中的register
调用约定(特定于 Delphi 编译器的约定(定义回调。
由于此限制,您必须使用外部库,该库将来自 Inno Setup 的回调方法包装到具有函数的函数中,该函数具有库可以使用的调用约定(InnoCallback 为此使用 stdcall
(。
因此,如果您使用支持 Delphi register
调用约定的语言编写库,那么您所要求的内容是可能的。出于好奇,在德尔福中你可以写,例如:
library MyLib;
type
TMyCallback = procedure(IntParam: Integer; StrParam: WideString) of object;
procedure CallMeBack(Callback: TMyCallback); stdcall;
begin
Callback(123, 'Hello!');
end;
exports
CallMeBack;
begin
end.
然后在Inno Setup中(没有任何包装库(:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}'My Program
[Files]
Source: "MyLib.dll"; Flags: dontcopy
[Code]
type
TMyCallback = procedure(IntParam: Integer; StrParam: WideString);
procedure CallMeBack(Callback: TMyCallback);
external 'CallMeBack@files:mylib.dll stdcall';
procedure MyCallback(IntParam: Integer; StrParam: WideString);
begin
MsgBox(Format('IntParam: %d; StrParam: %s', [IntParam, StrParam]),
mbInformation, MB_OK);
end;
procedure InitializeWizard;
begin
CallMeBack(@MyCallback);
end;
在Inno Setup 6中,有内置的CreateCallback
函数,其用途与InnoTools InnoCallback库中WrapCallback
函数相同。
因此,您现在可以执行以下操作:
Test(CreateCallback(@mycallback));