Solved

Detecting application launches

Posted on 2003-11-14
9
520 Views
Last Modified: 2010-05-18
Is there a way (I suspect a particular windows message) to find out when people launch programs/applications? Secondly once I can detect that is it possible to find out if it was launced with any parameters etc.?
0
Comment
Question by:Mat_a
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
9 Comments
 
LVL 6

Expert Comment

by:DaFox
ID: 9750014
Nope there's no windows message that notifies your app that a second one was launched.
A windows hook would be one possibility to detect the launch though.

Markus
0
 

Author Comment

by:Mat_a
ID: 9750191
I'm not looking to see if my app is run again, I'm wanting to monitor all application activity. If you have any info on windows hooks to do this I will award the points, any answer to this would be great :)
0
 
LVL 6

Expert Comment

by:DaFox
ID: 9750727
Mat,

I was not talking about a second instance of your application, I meant a totally different application (I think that's what you are aiming at, right ;-)).
What kind of activity are you after? If you just want to know if app xy is launched, you could do it with a hook (if you got the classname, window title, ... of it).
If nobody else has a better idea I'll have a look at my personal code library for an example! ;-)

Markus
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:Mat_a
ID: 9750813
Markus

Ok, just double checking... A present it will be monitoring game launches. I could put a fake exe file there that send all teh params on and reports, but it's a lot of hassle for end users (and I don't even know if my idea will work), so I was hoping to find out when a game gets launched and what params are used :)

Have to say I've never done hooks before.
0
 
LVL 6

Accepted Solution

by:
DaFox earned 200 total points
ID: 9754780
Hi Mat,

here we go, hope this helps:

app:

function SetHook(): Boolean; stdcall; external 'MatHook.dll';
function RemoveHook(): Boolean; stdcall; external 'MatHook.dll';

// ...

procedure TForm1.Button1Click(Sender: TObject);
begin
  if (not SetHook) then ShowMessage('Couldn''t start Hook');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if (not RemoveHook) then ShowMessage('Couldn''t stop Hook');
end;

---

DLL:

library MatHook;

uses
  Windows,
  Messages;

type
  THookRec = record
    hMatHook: HHOOK;
    hMatWnd: HWND;
    oldProc: Integer;
  end;

var
  map: DWord;
  buf: ^THookRec;

// new window proc - runs in context of target process
function MatWndProc(Handle: hWnd; Msg: uInt; wp: wParam; lp: lParam): LongInt; stdcall;
begin
  try
    case Msg of
      WM_CREATE:
      begin
        MessageBox(0, GetCommandLine, 'Command Line parameter(s)', MB_OK);
      end;

      // user definied message to stop subclassing
      // (RegisterWindowMessage would be a better choice instead of WM_USER message!)
      WM_USER + 1:
      begin
        // delete custom menu entries (quick'n'dirty)
        SetWindowLong(buf^.hMatWnd, GWL_WNDPROC, buf^.oldProc);
      end;

    end;
    Result := CallWindowProc(Pointer(buf^.oldProc), Handle, Msg, wp, lp);
  except
    Result := 0;
  end;
end;

// hook proc - waits for target window to be created
function MatHookProc(nCode: Integer; wp: wParam; lp: lParam): LongInt; stdcall;
var
  hTemp: hWnd;
  szClass: array[0..255] of Char;
begin
  try
    if (nCode >= HC_ACTION) then
    begin
      Case nCode of
        HCBT_CREATEWND:
        begin
          hTemp := HWND(wp);
          FillChar(szClass, 256, 0);
          GetClassName(hTemp, szClass, 256);
          if (szClass = 'Notepad') then
          begin
            buf^.hMatWnd := htemp;
            buf^.oldProc := GetWindowLong(buf^.hMatWnd, GWL_WNDPROC);
            SetWindowLong(buf^.hMatWnd, GWL_WNDPROC, Integer(@MatWndProc));
          end;
        end;
        HCBT_DESTROYWND:
        begin
          hTemp := HWND(wp);
          FillChar(szClass, 256, 0);
          GetClassName(hTemp, szClass, 256);
          if (szClass = 'Notepad') then
          begin
            SetWindowLong(buf^.hMatWnd, GWL_WNDPROC, buf^.OldProc);
          end;

        end;
      end;
    end;
    Result := CallNextHookEx(buf^.hMatHook, nCode, wp, lp);
  except
    Result := 0;
  end;
end;

// sets up hook
function SetHook: Boolean; stdcall; export;
begin
  try
    Result := false;
    if (not assigned(buf)) then
    begin
      map := CreateFileMapping(DWord(-1), nil, PAGE_READWRITE, 0, SizeOf(THookRec), 'HookRecMemBlock');
      buf := MapViewOfFile(map, FILE_MAP_ALL_ACCESS, 0, 0, 0);
      buf^.hMatHook := SetWindowsHookEx(WH_CBT, @MatHookProc, hInstance, 0);
      Result := true;
    end;
  except
    Result := false;
  end;
end;

// removes hook
function RemoveHook: Boolean; stdcall; export;
begin
  Result := false;
  if (assigned(buf)) then
  begin
    // tell our new wnd proc to stop subclassing
    // (has to be done in context of target process)
    SendMessage(buf^.hMatWnd, wm_User + 1, 1, 0);
    if (buf^.hMatHook <> 0) then UnhookWindowsHookEx(buf^.hMatHook);
    buf^.hMatHook := 0;
    UnmapViewOfFile(buf);
    buf := nil;
    Result := true;
  end;
end;

// DLL entry point
procedure DllEntry(dwReason: DWord);
begin
  Case dwReason of
    DLL_PROCESS_ATTACH:
    begin
      if (not assigned(buf)) then
      begin
        map := OpenFileMapping(FILE_MAP_ALL_ACCESS, false, 'HookRecMemBlock');
        buf := MapViewOfFile(map, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        CloseHandle(map);
        map := 0;
      end;
    end;
    DLL_PROCESS_DETACH:
    begin
      UnmapViewOfFile(buf);
      buf := nil;
    end;
  end;
end;

exports
  SetHook,
  RemoveHook;

// main
begin
  DisableThreadLibraryCalls(hInstance);
  DllProc := @DLLEntry;
  DllEntry(DLL_PROCESS_ATTACH);
end.


PS:
>> I could put a fake exe file there that send all teh params on and reports, but it's a lot of
>> hassle for end users (and I don't even know if my idea will work).

Yep, this would work. But what if your end user installs a patch or something else? Replacing the exe would be easy but has much side effects.

Markus
0
 
LVL 6

Expert Comment

by:DaFox
ID: 9754783
btw: the sample above subclasses notepad, just compile, run it and open notepad...
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 9758509
you can use the IShellExecuteHook (doesn't 'catch' the apps run with CreateProcess)
http://www.delphi-si.com/forum/prikazisporocila.php?tema=271&mesto=0

// main unit source
unit mainunit;

interface

uses
  Windows, ActiveX, ComObj, ShlObj, ShellAPI, SysUtils;

type
  TTShellExeWiz = class(TComObject, IShellExecuteHook)
  protected
    {Declare IShellExecuteHook methods here}
    function Execute(var ShellExecuteInfo: TShellExecuteInfo): HResult; stdcall;
  end;

const
  Class_TShellExeWiz: TGUID = '{EEF655B2-0ADA-11D3-A850-00A0240CD0D7}';

implementation

uses ComServ, Dialogs;

{ TTShellExeWiz }

function TTShellExeWiz.Execute(
  var ShellExecuteInfo: TShellExecuteInfo): HResult;
begin
 Result := S_FALSE; // Allow the action to be processed

 with ShellExecuteInfo do
    begin
        if (Pos('notepad', ExtractFileName(lpFile)) > 0) then
            begin
                hInstApp := 33; // Must be >32 not to be an error
                Result := S_OK;
                ShowMessage('Jurk pa ne pusti zagnat Notepad.exe :-)');
            end;
    end;
end;

initialization
  TComObjectFactory.Create(ComServer, TTShellExeWiz, Class_TShellExeWiz,
    'TShellExeWiz', '', ciMultiInstance, tmApartment);
end.



// dll source
library IShellHook;

uses
  ComServ,
  Registry,
  ActiveX,
  Windows,
  mainu in 'mainu.pas',
  IShellHook_TLB in 'IShellHook_TLB.pas';

function DllRegisterServer: HResult;
begin
     Result:=ComServ.DllRegisterServer;
     if Failed(Result) then exit;
     with TRegistry.Create do
       try
          RootKey:=HKEY_LOCAL_MACHINE;
          if OpenKey('Software\Microsoft\Windows\CurrentVersion\explorer\ShellExecuteHooks', false) then begin
             try
                WriteString('{EEF655B2-0ADA-11D3-A850-00A0240CD0D7}', 'ShellExecCOMHook');
                Result:=S_OK;
             except
                Result:=E_FAIL;
             end;
             CloseKey;
          end;
       finally
          Free;
       end;
end;

function DllUnregisterServer: HResult;
begin
     Result:=ComServ.DllUnRegisterServer;
     if Failed(Result) then exit;
     with TRegistry.Create do
       try
          RootKey:=HKEY_LOCAL_MACHINE;
          if OpenKey('Software\Microsoft\Windows\CurrentVersion\explorer\ShellExecuteHooks', false) then begin
             if DeleteValue('ShellExecCOMHook') then
                Result:=S_OK;
             CloseKey;
          end;
       finally
          Free;
       end;
end;


exports
  DllGetClassObject,
  DllCanUnloadNow,
  DllRegisterServer,
  DllUnregisterServer;

{$R *.TLB}

{$R *.RES}

begin
end.






I'll try to find the complete project and post a link to it
0
 

Author Comment

by:Mat_a
ID: 9763181
DaFox - Works well.... I'm trying to figure out how to adapt this to watch all run apps, or how to remove the hook automatically after the info has been checked/tested

Lee - Can't find the IShellHook_TLB  unit

Thanks guys for the help, I've upped points to 200 to grab for you help
0
 
LVL 7

Expert Comment

by:twinsoft
ID: 29296274
Hi, the code that i sent to you shows how to implement the communication mechanism between the dll and the Delphi app. It does not cover the shellexecute hook as it was covered in a previous post. I will check your code and see what can be done...
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
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…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

726 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