Call C # DLL from Inno Setup using callback

I have a running Inno Setup script in which I use innocallback.dll from Sherlock software.

This DLL wraps my procedure, so it can be passed to the C # DLL.

I do not want to use this DLL, I want to directly call my exported C # method and pass the callback procedure to it.

My question is:

How can I pass my Inno installation 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 few external DLLs 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 = 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);  } } 
+5
source share
2 answers

This answer is not recommended using Inno Setup 6. See My answer for an updated solution.

There is no way to refuse to use the InnoCallback wrapper library, since you simply cannot define the callback procedure of the calling convention of your choice in the Inno installer, nor can you define the callback function with the register call of the convention (one is specific to the Delphi compiler) in your c # library.

Because of this limitation, you must use an external library that wraps the callback method from Inno Setup into a function with a calling convention that your library can use (InnoCallback uses stdcall for this).

So what you ask would be possible if you are writing your library in a language that supports Delphi register calling conventions. Out of curiosity, in Delphi you can write, for example:

 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 then in Inno Setup (without any wrapper 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; 
+3
source

Inno Setup 6 has a built -in CreateCallback function that performs the same functions as the WrapCallback function from the InnoTools InnoCallback library.

So now you can do:

 Test(CreateCallback(@mycallback)); 
0
source

Source: https://habr.com/ru/post/1209462/


All Articles