通过回调从Inno安装程序调用C#DLL

通过回调从Inno安装程序调用C#DLL,c#,dll,callback,inno-setup,dllexport,C#,Dll,Callback,Inno Setup,Dllexport,我有一个正在运行的Inno安装脚本,我使用它 这个DLL包装了我的一个过程,这样就可以将它传递给C#DLL 我不想使用这个DLL,我想直接调用导出的C#方法并将回调过程传递给它 我的问题是: 如何将Inno设置过程(@mycallback)传递到我的C#DLL,以便将其用作我的委托/非托管函数指针 正如我所说,这段代码可以工作,但我希望使用尽可能少的外部DLL 这是我的密码: Inno设置脚本 类型 TTimerProc=过程(); TProgressCallback=过程(进度:整数);  

我有一个正在运行的Inno安装脚本,我使用它

这个DLL包装了我的一个过程,这样就可以将它传递给C#DLL

我不想使用这个DLL,我想直接调用导出的C#方法并将回调过程传递给它

我的问题是:

如何将Inno设置过程(
@mycallback
)传递到我的C#DLL,以便将其用作我的
委托
/
非托管函数指针

正如我所说,这段代码可以工作,但我希望使用尽可能少的外部DLL

这是我的密码:

Inno设置脚本

类型
TTimerProc=过程();
TProgressCallback=过程(进度:整数);
    
函数WrapProgressProc(callback:TProgressCallback;paramcount:integer):长单词;
外部的wrapcallback@files:innocallback.dll stdcall';
函数测试(回调:longword):字符串;
外部的Test@files:ExposeTestLibrary.dll stdcall';
变量
endProgram:布尔型;
过程mycallback(进度:整数);
开始
MsgBox(IntToStr(进度),MB信息,MB_OK); 
如果进度>15,则
开始
endProgram:=真;
结束
结束;
  
函数初始化设置:布尔;
变量
项目名称:长单词;
回调:长词;
味精:长词;
msg2:宽字符串;
开始
endProgram:=假;
progCallBack:=WrapProgressProc(@mycallback,1)//我们的proc有1个参数
测试(程序调用);
结果:=真;
结束;
这是我的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中不再有效。请参阅我的(@MartinPrikryl)答案以获取最新的解决方案。

无法停止使用包装InnoCallback库,因为您无法在Inno Setup中使用您选择的调用约定定义回调过程,也无法在C#库中使用
寄存器
调用约定(Delphi编译器特有的约定)定义回调

由于这个限制,您必须使用一个外部库,它将来自Inno安装程序的回调方法包装到一个函数中,该函数具有您的库可以使用的调用约定(InnoCallback为此使用
stdcall

因此,如果您使用支持Delphi的
register
调用约定的语言编写库,那么您所要求的将是可能的。出于好奇,您可以在Delphi中编写,例如:

库MyLib;
类型
TMyCallback=对象的过程(IntParam:Integer;StrParam:WideString);
过程回调(回调:TMyCallback);stdcall;
开始
回调(123,‘你好!’);
结束;
出口
回调;
开始
结束。
然后在Inno设置中(无任何包装库):

[设置]
AppName=我的程序
AppVersion=1.5
DefaultDirName={pf}\My程序
[档案]
资料来源:“MyLib.dll”;标志:dontcopy
[代码]
类型
TMyCallback=过程(IntParam:Integer;StrParam:WideString);
过程回调(回调:TMyCallback);
外部的CallMeBack@files:mylib.dll stdcall';
过程MyCallback(IntParam:Integer;StrParam:WideString);
开始
MsgBox(格式('IntParam:%d;StrParam:%s',[IntParam,StrParam]),
MB信息,MB_OK);
结束;
程序初始化;
开始
CallMeBack(@MyCallback);
结束;

使用Inno Setup 6,内置的函数与InnoTools InnoCallback库中的
WrapCallback
函数的作用相同

因此,您现在可以执行以下操作:

Test(CreateCallback(@mycallback));

我刚看到你拿到了inno安装金徽章。恭喜:)Inno安装程序6.0.3的更新:InnoCallback库完全停止工作,本机CreateCallback()现在是唯一的选项。