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 want to 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 Setup 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 = 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);
}
}
This answer is no longer valid with Inno Setup 6. See my (@MartinPrikryl) answer for up to date solution.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With