从回调Inno Setup的调用C#DLL [英] Call C# dll from inno Setup with callback

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

问题描述

我有一个正在运行的Inno Setup的脚本,其中i由福尔摩斯软件innocallback.dll使用。





这个DLL包装我的一个过程,以便它可以被传递到C#DLL。



我不wanne使用这个DLL,我想打电话给我出口C# 。方法直接传递给它的回调过程。



我的问题是:



如何将我的INNO过程(@mycallback)传递给我的C#的DLL,这样我可以把它作为我的代表/ UnmanagedFunctionPointer?



正如我所说的这些代码作品。但我想尽可能少的外部DLL的使用成为可能。



下面是我的代码:



Inno Setup的脚本

 键入
TTimerProc =()的过程;
TProgressCallback =过程(进度:整数);

功能WrapProgressProc(回调:TProgressCallback; paramcount:整数):长字;
外部wrapcallback @文件:innocallback.dll STDCALL';

功能测试(回调:长字):字符串;
外部测试@文件:ExposeTestLibrary.dll STDCALL';

变种
endProgram:布尔;

程序myCallBack函数(进度:整数);
开始
MSGBOX(IntToStr(进度),mbInformation,MB_OK);
如果进展> 15然后
开始
endProgram:= TRUE;

端;

功能InitializeSet​​up:布尔;
变种
progCallBack:长字;
回调:长字;
味精:长字;
MSG 2:WideString的;
开始
endProgram:= FALSE;
progCallBack:= WrapProgressProc(@ myCallBack函数,1); //我们的PROC有1个参数
测试(progCallBack);
结果:= TRUE;
端;



这是我的C#代码



 公共类识别TestClass 
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)
公众委托无效ReportProgress(UINT进度);

公共静态ReportProgress m_reportProgess;
静态UINT m_iProgress;


[DLLEXPORT(测试,CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall)]
静态INT测试(ReportProgress RPROG)
{
m_iProgress = 0;
m_reportProgess = RPROG;
System.Timers.Timer pTimer =新System.Timers.Timer();
pTimer.Elapsed + = aTimer_Elapsed;
pTimer.Interval = 1000;
pTimer.Enabled = TRUE;
GC.KeepAlive(pTimer);
返回0;
}

静态无效aTimer_Elapsed(对象发件人,System.Timers.ElapsedEventArgs E)
{
m_iProgress ++;
m_reportProgess(m_iProgress);
}
}


解决方案

有没办法降包装InnoCallback库的使用,因为你根本无法与您所选择的创新安装的调用约定定义一个回调过程,也可以定义与注册调用约定(一个专门针对Delphi编译)在C#库。



由于这种限制,你必须使用一个外部库,它包装从应用创新的回调方法设置与调用约定,你的库可以消耗(InnoCallback使用 STDCALL 为)的功能。



所以,什么你问了,如果你在一个支持德尔福的注册调用约定的语言写你的图书馆将成为可能。 。出于好奇,在Delphi中你可以写例如:

 库MyLib中; 


TMyCallback =过程(IntParam:整数; StrParam:WideString的)对象;

程序CallMeBack(回拨:TMyCallback); STDCALL;
开始
回调(123,'你好!');
端;

出口
CallMeBack;

开始
端。

和在Inno Setup的话(没有任何包装库):

  [设置] 
AppName的=我的计划
AppVersion = 1.5
DefaultDirName = {} PF方案\My

[文件]
来源:中是指mylib.dll标志:dontcopy

[代码]

TMyCallback =过程(IntParam:整数; StrParam:WideString的);

程序CallMeBack(回拨:TMyCallback);
外部CallMeBack @文件:中是指mylib.dll STDCALL';

程序myCallBack函数(IntParam:整数; StrParam:WideString的);
开始
MSGBOX(格式('IntParam数:%d; StrParam:%s的,[IntParam,StrParam]),
mbInformation,MB_OK);
端;

程序InitializeWizard;
开始
CallMeBack(@MyCallback);
端;


I have a running inno setup script, wherein i use innocallback.dll by Sherlock Software.

 

This DLL wraps a procedure of mine so that it can be passed to a C# DLL.

I don't wanne use this DLL, i want to call my exported C# method directly and pass to it the callback procedure.

My question is:

How can i pass my inno procedure (@mycallback) to my C# dll so that i can use it as my delegate/UnmanagedFunctionPointer ?.

As i said this code works but i want to use as little external Dll's as possible.

Here is my code:

Inno Setup Script

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;

And This is my C# Code

 public class TestClass
  {
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate void ReportProgress(uint progress);

    public static ReportProgress m_reportProgess;
    static uint m_iProgress;

    
    [DllExport("Test", CallingConvention = System.Runtime.InteropServices.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);
    }
}

解决方案

There's no way to drop the usage of the wrapping InnoCallback library since you simply cannot define a callback procedure with a calling convention of your choice in Inno Setup, nor you can define a callback with the register calling convention (the one specific to Delphi compiler) in your C# library.

Due to this limit you must use an external library, which wraps a callback method from Inno Setup into a function with a calling convention that your library can consume (InnoCallback uses stdcall for that).

So, what you're asking for would be possible if you were writing your library in a language that supports Delphi's register calling convention. Out of curiosity, in Delphi you could write e.g.:

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.

And in Inno Setup then (without any wrapping library):

[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的调用C#DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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