Solved

Monitor for a specific window / process

Posted on 2003-11-23
5
437 Views
Last Modified: 2010-04-03
Hello All,

I know how to get all the current windows or processes, but for some reason I'm having trouble with something that should be much simpler than that.

I want to monitor for a specific caption and then execute an action if the caption becomes visible.  For example, my app will run in the background, if it sees a window named 'Outlook' then I want it to execute an action or run a function.  I would also like this to be friedly with system resources, but spontanious.  In other words, I don't want to hang a slow system with a low interval timer, but I want the app to react instantly to the apearence of 'Outlook'

If possible, I would like to get partial captions.  As-In if part of the caption is 'Outlook'.  So even if the actual caption is 'Microsoft Outlook' or 'Microsoft Outlook - Contacts' It will still fire my function.

I hope I am clear.  :)
// Happy Coding
0
Comment
Question by:fibdev
  • 2
  • 2
5 Comments
 
LVL 7

Assisted Solution

by:jconde
jconde earned 25 total points
ID: 9809201
Hi!

In my example, button1 shows the list of the executable files currently running.  Button2 displays all of the running window-captions.  I beleive the code for "Button2" will be the one that helps you out the most.

Basically, modify the code and fit it into a timer and parse each string to find the application you're looking for:


unit Unit1;

interface

uses
  Controls, StdCtrls, Classes, Forms, windows, SysUtils, tlhelp32;

type
  TForm1 = class(TForm)
    Button1: TButton;
    ListBox1: TListBox;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  WindowList: TList;

implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
var
 I: Integer;
 Snapshot: THandle;
 PE: TProcessEntry32;
begin
 ListBox1.Clear;
 Snapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 if (Snapshot = DWORD(-1)) then
     Exit;
 PE.dwSize := SizeOf(TProcessEntry32);
 if Process32First(Snapshot, PE) then
 repeat
   I := ListBox1.Items.Add(PE.szExeFile);
 until not Process32Next(Snapshot, PE);
 CloseHandle (Snapshot);
end;

function GetWindow (Handle: HWND; LParam: longint): bool; stdcall;
begin
  Result := true;
  WindowList.Add (Pointer(Handle));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i: integer;
  Hnd: HWND;
  Buffer: array [0..255] of char;
begin
  ListBox1.Clear;
  try
    WindowList := TList.Create;
    EnumWindows (@GetWindow, 0);
    ListBox1.Items.Clear;
    for i := 0 to WindowList.Count - 1 do begin
      Hnd := HWND (WindowList [i]);
      if IsWindowVisible (Hnd) then begin
        GetWindowText (Hnd, Buffer, SizeOf (Buffer) - 1);
        if Buffer [0] <> #0 then
          ListBox1.Items.Add (StrPas(Buffer));
      end;
    end;
  finally
    WindowList.Free;
  end;
end;

end.
0
 
LVL 5

Expert Comment

by:DeerBear
ID: 9810052
Hi,

You can "easily" do it using hooks <g>.

It's enough to use the GetMessage hook, and monitor the WM_SETFOCUS message.
Once you find the window text and compare it to your text, you can issue the
related action.

HTH,

Andrew

P.S. To use Hooks, have a look at SetWindowsHookEx/UnHookWindowsHookEx.
0
 
LVL 3

Author Comment

by:fibdev
ID: 9810238
jCondi,

Thanks for the code.  I am already alble to do that.  :)

DeerBeer,

Please elaborate  :)
0
 
LVL 5

Accepted Solution

by:
DeerBear earned 25 total points
ID: 9810379
Hi again,

I was simply saying you should use a hook, specifically the WH_GETMESSAGE hook, which will
monitor the incoming messages for a Window. It can be local or system wide.

In the system-wide version, you can monitor all messages from all the windows in the system,
thus you just retrieve the caption for the Window you're interested in and then issue appropriate
action if the message is WM_SETFOCUS or WM_SETFOREGROUND( which is the one that actually
makes the form visible ).

That's all, in theory.

The problem is in practice <g>.

Now I'll show you a very simple way to implement what you need, but please
beware that this code can be DANGEROUS and you can't debug it as you'd do
with any other DLL, k?

I'll simply write it without testing it, thus you'll have to test it on your own.

If someone has the time to, please look at it and correct it if needed.

Code:


library TestLib;

interface

uses Windows, Messages,
       uWindowUtils; // This unit comes from my own codebase and will be posted just after the
                            // library code.

var Caption : String;

function GetMessageHook (code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
var Msg : tagMsg;
     TmpCaption : String;
begin
  if code > 0 then
  begin
     @Msg := Pointer( lparam );
     case Msg.message of
        WM_SETFOREGROUND : begin
                                               TmpCaption := uWindowUtils.GetWindowText( Msg.Handle );
                                               if TmpCaption = Caption then
                                                  DoYourActionHere;
                                            end;
    end;
  end
  else Result := CallNextHook( WH_GETMESSAGE,wparam,lparam );
end;

var TheHook : Integer;

procedure InstallHook( CaptionValue : String );stdcall;
begin
   Caption := CaptionValue;
   theHook := SetWindowsHookEx(WH_GETMESSAGE, @MyHookProc, hInstance, 0);
end;

procedure RemoveHook;stdcall;
begin
   UnhookWindowsHookEx(theHook);
end;

exports
 
    InstallHook index 1,
    RemoveHook index 2;

end.

uWindowUtils module:

unit uWindowUtils;

interface

uses Windows;

function GetWindowText( Handle : THandle ) : String;
function GetWindowClass( Handle : THandle ) : String;

implementation

function GetWindowText( Handle : THandle ) : String;
var WText : PChar;
    TxtBuf : String;
begin
  GetMem( WText,255 );
  Windows.GetWindowText( Handle,WText,255 );
  TxtBuf := WText;
  Result := TxtBuf;
  FreeMem( WText );
end;

function GetWindowClass( Handle : THandle ) : String;
var WText : PChar;
    TxtBuf : String;
begin
  GetMem( WText,255 );
  GetClassName( Handle,WText,255 );
  TxtBuf := WText;
  Result := TxtBuf;
  FreeMem( WText );
end;

end.

To make it work appropriately, you'll need to setup a MemoryMappedFile.

Look to my reply history for an example of how to do it.

HTH,

Andrew
0
 
LVL 3

Author Comment

by:fibdev
ID: 10090568
I didn't really get what I was after... Just cleaning house.  Happy new year.  :)
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now