1

I need your help, please. I'm trying to call function from DLL written in Delphi 10 Seattle from Inno Setup (ANSI). But I do not understand what is the problem. If I make application in Delphi and call this function from DLL, it works perfectly! See code listing:

Delphi DLL:

function Process(Pb: TProgressBar): Integer; stdcall;
var
  I: integer;
begin
  for I := 0 to 1000 do
  begin
    Pb.Position := I;
    Pb.Update;
    Sleep(10);
  end;
end;

Exports
  Process;

Inno Setup (ANSI):

function Count(Progr: TNewProgressBar): integer; external 'Process@files:CallC.dll stdcall delayload';

procedure NewButton1Click(Sender: TObject);
begin
   Count(NewProgressBar1);
end;

After call I get Access Violation. But, comment in dpr file i read, ShareMem write first line, but zero effect.

Show me how to correctly update progress bar in Inno Setup from Delphi DLL, please.

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
Malcolm
  • 33
  • 1
  • 7

1 Answers1

1

You cannot call object methods this way. You may be lucky to get this working, if you use exactly the same version of Delphi as the one Inno Setup is built with, as your tests with Delphi application shows. But it is still wrong and unreliable, do not do it. As you use a different Delphi version, the layout of the progress bar class in memory is different, hence the "Access violation".


For this particular task, you can easily do with just a handle to the progress bar:

function Process(Handle: THandle): Integer; 
var
 I: Integer;
begin
  SendMessage(Handle, PBM_SETRANGE, 0, 1000 shl 16);
  for I := 0 to 1000 do
  begin
    SendMessage(Handle, PBM_SETPOS, I, 0);   
    UpdateWindow(Handle);
    Sleep(10);
  end;
end;

In Inno Setup, call the function like:

function Count(Handle: THandle): integer;
  external 'Process@files:CallC.dll stdcall delayload';

procedure NewButton1Click(Sender: TObject);
begin
  Count(NewProgressBar1.Handle);
end;

For more advanced tasks, you need to use a callback.

See

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • Even if the memory layout is the same, it's still wrong as has been discussed so many times before. Please don't perpetuate any myth that sharing classes across dll boundaries is valid. – David Heffernan Feb 08 '16 at 07:55
  • @DavidHeffernan I've just tried to explain OP why he was lucky that his tests with Dephi application works. I did not aim to suggest that it should be used. I've updated my wording. – Martin Prikryl Feb 08 '16 at 07:59
  • Guys Guys Guys!!! This method is Perfect, but don't work, i'm don't understand why?! I compile and click button. form freeze 2-th second, and progressbar position not changes. See [ScreenShot](http://s8.hostingkartinok.com/uploads/images/2016/02/6b6dd076394b6e2361d9f5d7d997790c.png) – Malcolm Feb 08 '16 at 10:21
  • @Martin Prikryl - Please ask, ProgressBar is not changes. – Malcolm Feb 08 '16 at 10:49
  • Probably nothing is pumping the message queue – David Heffernan Feb 08 '16 at 14:40
  • `for I := 0 to 1000` it's must fill progressbar position, but - not fill, only 1% of 100%. See previous my reply ScreenShot. – Malcolm Feb 08 '16 at 14:46
  • You probably have different range set, I've update the code with `PBM_SETRANGE` message. – Martin Prikryl Feb 08 '16 at 16:37
  • Yeah! Super! Great Work! But, i don't undersanf how is it work? `PBM_SETRANGE, 0, 1000 shl 16`, if get not `for`, and **Download File**. – Malcolm Feb 09 '16 at 02:00
  • Or Copy file from DLL? What is variables need paste to `PBM_SETRANGE` and `PBM_SETPOS`? – Malcolm Feb 09 '16 at 04:31
  • Replace the 1000 in `PBM_SETRANGE` with the value you would use for `TNewProgressBar.Max`. For `PBM_SETPOS`, use what you would have used for `TNewProgressBar.Position`. – Martin Prikryl Feb 09 '16 at 07:23
  • Very Very Well!! Thanks Advance! – Malcolm Feb 09 '16 at 10:35