Timer in a dll file.

Hey,

How do you add a timer to a dll file. Setting a variable as TTimer is not possible.

Thnx!
TonyJizAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

paulb1989Commented:
You will need to create a form in your DLL using File-New-Form and put the timer on there.

When you need to use the timer, create the form and you can use the timer that's on it.

Also remember to free the form when you're finished.
0
Wim ten BrinkSelf-employed developerCommented:
There are dozens of ways to do this. You could add a form or datamodule to the DL, drop a TTimer on it and just create the form/datamodule when you require the timer.
You could also just add a messageloop and the Windows API if you want a real minimal timer. Or you create the TTimer dynamically but then you need to pass a parenthandle to this timer, since it needs to hook into the messageloop.
0
wjmfzszCommented:
Give you a example:
1. add a variable tmpTimer:TTimer to your object;
2. create/destroy this TTime in your create/destroy produce.
   add "tmpTimer:=TTimer.Create(nil);" to your create produce.
   add "tmpTimer.Free" to your destroy produce.
3. assign a TTimer event to TTimer.OnTimer;
   declare a produce like this: produce EventTimer(Sender:TObject);
   assign this produce to TTimer.OnTimer: tmpTimer.OnTimer:=EventTimer;
0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

TonyJizAuthor Commented:
Thnx, but anyone else? Using a form is not an option.
0
Wim ten BrinkSelf-employed developerCommented:
The alternative is to use the Windows API in your DLL. But in all situations you will need a messageloop to handle the message that the timer will be sending to your application. This means that you will have to create an (invisible) window and have a loop somewhere to process the messages for this window. Preferably in a separate thread but that would mean that the communications with your main thread will be troublesome.
Using a form or datamodule would remove the need for these Windows API solutions but  I agree, it adds a lot of overhead to your DLL.

At http://www.workshop-alex.org/Wallpaper/Wallpaper.html I have some simple trayicon example that uses the Windows API to run a timer. It shows you how to use a timer and how to respond on other messages too. The timer logic is encapsulated in the WindowProc routine, where I enable or disable the timer and also respond on the timer messages. (It also displays a trayicon and can change your desktop wallpaper.)

If your DLL or executable doesn't support a messageloop in any way then there is no solution. Even thread synchronisations won't work if you don't have any message handler in your application.

0
TonyJizAuthor Commented:
Hey,

if I add a form to the dll file, then put a timer on the form, then put a messagebox on the timer event, then run the dll from another program, then the messagebox wont show up.

Any ideas?
Thnx!
0
Wim ten BrinkSelf-employed developerCommented:
Did you create the form? DLL's don't generally create forms...
Anyway, I've tried it myself this time and you're right. I forgot. The form will still depend on the main thread having a messageloop. If your executable doesn't have one, it will never process the messages sent in your DLL.

For those who are interested, I created this tiny DLL, that doesn't need any DFM files or whatever:

library TimerDLL;
uses Windows, SysUtils, Classes, Forms, extctrls;

type
  TDLLForm = class( TForm )
  private
    Timer: TTimer;
  protected
  public
    procedure TimerAction( Sender: TObject );
  end;

function StartTimer: Pointer; stdcall; export;
var
  AForm: TDLLForm;
begin
  Result := nil;
  try
    AForm := TDLLForm.CreateNew( Application );
    AForm.Timer := TTimer.Create( AForm );
    AForm.Timer.Interval := 1000;
    AForm.Timer.OnTimer := AForm.TimerAction;
    AForm.Timer.Enabled := True;
    Result := AForm;
  except on E: Exception do MessageBox( GetDesktopWindow, PChar( E.Message ), 'Exception', MB_OK );
  end;
end;

procedure StopTimer( const ATimer: Pointer ); stdcall; export;
begin
  if Assigned( ATimer ) then TDLLForm( ATimer ).Free;
end;
exports StartTimer, StopTimer;

procedure TDLLForm.TimerAction( Sender: TObject );
begin
  MessageBox( GetDesktopWindow, 'Hello, World.', 'Timer', MB_OK );
end;

begin
  Application.Run;
end.

And it works quite nice if the application that loads this DLL contains a messageloop since the form in this DLL just hooks into the existing messageloop. But if there's no messageloop then this code just gets stuck.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Wim ten BrinkSelf-employed developerCommented:
Well, let me show you the nightmare code of the timer that does work in a DLL and it's even a very small solution too! (No forms!)

library DLL_Timer;

uses Windows;

const
  sTimerWndClass = 'Timer';
  ExStyle = WS_EX_TOOLWINDOW;
  Style = WS_CAPTION or WS_SYSMENU or WS_MINIMIZEBOX;
  TimerWndClass: TWndClass = (
    style: CS_CLASSDC or CS_PARENTDC;
    lpfnWndProc: nil;
    cbClsExtra: 0;
    cbWndExtra: 0;
    hInstance: 0;
    hIcon: 0;
    hCursor: 0;
    hbrBackground: color_btnface + 1;
    lpszMenuName: nil;
    lpszClassName: sTimerWndClass );

var
  AThread: THandle = 0;
  AThreadID: Cardinal;
  AHandle: THandle = 0;

procedure TimerProc( Handle: HWND; Ms, Event: UINT; Time: DWORD ); stdcall;
begin
  MessageBox( GetDesktopWindow, 'Hello, World.', 'Timer', MB_OKCANCEL );
end;

function ThreadProc( Value: Pointer ): Integer;
var
  ATimer: THandle;
  AMsg: TMsg;
begin
  AHandle := CreateWindowEx( ExStyle, sTimerWndClass, nil, Style, 0, 0, 10, 10, GetDesktopWindow, 0, hInstance, nil );
  UpdateWindow( AHandle );
  ATimer := SetTimer( AHandle, 0, 1000, @TimerProc );
  while ( GetMessage( aMsg, AHandle, 0, 0 ) ) do begin
    TranslateMessage( aMsg );
    DispatchMessage( aMsg );
  end;
  KillTimer( AHandle, ATimer );
  Result := 0;
end;

procedure StartTimer;
begin
  if ( AThread = 0 ) then begin
    AThread := BeginThread( nil, 0, ThreadProc, nil, 0, AThreadID );
  end;
end;

procedure StopTimer;
begin
  if not ( AThread = 0 ) then begin
    CloseWindow( AHandle );
    AThread := 0;
  end;
end;

exports StartTimer, StopTimer;

begin
  TimerWndClass.lpfnWndProc := @DefWindowProc;
  RegisterClass( TimerWndClass );
end.

Above DLL code compiles to less than 20 KB and will display a messagebox that you can close by pressing OK. Keep in mind that this code needs to use a thread since it needs a messageloop. I did not use the TThread class since there's no real need for it. We can't synchronise correctly with the main thread if the main thread has no messageloop anyway. But above code will work nicely in a simple console application.
Just be very, very aware of the multiple threading issues that you can and will encounter.

The sample console application that uses above code;

program Timer;
{$APPTYPE CONSOLE}
procedure StartTimer; external 'DLL_Timer.dll';
procedure StopTimer; external 'DLL_Timer.dll';
begin
  StartTimer;
  Write( 'Press <Enter> to quit.' );
  ReadLn;
  StopTimer;
end.

Wow, that looks easy. :-)
0
TonyJizAuthor Commented:
Thnx man!
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.