views:

154

answers:

2

This is approach I found for Tray ... :

http://www.programmersheaven.com/mb/delphikylix/257563/257563/how-can-i-make-a-system-tray-flash/

Does the same technique works for Dialogs ( as they are forms with addition params, in fact )? Or I can do it with way faster methods like getting handle / address / interface and overload or overdrive the function with FlashWindow(Ex) method?

I mean - can I make, for example ShowMessage(), window / dialog flash using FlashWindowEx() method and if I can, can it be done using the example in link given above?

Please, point to best direction or clarify my doubts ..

Thanks.

Sorry for bad formulation of question.

+2  A: 

The same technique applies to any top-level window, including dialog boxes. If you can get the window's handle, you can pass it to FlashWindowEx.

Rob Kennedy
+1  A: 

There are many ways a modal form or dialog (both VCL or native from the system) can be shown from a Delphi program, so you need to somehow hook into message processing and catch messages that are sent when a modal form or dialog is shown.

For that a message hook can be set using the SetWindowsHookEx() API function. Since you need this only while the application is inactive you could set it in the handler of the OnDeactivate application event, and reset it in the handler for the OnActivate application event:

var
  gNextHook: HHOOK;

procedure TForm1.AppActivate(Sender: TObject);
begin
  if gNextHook <> 0 then
    UnhookWindowsHookEx(gNextHook);
  gNextHook := 0;
end;

procedure TForm1.AppDeactivate(Sender: TObject);
begin
  gNextHook := SetWindowsHookEx(WH_CALLWNDPROC, @WndProcHook, 0,
    GetCurrentThreadId);
end;

The hook function would watch for messages that are sent when a modal dialog or form is shown, and call FlashWindowEx() with the correct parameters:

function WndProcHook(nCode: integer; AWParam: WPARAM; ALParam: LPARAM): LRESULT; stdcall;
var
  DataPtr: PCWPStruct;
  Fwi: TFlashWInfo;
begin
  DataPtr := PCWPStruct(ALParam);
  if (DataPtr^.message = WM_INITDIALOG)
    or ((DataPtr^.message = CM_ACTIVATE) and (DataPtr^.lParam = 0) and (DataPtr^.wParam = 0))
  then begin
    Fwi.cbSize := SizeOf(TFlashWInfo);
    // flash caption of new modal window
    Fwi.hwnd := DataPtr^.hwnd;
    Fwi.dwFlags := FLASHW_ALL or FLASHW_TIMERNOFG;
    Fwi.uCount := 0;
    Fwi.dwTimeout := 0;
    FlashWindowEx(Fwi);
    // uncomment this to flash task bar button as well
(*
    Fwi.hwnd := Application.MainForm.Handle;
    Fwi.dwFlags := FLASHW_TRAY or FLASHW_TIMERNOFG;
    FlashWindowEx(Fwi);
*)
  end;
  Result := CallNextHookEx(gNextHook, nCode, AWParam, ALParam);
end;

I chose WM_INITDIALOG which is sent for native dialogs like the open or save dialogs, and CM_ACTIVATE which is sent when a VCL form is shown modally. There may be more such messages that need to be caught. Above code works for the MessageDlg() function, the Application.MessageBox() function and TOpenDialog at least.

Since these dialogs don't have their own taskbar button I added (commented out) code to flash the taskbar button of the main form as well. This isn't optimal, as they flash out of sync.

Tested with Delphi 2009 on Windows XP, all error handling omitted, use it as a starting point only.

mghie