![]() |
Eigene Timer Komponente aus der MMSystem
Hi,
ich habe versucht eine eigene Timer Komponente zu basteln, die den MultiMedia Timer aus der Unit MMSystem verwendet ... Leider kommt es immer wieder zu AccessViolations. Kann mir da jemand helfen:
Delphi-Quellcode:
Florian
unit SystemTimer;
interface uses Windows, SysUtils, MMSystem, Classes, SyncObjs; type TSystemTimer = class(TObject) private TimerID: Longword; FOnTimer: TNotifyEvent; FInterval: integer; procedure SetInterval(Value: integer); function GetInterval: integer; public procedure StartTimer; procedure StopTimer; constructor Create; destructor Destroy; override; published property Interval: integer read GetInterval write SetInterval; property OnTimer: TNotifyEvent read FOnTimer write FOnTimer; end; implementation var Timers: TList; IDs: TStringList; CS: TCriticalSection; procedure TSystemTimer.SetInterval(Value: integer); begin FInterval := Value; end; function TSystemTimer.GetInterval: integer; begin Result := FInterval; end; procedure TimerCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; begin CS.Enter; if assigned(TSystemTimer(Timers[IDs.IndexOf(IntToStr(uTimerID))]).OnTimer) then TSystemTimer(Timers[IDs.IndexOf(IntToStr(uTimerID))]).OnTimer(TSystemTimer(Timers[IDs.IndexOf(IntToStr(uTimerID))])); CS.Leave; end; constructor TSystemTimer.Create; begin inherited Create; end; destructor TSystemTimer.Destroy; begin inherited Destroy; end; procedure TSystemTimer.StartTimer; begin Timers.Add(Pointer(Self)); TimerID := timeSetEvent(FInterval, 0, TimerCallback, 0, TIME_PERIODIC); IDs.Add(IntToStr(TimerID)); end; procedure TSystemTimer.StopTimer; begin timeKillEvent(TimerID); Timers.Delete(IDs.IndexOf(IntToStr(TimerID))); IDs.Delete(IDs.IndexOf(IntToStr(TimerID))); end; initialization IDs := TStringList.Create; Timers := TList.Create; CS := TCriticalSection.Create; finalization Timers.Free; IDs.Free; CS.Free; end. |
Re: Eigene Timer Komponente aus der MMSystem
Anstelle der globalen Listen würde ich einfach der Callback-Funktion die Instanz mitgeben. Somit kannst du in der globalen Callbackfunktion über den übergebenen Parameter die Methode der Instanz aufrufen.
|
Re: Eigene Timer Komponente aus der MMSystem
:gruebel: Kannst du mir ein Codebeispiel geben? Ich verstehe nicht so ganz, wie du das meinst.
Florian |
Re: Eigene Timer Komponente aus der MMSystem
so ...
gruß Stoxx
Delphi-Quellcode:
unit SystemTimerU;
interface uses Windows, SysUtils, MMSystem, Classes; type TMMTimerData = record Instanz : TObject; end; PMMTimerData = ^TMMTimerData; TSystemTimer = class(TObject) private pSelfData : PMMTimerData; TimerID: Longword; FOnTimer: TNotifyEvent; FInterval: integer; procedure SetInterval(Value: integer); function GetInterval: integer; public procedure StartTimer; procedure StopTimer; constructor Create; destructor Destroy; override; published property Interval: integer read GetInterval write SetInterval; property OnTimer: TNotifyEvent read FOnTimer write FOnTimer; end; implementation //============================================================================== constructor TSystemTimer.Create; begin inherited Create; TimerID := 0; new(PSelfData); end; //============================================================================== destructor TSystemTimer.Destroy; begin FOnTimer := nil; self.stopTimer; dispose(PSelfData); sleep(50); // eigenartige Abstürze ohne dies inherited Destroy; end; //============================================================================== procedure TSystemTimer.SetInterval(Value: integer); begin FInterval := Value; end; //============================================================================== function TSystemTimer.GetInterval: integer; begin Result := FInterval; end; //============================================================================== procedure TimerCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; pascal; var Timer : TSystemTimer; selfData : TMMTimerData; begin if dwUser <> 0 then begin SelfData := pMMTimerData(dwUser)^; Timer := TSystemTimer(selfdata.instanz); if assigned(Timer.FOnTimer) then Timer.FOnTimer(Timer); end; end; //============================================================================== procedure TSystemTimer.StartTimer; begin PSelfData.Instanz := Self; if TimerID = 0 then TimerID := timeSetEvent(FInterval, 0, @TimerCallback, Integer(pSelfData), TIME_PERIODIC); end; //============================================================================== procedure TSystemTimer.StopTimer; begin pSelfData.Instanz := nil; if TimerID <> 0 then timeKillEvent(TimerID); TimerID := 0; end; end. |
Re: Eigene Timer Komponente aus der MMSystem
Eine überarbeitete Variante ohne Probleme mit Sleep:
Delphi-Quellcode:
Das ganze könnte dann auch in die Tool-Palette installiert werden, und natürlich auch noch um die eine oder andere Eigenschaft (z.B.: Resolution) erweitert werden.
unit compFastTimer;
interface uses Windows, SysUtils, MMSystem, Classes; type TFastTimer = class(TComponent) private fTimerID: Longword; fInterval: Integer; pSelfData : PMMTimerData; FOnTimer: TNotifyEvent; fEnabled: Boolean; procedure SetInterval(Value: integer); function GetInterval: integer; procedure SetEnabled(const Value: Boolean); public constructor Create(Owner: TComponent); Override; destructor Destroy; override; published property Enabled: Boolean read fEnabled write SetEnabled; property Interval: integer read GetInterval write SetInterval; property OnTimer: TNotifyEvent read FOnTimer write FOnTimer; end; implementation Const TIME_KILL_SYNCHRONOUS = $0100; procedure TimerCallback(uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD) stdcall; pascal; var ATimer: TFastTimer; begin if dwUser <> 0 then begin ATimer := TFastTimer(dwUser); if Assigned(ATimer.fOnTimer) then ATimer.fOnTimer(ATimer); end; end; { TFastTimer } constructor TFastTimer.Create(Owner: TComponent); begin inherited; fTimerID := 0; fInterval := 1000; end; destructor TFastTimer.Destroy; begin Enabled := FALSE; inherited; end; function TFastTimer.GetInterval: integer; begin Result := fInterval; end; procedure TFastTimer.SetInterval(Value: integer); begin fInterval := Value; end; procedure TFastTimer.SetEnabled(const Value: Boolean); begin if fEnabled <> Value then begin fEnabled := Value; if fEnabled then begin // Timer starten ... fTimerID := timeSetEvent(fInterval, 0, @TimerCallback, Integer(Self), TIME_PERIODIC Or TIME_KILL_SYNCHRONOUS); end else begin timeKillEvent(fTimerID); fTimerID := 0; end; end; end; end. ACHTUNG!!! Updates der grafischen Oberfläche in OnTimer sind natürlich verboten!! (siehe ![]() ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:53 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz