AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Ersatz für Sleep?

Ein Thema von PeterPanino · begonnen am 9. Mär 2016 · letzter Beitrag vom 10. Mär 2016
Antwort Antwort
PeterPanino

Registriert seit: 4. Sep 2004
1.451 Beiträge
 
Delphi 10.4 Sydney
 
#1

Ersatz für Sleep?

  Alt 9. Mär 2016, 19:17
Delphi-Version: 10 Seattle
Hallo und schönen Abend!

Ich verwende diesen Code, um den Windows CHM-Viewer in mein Programm einzubetten und eine CHM-Datei darin anzuzeigen:

Formular-Definition:
Delphi-Quellcode:
object Form1: TForm1
  Left = 1838
  Top = 468
  Caption = 'Form1'
  ClientHeight = 681
  ClientWidth = 656
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  DesignSize = (
    656
    681)
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 24
    Top = 24
    Width = 177
    Height = 25
    Caption = 'Embed Viewer App'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Panel1: TPanel
    Left = 8
    Top = 64
    Width = 640
    Height = 609
    Anchors = [akLeft, akTop, akRight, akBottom]
    TabOrder = 1
    OnResize = Panel1Resize
    ExplicitWidth = 448
    ExplicitHeight = 321
  end
  object Button2: TButton
    Left = 216
    Top = 24
    Width = 177
    Height = 25
    Caption = 'Release Viewer App'
    TabOrder = 2
    OnClick = Button2Click
  end
end
Form-Unit:
Delphi-Quellcode:
unit MainForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Panel1Resize(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    FAppWnd: DWORD;
    procedure PADoEmbeddApp(APanel: TPanel; const AAppToExec, AParam: string);
    procedure PADoReleaseEmbeddedApp;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Winapi.ShellAPI;

procedure TForm1.PADoEmbeddApp(APanel: TPanel; const AAppToExec, AParam: string);
// App starten und einbetten
// uses Winapi.ShellAPI;
var
  ExecuteFile: string;
  SEInfo: TShellExecuteInfo;
  RetryCount: Integer;
begin
  FillChar(SEInfo, SizeOf(SEInfo), 0);
  SEInfo.cbSize := SizeOf(TShellExecuteInfo);
  with SEInfo do
  begin
    fMask := SEE_MASK_NOCLOSEPROCESS;
    Wnd := APanel.Handle;
    lpFile := PChar(AAppToExec);
    lpParameters := PChar(AParam);
    nShow := SW_HIDE;
  end;

  if ShellExecuteEx(@SEInfo) then // wenn Programm erfolgreich gestartet wurde
  begin
    RetryCount := 0;
    repeat
      FAppWnd := FindWindow(PChar('HH Parent'), nil);
      Sleep(100);
      Inc(RetryCount);
    until (FAppWnd <> 0) or (RetryCount > 10);

    if FAppWnd <> 0 then // wenn das Fenster der ViewerApp gefunden wurde
    begin
      Winapi.Windows.SetParent(FAppWnd, SEInfo.Wnd);
      SetWindowLong(FAppWnd, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE)
        and not WS_BORDER
        and not WS_THICKFRAME
        and not WS_DLGFRAME
        );

      SetWindowPos(FAppWnd, 0, 0, 0, APanel.Width, APanel.Height, SWP_ASYNCWINDOWPOS);

      Sleep(1000); // das Gelbe vom Ei?

      APanel.Repaint;
      Application.ProcessMessages;

      ShowWindow(FAppWnd, SW_SHOWMAXIMIZED);
    end;
  end;
end;

procedure TForm1.PADoReleaseEmbeddedApp;
// Eingebettetes Programm beenden
begin
  if FAppWnd <> 0 then
  begin
    PostMessage(FAppWnd, WM_Close, 0, 0);
    FAppWnd := 0;
  end;
end;

procedure TForm1.Panel1Resize(Sender: TObject);
// Größe von Embedded App zusammen mit Fenster verändern
begin
  if IsWindow(FAppWnd) then
    SetWindowPos(FAppWnd, 0, 0, 0, Panel1.Width, Panel1.Height, SWP_ASYNCWINDOWPOS);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  PADoEmbeddApp(Panel1, 'hh.exe', 'R:\Example.chm');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  PADoReleaseEmbeddedApp;
end;

end.
Das funktioniert auch sehr gut. Nur stört mich das Sleep(1000); nach SetWindowPos. Oder auch das Sleep(100); in der repeat-Schleife davor. Gibt es dafür keine elegantere Lösung?
  Mit Zitat antworten Zitat
BenjaminH

Registriert seit: 14. Okt 2004
Ort: Freiburg im Breisgau
713 Beiträge
 
Turbo Delphi für Win32
 
#2

AW: Ersatz für Sleep?

  Alt 9. Mär 2016, 19:23
Wenn du meinst, dass dein Fenster währenddessen nicht reagiert, dann ist das eine Lösung: http://www.delphipraxis.net/6620-delay.html
Benjamin
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.451 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: Ersatz für Sleep?

  Alt 9. Mär 2016, 19:43
Danke, Benjamin. Das funktioniert!

Noch eleganter wäre es allerdings, wenn die Delay-Schleife sofort verlassen würde, sobald das HH-Fenster fertig eingebettet ist. Denn zur Zeit ist die Zeit nur eine VERMUTUNG:

1000 ms: Funktioniert, das eingebettete HH-Fenster wird angezeigt.

500 ms: Das eingebettete HH-Fenster wird nicht angezeigt.

Könnte aber auf anderen Computern anders sein.

Geändert von PeterPanino ( 9. Mär 2016 um 19:45 Uhr)
  Mit Zitat antworten Zitat
BenjaminH

Registriert seit: 14. Okt 2004
Ort: Freiburg im Breisgau
713 Beiträge
 
Turbo Delphi für Win32
 
#4

AW: Ersatz für Sleep?

  Alt 9. Mär 2016, 19:46
Das kannst du ja selbst bei jedem
 if Application.Terminated OR WINDOWVISIBLE(bla) then Exit; überprüfen.
Benjamin
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.451 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Ersatz für Sleep?

  Alt 9. Mär 2016, 20:02
IsWindowVisible(FAppWnd) geht leider nicht, da es gleich True zurückgibt, ohne dass es fertig eingebettet ist:
Delphi-Quellcode:
if ShellExecuteEx(@SEInfo) then // wenn Programm erfolgreich gestartet wurde
  begin
    RetryCount := 0;
    repeat
      FAppWnd := FindWindow(PChar('HH Parent'), nil);
      Sleep(100);
      Inc(RetryCount);
    until (FAppWnd <> 0) or (RetryCount > 10);

    if FAppWnd <> 0 then // wenn das Fenster der ViewerApp gefunden wurde
    begin
      Winapi.Windows.SetParent(FAppWnd, SEInfo.Wnd);
      SetWindowLong(FAppWnd, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) and not WS_BORDER and not WS_THICKFRAME and
        not WS_DLGFRAME);

      SetWindowPos(FAppWnd, 0, 0, 0, APanel.Width, APanel.Height, SWP_ASYNCWINDOWPOS);

      Delay(1000);

      ShowWindow(FAppWnd, SW_SHOWMAXIMIZED);
    end;
  end;
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.451 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: Ersatz für Sleep?

  Alt 9. Mär 2016, 20:36
Ich habe jetzt folgendes versucht, aber es funktioniert leider auch nicht:
Delphi-Quellcode:
procedure TForm1.Delay(Milliseconds: Integer);
var
  Tick: DWORD;
  Event: THandle;
  WindRect, OldRect: TRect;
begin
  Event := CreateEvent(nil, False, False, nil);
  try
    Tick := GetTickCount + DWORD(Milliseconds);
    GetWindowRect(FAppWnd, OldRect);
    while (Milliseconds > 0) and (MsgWaitForMultipleObjects(1, Event, False, Milliseconds, QS_ALLINPUT) <> WAIT_TIMEOUT) do
    begin
      Application.ProcessMessages;
      if Application.Terminated then EXIT;

      GetWindowRect(FAppWnd, WindRect);
      if OldRect <> WindRect then EXIT;
      OldRect := WindRect;

      Milliseconds := Tick - GetTickCount;
    end;
  finally
    CloseHandle(Event);
  end;
end;

Geändert von PeterPanino ( 9. Mär 2016 um 20:41 Uhr)
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.451 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Ersatz für Sleep?

  Alt 9. Mär 2016, 22:39
So funktioniert es jetzt perfekt:
Delphi-Quellcode:
object Form1: TForm1
  Left = 1846
  Top = 421
  Caption = 'Form1'
  ClientHeight = 681
  ClientWidth = 656
  Color = clBtnFace
  DoubleBuffered = True
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  DesignSize = (
    656
    681)
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 24
    Top = 24
    Width = 177
    Height = 25
    Caption = 'Embed Viewer App'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Panel1: TPanel
    Left = 8
    Top = 64
    Width = 640
    Height = 609
    Anchors = [akLeft, akTop, akRight, akBottom]
    TabOrder = 1
    OnResize = Panel1Resize
    object Panel2: TPanel
      Left = 1
      Top = 1
      Width = 638
      Height = 607
      Align = alClient
      BevelOuter = bvNone
      TabOrder = 0
      ExplicitLeft = 96
      ExplicitTop = 200
      ExplicitWidth = 185
      ExplicitHeight = 41
    end
  end
  object Button2: TButton
    Left = 216
    Top = 24
    Width = 177
    Height = 25
    Caption = 'Release Viewer App'
    TabOrder = 2
    OnClick = Button2Click
  end
end
Delphi-Quellcode:
unit MainForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  CodeSiteLogging,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    Button2: TButton;
    Panel2: TPanel;
    procedure Button1Click(Sender: TObject);
    procedure Panel1Resize(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
    FAppWnd: DWORD;
    procedure PADoEmbeddApp(APanel: TPanel; const AAppToExec, AParam: string);
    procedure PADoReleaseEmbeddedApp;
    procedure PADelay(Milliseconds: Integer; APanel: Tpanel);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Winapi.ShellAPI;

procedure SimplePADelay(Milliseconds: Integer);
var
  Tick: DWORD;
  Event: THandle;
begin
  Event := CreateEvent(nil, False, False, nil);
  try
    Tick := GetTickCount + DWORD(Milliseconds);
    while (Milliseconds > 0) and (MsgWaitForMultipleObjects(1, Event, False, Milliseconds, QS_ALLINPUT) <> WAIT_TIMEOUT) do
    begin
      Application.ProcessMessages;
      if Application.Terminated then
        EXIT;
      Milliseconds := Tick - GetTickCount;
    end;
  finally
    CloseHandle(Event);
  end;
end;

procedure TForm1.PADelay(Milliseconds: Integer; APanel: Tpanel);
var
  Tick: DWORD;
  Event: THandle;
  WindRect, OldRect: TRect;
begin
  Event := CreateEvent(nil, False, False, nil);
  try
    Tick := GetTickCount + DWORD(Milliseconds);
    GetWindowRect(FAppWnd, OldRect);
    while (Milliseconds > 0) and (MsgWaitForMultipleObjects(1, Event, False, Milliseconds, QS_ALLINPUT) <> WAIT_TIMEOUT) do
    begin
      Application.ProcessMessages;
      if Application.Terminated then
        EXIT;

      GetWindowRect(FAppWnd, WindRect);
      if OldRect <> WindRect then
      begin
        APanel.Repaint;
        APanel.Update;
        Application.ProcessMessages;
        EXIT;
      end;
      OldRect := WindRect;

      Milliseconds := Tick - GetTickCount;
    end;
  finally
    CloseHandle(Event);
  end;
end;

procedure TForm1.PADoEmbeddApp(APanel: TPanel; const AAppToExec, AParam: string);
// App starten und einbetten
// uses Winapi.ShellAPI;
var
  ExecuteFile: string;
  SEInfo: TShellExecuteInfo;
  RetryCount: Integer;
begin
  FillChar(SEInfo, SizeOf(SEInfo), 0);
  SEInfo.cbSize := SizeOf(TShellExecuteInfo);
  with SEInfo do
  begin
    fMask := SEE_MASK_NOCLOSEPROCESS;
    Wnd := APanel.Handle;
    lpFile := PChar(AAppToExec);
    lpParameters := PChar(AParam);
    nShow := SW_HIDE;
  end;

  if ShellExecuteEx(@SEInfo) then // wenn Programm erfolgreich gestartet wurde
  begin
    RetryCount := 0;
    CodeSite.Send('VOR repeat');
    repeat
      FAppWnd := FindWindow(PChar('HH Parent'), nil);
      //Sleep(100);
      SimplePADelay(100);
      Inc(RetryCount);
    until (FAppWnd <> 0) or (RetryCount > 10);
    CodeSite.Send('NACH until');

    if FAppWnd <> 0 then // wenn das Fenster der ViewerApp gefunden wurde
    begin
      APanel.Visible := False;
      try
        Screen.Cursor := crHourGlass;
        try
          Winapi.Windows.SetParent(FAppWnd, SEInfo.Wnd);
          SetWindowLong(FAppWnd, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE) and not WS_BORDER and not WS_THICKFRAME and not WS_DLGFRAME);
          SetWindowPos(FAppWnd, 0, 0, 0, APanel.Width, APanel.Height, SWP_ASYNCWINDOWPOS);

          CodeSite.Send('VOR PADelay');
          PADelay(2000, APanel);
          CodeSite.Send('NACH PADelay');

          ShowWindow(FAppWnd, SW_SHOWMAXIMIZED);
          ShowWindow(FAppWnd, SW_SHOWMAXIMIZED);
        finally
          Screen.Cursor := crDefault;
        end;
      finally
        APanel.Visible := True;
      end;
    end;
  end;
end;

procedure TForm1.PADoReleaseEmbeddedApp;
// Eingebettetes Programm beenden
begin
  if FAppWnd <> 0 then
  begin
    PostMessage(FAppWnd, WM_Close, 0, 0);
    FAppWnd := 0;
  end;
end;

procedure TForm1.Panel1Resize(Sender: TObject);
// Größe von Embedded App zusammen mit Fenster verändern
begin
  if IsWindow(FAppWnd) then
  begin
    SetWindowPos(FAppWnd, 0, 0, 0, Panel1.Width, Panel1.Height, SWP_ASYNCWINDOWPOS);
    ShowWindow(FAppWnd, SW_SHOWMAXIMIZED);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  PADoEmbeddApp(Panel2, 'hh.exe', 'R:\Example.chm');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  PADoReleaseEmbeddedApp;
end;

end.
Was jetzt noch nervt, ist das lästige Flackern beim Ändern der Fenstergröße.
  Mit Zitat antworten Zitat
Faxe

Registriert seit: 10. Jan 2013
28 Beiträge
 
Delphi XE3 Professional
 
#8

AW: Ersatz für Sleep?

  Alt 10. Mär 2016, 11:20
Was passiert wenn GetTickCount nach gut 41 Tagen wieder bei 0 anfängt?
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#9

AW: Ersatz für Sleep?

  Alt 10. Mär 2016, 12:14
Was passiert wenn GetTickCount nach gut 41 Tagen wieder bei 0 anfängt?
Man nimmt einen Kredit für die Stromrechnung auf.
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:59 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz