-2

I am trying to use gdi+ in inno but I can't able to draw outside the onpaint event

MyDllCode:

int DrawLine(HWND hwnd, ARGB LineColor, int startX, int startY, int endX,
         int endY) {
  auto hDc = GetDC(hwnd);
  Graphics graphics(hDc);
  graphics.SetSmoothingMode(SmoothingModeHighQuality);
  Pen pen((Color(LineColor)));
  pen.SetWidth(100);
  auto r = graphics.DrawLine(&pen, startX, startY, endX, endY);
  ReleaseDC(hwnd, hDc);
  return r;
}

above function is successful when called inside the onpaint event but doesn't draw anything when called from somewhere else like InitializeWizard();

Working InnoCode, Drawing is successful:

function StartGDI(): Longword;
 external 'StartGDI@{#DLLPATH} stdcall delayload';
procedure ShutDownGDI(token: longword);
 external 'ShutDownGDI@{#DLLPATH} stdcall delayload';

function DrawLine(h : HWND; LineColor: ARGB;startX: integer;startY: integer;endX: integer;
         endY: integer): integer;
  external 'DrawLine@{#DllPATH} stdcall delayload';


var
  Token: Longword;

 procedure PaintWF(Sender: TObject);
 var
  col : ARGB;
 begin
  DrawLine(WizardForm.Handle,$ffFF00ff,10,10,900,900);
 end;

procedure InitializeWizard();
begin
  token := StartGDI;
  with WizardForm do
  begin
    ClientWidth:=854;
    ClientHeight:=576;
    Center;
    OuterNotebook.Hide;
    InnerNotebook.Hide;
    Bevel.Hide;
    PageNameLabel.Hide;
    PageDescriptionLabel.Hide;
    MainPanel.Hide;
    BackButton.SetBounds(0,0,0,0);
    NextButton.SetBounds(0,0,0,0);
    CancelButton.SetBounds(0,0,0,0);
    DirBrowseButton.SetBounds(0,0,0,0);
    GroupBrowseButton.SetBounds(0,0,0,0);
    OnPaint := @PaintWF;
  end;      
end;

not working but what I needed to work

function StartGDI(): Longword;
 external 'StartGDI@{#DLLPATH} stdcall delayload';
procedure ShutDownGDI(token: longword);
 external 'ShutDownGDI@{#DLLPATH} stdcall delayload';

function DrawLine(h : HWND; LineColor: ARGB;startX: integer;startY: integer;endX: integer;
         endY: integer): integer;
  external 'DrawLine@{#DllPATH} stdcall delayload';


var
  Token: Longword;


procedure InitializeWizard();
begin
  token := StartGDI;
  with WizardForm do
  begin
    ClientWidth:=854;
    ClientHeight:=576;
    Center;
    OuterNotebook.Hide;
    InnerNotebook.Hide;
    Bevel.Hide;
    PageNameLabel.Hide;
    PageDescriptionLabel.Hide;
    MainPanel.Hide;
    BackButton.SetBounds(0,0,0,0);
    NextButton.SetBounds(0,0,0,0);
    CancelButton.SetBounds(0,0,0,0);
    DirBrowseButton.SetBounds(0,0,0,0);
    GroupBrowseButton.SetBounds(0,0,0,0);
  end;

  DrawLine(WizardForm.Handle,$ffFF00ff,10,10,900,900);

end;

full Code with dll code: https://drive.google.com/open?id=1_3Gn9Y6PD9iqxQCgZ8VXVrMM1-ncBTOs

unknown.prince
  • 710
  • 6
  • 19
  • 2
    As a general rule, drawing outside of `WM_PAINT` is a bad idea; even when it works, you have to duplicate your "outside-of-WM_PAINT drawing code" inside the `WM_PAINT`, as it may be called 1 ms after you drew because a window was dragged in front of yours, and you wouldn't want to lose the extra stuff you drew. So, just make sure that your `WM_PAINT` works as expected and just call `InvalidateRect` as needed. – Matteo Italia Dec 02 '18 at 15:06
  • for example: updating progress in inno(Circular Progress Bar) – unknown.prince Dec 02 '18 at 15:08
  • 2
    Keep a variable with the value of the progress bar. In `WM_PAINT`, draw it accordingly. When you update the value, also issue an `InvalidateRect`. This has also the advantage of coalescing multiple paints if you issue them very quickly. Of course, for paint to occur correctly you cannot block the event loop, but that is expected anyway (your GUI would hang, and that's not a Good Thing). – Matteo Italia Dec 02 '18 at 15:10
  • for progress bar, I have to update progress in say 10 seconds, how can i call WM_PAINT in every 10 seconds, for now i am using timer to update the progress – unknown.prince Dec 02 '18 at 15:13
  • 2
    Use a timer and issue an `InvalidateRect` there, exactly as you would do if drawing directly... – Matteo Italia Dec 02 '18 at 15:13
  • thanks will try and report back, but i also see other gdi-based libraries drawing without WM_Paint msg, how they do it? – unknown.prince Dec 02 '18 at 15:16
  • I never used GDI+, but in plain GDI you can always do `GetDC` and draw whenever you like most (heck, you can even do `CreateDC` and paint over the whole screen), but, as I said, outside of very particular cases it's generally a bad idea. – Matteo Italia Dec 02 '18 at 15:17
  • but in my case why GetDC is not working,(I am new to GDI+) – unknown.prince Dec 02 '18 at 15:19
  • If I knew I would have replied instead of commenting ;-) but again, it's not an area I know particularly well as _usually_ it's not needed or is just more hassle than it's worth. – Matteo Italia Dec 02 '18 at 15:20
  • 1
    GDI+ is in no way special. It wraps your standard GDI objects like device contexts. If you cannot render to a window using GDI+ you are simply doing it wrong. We cannot help with that since the question is missing a [mcve]. – IInspectable Dec 02 '18 at 15:54
  • There's no `OnPaint` event in Inno Setup proper. If you are using some 3rd party clone of Inno Setup, you need to tell us. – Martin Prikryl Dec 02 '18 at 20:15
  • Yes i am using a inno enhanced edition – unknown.prince Dec 03 '18 at 00:40
  • 1
    @bluedragon Come on! WHAT enhanced version? Say that in your question, not in comments. – Martin Prikryl Dec 03 '18 at 07:04
  • There is possibility that your `hwnd` is not visible yet. Drawing to hidden window is lost. You will get `WM_PAINT` when window will be finally shown. – Daniel Sęk Dec 03 '18 at 08:06

1 Answers1

0

What are you trying to draw? Do you have any reason to implement the drawing the way you do?

Did you consider drawing on an TBitmapImage control instead?

For an example, see How do I change the color of my progress bar in Inno Setup?

Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992