AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

was macht AllocateHWND genau?

Ein Thema von snook · begonnen am 10. Aug 2011 · letzter Beitrag vom 10. Aug 2011
Antwort Antwort
snook

Registriert seit: 25. Jun 2010
94 Beiträge
 
Delphi 2005 Professional
 
#1

was macht AllocateHWND genau?

  Alt 10. Aug 2011, 12:19
Delphi-Version: 5
hey,

wie der titel schon sagt, würde mich mal interessieren was AllocateHwnd genau bewirkt. hintergrund ist der, dass isch nen DLL-TImer geschrieben hab, der in nem eigenen Thread (aus der DLL gestartet) läuft und auf einen waitabletimer wartet. da ich in DLL's kein synchronize benutze, lasse ich den Timer via PostMessage sich mitteilen, wann er fertig ist.

und hier jetzt das interessante:

ich habe den thread in eine weitere klasse gekapselt, die via AllocateHWND ein fensterhandle bekommt, den thread startet und in ihrer MessageProc auf den timer reagiert. wenn ich das ganze in ner DLL laufen lasse, dann hab ich mich jetzt im nachhinein gewundert, dass die Message aus dem thread (ist ja via Postmessage gesendet) überhaupt ankommt. es gibt ja keine schleife die diese Message verarbeiten könnte. kann es sein, dass sich AllocateHWnd IMMER an das Application-Objekt aus der Hauptanwendung wendet, egal ob es in einer DLL aufgerufen wurde? wenn ja, wie geht das? woher kennt AllocateHwnd mein Application-Object?

viele grüße Basti
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.017 Beiträge
 
Delphi 12 Athens
 
#2

AW: was macht AllocateHWND genau?

  Alt 10. Aug 2011, 12:35
Du hast eine Professional, damit Zugriff auf den VCL-Quellcode und demnach auch auf das, was diese Funktion macht.

Wenn du in einem Thread ein Fenster erzeugst, dann mußt du in diesem Thread auch eine Nachrichtenschleife/-verarbetung einbauen, welche diese Nachrichten verarbeitet.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#3

AW: was macht AllocateHWND genau?

  Alt 10. Aug 2011, 12:52
eine ziemlich wirre Beschreibung. Hier würde mich mal der quelltext interessieren.
wie erzeugst du den Thread? Und an welcher Stelle erzeugst du dann den Timer (TTimer?).

Zitat:
...eine weitere klasse gekapselt, die via AllocateHWND ein fensterhandle bekommt, ...und in ihrer MessageProc auf den timer reagiert.
(wenn ich das ganze in ner DLL laufen lasse, dann hab ich mich jetzt im nachhinein gewundert, dass die Message aus dem thread (ist ja via Postmessage gesendet) überhaupt ankommt. es gibt ja keine schleife die diese Message verarbeiten könnte. ...)
Läuft in dem Thread in dem du AllocateHWND aufgerufen hast kein MessageLoop? Wenn die Klasse im gleichen Thread erzeugt wurde in dem auch dein TApplication.Run der Hauptanwendung läuft dann gibt es auch einen Messageloop.
Ein Messageloop bekommt (mit GetMessage etc.) alle Messages der Fenster des Threads in dem der Loop läuft.
Dabei ist es egal in welchem Programmmodul (dll, exe etc.) das Fensterhandel angefordert wurde. Ausschlaggebend ist einzig und allein der Thread.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's

Geändert von SirThornberry (10. Aug 2011 um 12:55 Uhr)
  Mit Zitat antworten Zitat
snook

Registriert seit: 25. Jun 2010
94 Beiträge
 
Delphi 2005 Professional
 
#4

AW: was macht AllocateHWND genau?

  Alt 10. Aug 2011, 13:00
okay, sry war wohl noch etwas zu früh am morgen , ich häng mal die unit rein
Delphi-Quellcode:
unit ExtDLLTimer;

interface

uses Windows, SysUtils, Classes, messages;

const
  CTI_MULT_FACTOR = 10000;
  CTI_MAXINTERVAL = $8000000000000000;
  CTI_MAXINTERVAL_MS = CTI_MAXINTERVAL div CTI_MULT_FACTOR;

// Timeout to wait for finishing timer-thread
  CTI_EXITTIMEOUT = 1000;

type
  TAPIWaitableTimer = class(TThread)
  private
    FOnTimer : TNotifyEvent;
    FTimer,
    FCloseEvent,
    FPauseEvent,
    FExitEvent : Cardinal;
    FInterval : Int64;
    FRunning,
    FContinuous : boolean;
    FHandle : HWND;
    procedure CLoseHandles;
    function GetEnabled: boolean;
    procedure ThrowTimerEvent;
    procedure SetEnabled(const Value: boolean);
    procedure SetInterval(const Value: Int64);
  protected
    procedure Execute; override;
    procedure StartTimer;
    procedure StopTimer;
  public
    constructor Create(AContinuous: boolean; ATimerObject: HWND;
      AExitEvent: Cardinal); reintroduce;
    destructor Destroy; override;
    property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
    property Enabled: boolean read GetEnabled write SetEnabled;
    property CloseEvent: Cardinal read FCloseEvent;
    property Interval: Int64 read FInterval write SetInterval;
  end;

  TDLLTimer = class(TObject)
  private
    FHandle : HWND;
    FExitEvent : Cardinal;
    FOnTimer : TNotifyEvent;
    FTimer : TAPIWaitableTimer;
    FContinuous: boolean;
    FInterval : Cardinal;
    function GetEnabled: boolean;
    procedure OnAPITimer(Sender: TObject);
    procedure APITimerTerminated(Sender: TObject);
  public
    constructor Create(AContinuous: boolean); reintroduce;
    destructor Destroy; override;
    procedure WndProc(var Msg: TMessage);
    procedure StartTimer(AInterval: Int64);
    procedure StopTimer;
    property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
    property Enabled: boolean read GetEnabled;
  end;

implementation

{ TAPIWaitableTimer }

constructor TAPIWaitableTimer.Create(AContinuous: boolean; ATimerObject: HWND;
  AExitEvent: Cardinal);
begin
  inherited create(false);
  FHandle := ATimerObject;
  FExitEvent := AExitEvent;
  FTimer := CreateWaitableTimer(nil, false, PChar(''));
  FCloseEvent := CreateEvent(nil, false, false, PChar(''));
  FPauseEvent := CreateEvent(nil, false, false, PChar(''));
  FRunning := false;
  FContinuous := AContinuous;
  FreeOnTerminate := true;
  SetInterval(1000);
end;

destructor TAPIWaitableTimer.Destroy;
begin
  CloseHandles;
  SetEvent(FExitEvent);
  inherited;
end;

procedure TAPIWaitableTimer.CloseHandles;
begin
  if FTimer > 0 then
    closehandle(FTimer);
  if FCLoseEvent > 0 then
    closehandle(FCloseEvent);
  if FPauseEvent > 0 then
    closehandle(FPauseEvent);
  FTimer := 0;
  FCloseEvent := 0;
end;

procedure TAPIWaitableTimer.Execute;
var objs : Array[0..2] of Cardinal;
    lQuit: boolean;
begin
  lQuit := false;
  if (FTimer > 0) and (FCloseEvent > 0) then
  begin
    objs[0] := FTimer;
    objs[1] := FCloseEvent;
    objs[2] := FPauseEvent;
    repeat

      case WaitForMultipleObjects(3, @objs, false, INFINITE) of
        WAIT_OBJECT_0 :
          begin
// synchronize(ThrowTimerEvent);
            PostMessage(FHandle, WM_TIMER, 0, 0);
            FRunning := false;
            if FContinuous then StartTimer;
          end;
        WAIT_OBJECT_0 + 1: lQuit := true;
        WAIT_OBJECT_0 + 2:
          case Enabled of
            true : StopTimer;
            false : StartTimer;
          end;
      end;
    until lQuit;
  end;
  Terminate;
end;

function TAPIWaitableTimer.GetEnabled: boolean;
begin
  result := (FTimer > 0) and (FCloseEvent > 0) and FRunning;
end;

procedure TAPIWaitableTimer.SetEnabled(const Value: boolean);
begin
  if Value <> Enabled then
    SetEvent(FPauseEvent);
  if suspended then
    resume;
end;

procedure TAPIWaitableTimer.SetInterval(const Value: Int64);
begin
  FInterval := Value;
  if Enabled then StartTimer;
end;

procedure TAPIWaitableTimer.StartTimer;
const WaitDur = 10;
var Duration: TLargeInteger;
    Per : Integer;
begin
  // not sure why have to wait, but else timer sometimes behaves corrupted
  sleep(WaitDur);
  if abs(FInterval) > abs(CTI_MAXINTERVAL_MS) then
    raise Exception.Create('Maximum Interval exceeded!');
  FInterval := FInterval - WaitDur;
  Duration := (-1) * FInterval * CTI_MULT_FACTOR;
  Per := 0;
  FRunning := SetWaitableTimer(FTimer, Duration, Per, nil, nil, true);
  if not FRunning then
    raise Exception.Create(SysErrorMessage(GetLastError));
  if suspended then
    resume;
end;

procedure TAPIWaitableTimer.StopTimer;
begin
  FRunning := false;
  if not CancelWaitableTimer(FTimer) then
    raise Exception.Create(SysErrorMessage(GetLastError));
end;

procedure TAPIWaitableTimer.ThrowTimerEvent;
begin
  if FRunning and Assigned(FOnTimer) then
    FOnTimer(self);
end;

{ TDLLTimer }

constructor TDLLTimer.Create(AContinuous: boolean);
begin
  inherited create;
{$IFDEF MSWINDOWS}
  FHandle := Classes.AllocateHWnd(WndProc);
{$ENDIF}
{$IFDEF LINUX}
  FHandle := WinUtils.AllocateHWnd(WndProc);
{$ENDIF}
  FContinuous := AContinuous;
  FExitEvent := CreateEvent(nil, false, false, '');
  FTimer := TAPIWaitableTimer.Create(AContinuous, FHandle, FExitEvent);
  FTImer.OnTimer := OnAPITimer;
  FTimer.OnTerminate := APITimerTerminated;
end;

destructor TDLLTimer.Destroy;
begin
{$IFDEF MSWINDOWS}
  Classes.DeallocateHWnd(FHandle);
{$ENDIF}
{$IFDEF LINUX}
  WinUtils.DeallocateHWnd(FHandle);
{$ENDIF}
  FTimer.OnTerminate := nil;
  ResetEvent(FExitEvent);
  SetEvent(FTimer.CloseEvent);
  case WaitForSingleObject(FExitEvent, CTI_EXITTIMEOUT) of
    WAIT_OBJECT_0: FTimer := nil;
    WAIT_TIMEOUT : raise Exception.Create('Error releasing DLLTimer');
  end;
  inherited;
end;

procedure TDLLTimer.APITimerTerminated(Sender: TObject);
var lEnabled: boolean;
begin
  lEnabled := FTimer.Enabled;
  if Assigned(FTimer.FatalException) then
    raise Exception.Create(Exception(FTimer.FatalException).Message)
  else
  begin
    ResetEvent(FExitEvent);
    FTimer := TAPIWaitableTimer.Create(FContinuous, FHandle, FExitEvent);
    FTImer.OnTimer := OnAPITimer;
    FTimer.OnTerminate := APITimerTerminated;
    FTimer.Interval := FInterval;
    if lEnabled then
      FTimer.StartTimer;
  end;
end;

function TDLLTimer.GetEnabled: boolean;
begin
  result := FTimer.Enabled;
end;

procedure TDLLTimer.OnAPITimer(Sender: TObject);
begin
  if Assigned(FOnTimer) then
    FOnTimer(Sender);
end;

procedure TDLLTimer.StartTimer(AInterval: Int64);
begin
  FInterval := AInterval;
  FTimer.Interval := AInterval;
  FTimer.Enabled := true;;
end;

procedure TDLLTimer.StopTimer;
begin
  FTimer.Enabled := false;
end;

procedure TDLLTimer.WndProc(var Msg: TMessage);
begin
  case Msg.Msg of
    WM_TIMER: OnApiTimer(FTimer);
  end;
end;

en
d.
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#5

AW: was macht AllocateHWND genau?

  Alt 10. Aug 2011, 13:12
Und in welchem Thread wird TDllTimer erzeugt? Davon ist abhängig wer/was die Nachrichten in die WindowProc von TDLLtimer befördert.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
snook

Registriert seit: 25. Jun 2010
94 Beiträge
 
Delphi 2005 Professional
 
#6

AW: was macht AllocateHWND genau?

  Alt 10. Aug 2011, 13:18
TDLLTimer wird z.B. in einer DLL erzeugt. und diese DLL wird aus dem Kontext des Hauptthreads geladen
  Mit Zitat antworten Zitat
Benutzerbild von SirThornberry
SirThornberry
(Moderator)

Registriert seit: 23. Sep 2003
Ort: Bockwen
12.235 Beiträge
 
Delphi 2006 Professional
 
#7

AW: was macht AllocateHWND genau?

  Alt 10. Aug 2011, 13:20
Zitat:
TDLLTimer wird z.B. in einer DLL erzeugt. und diese DLL wird aus dem Kontext des Hauptthreads geladen
Dann steht der Grund ja in meinem ersten Post in diesem Thema.
Es ist unerheblich in welchem Programmmodul der Code zum erzeugen liegt und es ist auch unerheblich in welchem Threadcontext die DLL geladen wurde.
Der Threadcontext in dem das Fensterhandle angefordert wird ist maßgebend.
Jens
Mit Source ist es wie mit Kunst - Hauptsache der Künstler versteht's
  Mit Zitat antworten Zitat
snook

Registriert seit: 25. Jun 2010
94 Beiträge
 
Delphi 2005 Professional
 
#8

AW: was macht AllocateHWND genau?

  Alt 10. Aug 2011, 13:22
ooohh krass. ich hab die ganze zeit gedacht die message loop ist vom modul abhängig. perfekt, dank dir

ähem, dann hab ich wohl einiges anderes auch noch nicht verstanden. wieso bekommt denn dann der klassische TTimer aus delphi kein WM_TIMER Event geschickt, wenn er in einer DLL erzeugt wurde?

Geändert von snook (10. Aug 2011 um 13:25 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.017 Beiträge
 
Delphi 12 Athens
 
#9

AW: was macht AllocateHWND genau?

  Alt 10. Aug 2011, 15:01
Nein, die Message-Behandlung ist immer vom threadabhängig.

Die Message-Behandlung in Komponenten ist von dem Thread abhängig, in welchem sie erstellt werden.

Grundsätzlich hat erstmal jeder Thread keine Message-Queue.
Sobald die erste anfrage an diesen Thread gestellt wird, wird für diesen Thread eine solche Queue (Warteschleife) eingerichtet.

PostThreadMessage schickt die Nachricht direkt an die Queue eines Threads und PostMessage/SendMessage schicken die Nachrichten an den Thread, in welchem diese Komponente erstellt wurde.

Und eine "Message-Loop" verarbeitet nur Messages des Threads, in welchem sie läuft.
Für den Hauptthread stellt Delphi-Referenz durchsuchenApplication eine "Message-Loop" bereit und für andere Threads müßte man das selber machen.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#10

AW: was macht AllocateHWND genau?

  Alt 10. Aug 2011, 17:23
ähem, dann hab ich wohl einiges anderes auch noch nicht verstanden. wieso bekommt denn dann der klassische TTimer aus delphi kein WM_TIMER Event geschickt, wenn er in einer DLL erzeugt wurde?
Weil der sich an das Application-Objekt wendet. Und diese sind verschieden in DLL und Exe.
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 22:26 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