Solved

Substituting Window Procedure in another process

Posted on 2003-10-30
6
206 Views
Last Modified: 2010-04-05
Hello,

I am trying to substitute a Window Procedure in another process.
I've come across Madshi collection, thus I was thinking about using
DLL injection in order to solve my problem.

But there's a thing: how can I say which handle the DLL should refer to
after a call to CreateProcessEx?

I mean, how am I supposed to communicate with the DLL in the
other process?

Which other paths may be advisable in order to get a decent result?

TIA,

Andrew

P.S. I tried using hooks, but am having all sorts of troubles, starting from the
fact I have no clue about how to share the right window handle. Any clues on how
I could achieve this?
0
Comment
Question by:DeerBear
[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
  • 4
  • 2
6 Comments
 
LVL 5

Author Comment

by:DeerBear
ID: 9649515
I've been trying all sorts of tricks in order to make this thing work.
I guess the problem relies in my lack of understanding about how
Window maps DLLs in processes, so really a deep understanding of
this topic may lead to a quick and easy solution.

Andrew
0
 
LVL 1

Accepted Solution

by:
fanar earned 150 total points
ID: 9655222
Hey check this out this is a hook program that subclasses msn and then adds a menu to it. It incluedes event handling also

You should find everything u need in here

http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20429026.html#7621675

Hope this helps ,
Anar
0
 
LVL 5

Author Comment

by:DeerBear
ID: 9685709
Hi again,

This is the DLL I have now:

library EventReg_Hks;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
  Hook_Mgt in 'Hook_Mgt.pas',
  HookRoutines in 'HookRoutines.pas',
  Windows,
  Messages,
  SysUtils;

{$R *.RES}

type

  PShared=^TShared;
  TShared = record
    WindowHandle: integer;
    PID: Cardinal;
    bSubClassDone: boolean;
    AttachCount:Integer;
  end;

var
  MemFile: THandle;
  Shared: PShared;
  OldWndProc: pointer;

const HookMemFileName='MyMemoryMappedFile.Andrea';

function NewWndProc(HWindow: HWnd; Message, WParam: Longint;
                    LParam: Longint): Longint;
begin
  if Message = WM_COMMAND then
  begin
    if HiWord(WParam) = 0 then
    begin
      if LoWord( WParam ) = 2 then
        Result := CallWindowProc(OldWndProc,
                           HWindow,
                           Message,
                           WParam,
                           LParam)
      else
        Result := 0;
      Exit;
    end;
  end;
  result := CallWindowProc(OldWndProc,
                           HWindow,
                           Message,
                           WParam,
                           LParam);
end;

procedure DoSubClassWindow;
begin
  if Not Shared^.bSubClassDone then begin
    // subclasso la finestra...
    Shared^.bSubClassDone := True;
    OldWndProc := Pointer(GetWindowLong(Shared^.WindowHandle, GWL_WNDPROC));
    MessageBox( Shared^.WindowHandle,PCHar( 'Risultato: '+GetLastErrorString( ) ),'WndProc',MB_OK );
    SetWindowLong(Shared^.WindowHandle, GWL_WNDPROC, Longint(@NewWndProc));
  end
  else // ho già subclassato questa finestra !!
end;

procedure DoSubClassBack;
begin
  if Shared^.bSubClassDone then
    // de-subclasso la finestra...
    SetWindowLong(Shared^.WindowHandle, GWL_WNDPROC, Longint(OldWndProc));
end;

procedure Intro; stdcall;
begin
  MemFile := OpenFileMapping(FILE_MAP_WRITE, False, HookMemFileName);
  if MemFile=0 then
    MemFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,
                                 SizeOf(TShared), HookMemFileName);
  Shared := MapViewOfFile(MemFile, FILE_MAP_WRITE, 0, 0, 0);
  if MemFile=0 then
    FillChar(Shared^, SizeOf(TShared), 0);

  Inc(Shared^.AttachCount);

  if GetCurrentProcessId = Shared^.PID then
    DoSubClassWindow;
end;

procedure Extro; stdcall;
var
  bFinished:Boolean;
begin
  Dec(Shared^.AttachCount);
  bFinished := (Shared^.AttachCount=0);

  if (GetCurrentProcessId = Shared^.PID) and Shared^.bSubClassDone then
    DoSubClassBack;

  if bFinished then
  begin
    RemoveHook;
    UnmapViewOfFile(Shared);
    CloseHandle(MemFile);
  end;
end;

procedure DLLEntryPoint(reason:integer);
begin
  case reason of
    0: {DLL_PROCESS_DETACH} Extro;
    1: {DLL_PROCESS_ATTACH} Intro;
  end;
end;

procedure SetPID(APID: Cardinal); stdcall;
begin
  Shared^.PID := APID;
end;


procedure SetWindowHandle(AHandle: Integer); stdcall;
begin
  Shared^.WindowHandle := AHandle;
  Shared^.bSubClassDone := False;
end;

exports
  InstallHook index 1,
  RemoveHook index 2,
  SetWindowHandle index 3,
  SetPID index 4;

begin
  Intro;
  DLLProc := @DLLEntryPoint;
end.

Now the used units:

unit Hook_Mgt;

interface

uses SysUtils,Windows;

Procedure InstallHook; stdcall;
procedure RemoveHook; stdcall;

implementation

uses HookRoutines;

var TheHook : Integer;

Procedure InstallHook; stdcall;
begin
  theHook := SetWindowsHookEx(WH_GETMESSAGE, @MyHookProc, hInstance, 0);
end;

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

procedure UninstallHooks;
begin
end;

procedure SetUpCallBack( CB : TFarProc );
begin
  CallBack := CB;
end;

end.

unit HookRoutines;

interface

uses sysUtils, Windows, Messages;

var CallBack : TFNHookProc;

function MyHookProc(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
procedure SetWndProcHandle( Handle : HWND );stdcall;
function GetLastErrorString( ErrorCode: DWord ) : PChar;

implementation

var Window : Hwnd;
    LastProc : Pointer;

procedure SetWndProcHandle( Handle : HWND );
begin
  Window := Handle;
end;

Function GetLastErrorString(ErrorCode: dWord): PChar;
var Buffer: PChar;
begin
  GetMem( Result,200 );
  FillChar( Result^,SizeOf( Result^ ),0 );
  GetMem(Buffer,200);
  if FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                   Pointer(FORMAT_MESSAGE_FROM_HMODULE),
                   ErrorCode,
                   0,
                   Buffer,
                   200,
                   nil) <> 0 then
  begin
    StrCopy( Result, Buffer );
  end;
  FreeMem(Buffer);
end;

var Count : Integer;

function MyHookProc(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT stdcall;
begin
  Result := CallNextHookEx( WH_CBT,code,wparam,lparam );
end;

initialization

end.

The calling code is as follows:

procedure TRecordItem.Launch;
var BlCreateProcess : Boolean;
    SI : TStartupInfo;
    PI : TProcessInformation;
    WT : TWaitThread;
    LP : PChar;
    EnvBlock : Pointer;
    BlockSize : Integer;
    EnvVars : TStringList;
begin
  FillChar(SI,SizeOf(TStartupInfo),#0);
  SI.cb:=SizeOf(TStartupInfo);
  GetMem( LP,Length( LaunchPath ) );
  LP := StrPCopy( LP,LaunchPath );
  BlCreateProcess := CreateProcess(nil, LP, nil, nil, True, 0, nil, nil, si, pi);
  FreeMem( LP );
  if BlCreateProcess then
  begin
    FProcessId := PI.dwProcessId;
    FProcessHandle := PI.hProcess;
    MainFrm.ProcessId := FProcessId;
    Sleep(100);
    EnumWindows( @EnumProc,0 );
    MainFrm.AppBox.Caption := GetWindowText( MainFrm.WindowHandle );
    WT := TWaitThread.Create( True );
    WT.ProcessHandle := FProcessHandle;
    WT.Resume;
//    SetupCallBack( @JournalRecordProc );
    SetPID(PI.dwProcessId);
    SetWindowHandle(MainFrm.WindowHandle);
    InstallHook;
    PostMessage(MainFrm.WindowHandle, WM_USER, 0, 0); // forza l'hook
  end
  else begin
         RaiseLastWin32Error;
       end;
end;

I increased the points, hoping I'll get some thorough responses.

TIA,

Andrew
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 5

Author Comment

by:DeerBear
ID: 9686396
Hey,

I'm now convinced that Windows is picking on me!

I have compiled this code in the DLL:

procedure DoSubClassWindow;
begin
  if Not Shared^.bSubClassDone then
  begin
    // subclasso la finestra...
    Shared^.bSubClassDone := True;
    OldWndProc := Pointer(GetWindowLong(Shared^.WindowHandle, GWL_WNDPROC));
    MessageBox( Shared^.WindowHandle,PCHar( 'Risultato: '+GetLastErrorString( GetLastError ) ),'WndProc',MB_OK );
    SetWindowLong(Shared^.WindowHandle, GWL_WNDPROC, Longint(@NewWndProc));
  end
  else // ho già subclassato questa finestra !!
end;

GetLastErrorString retrieves the last error issued by win32 and the surprise is... well,
the message is: "Invalid Window Handle"... but SURPRISE! That handle is just the very same
handle used to display the message... and I'm sure DoSubClass is called in the right process!

I'm feeling kinda disappointed... :-(

Any ideas?

TIA,

Andrew
0
 
LVL 1

Expert Comment

by:fanar
ID: 9752038
Hey Andrew try puting the whole source inside the ProcFunction for the Hook .

This is what i mean
first to to subclass a window u have to inject ur dll into its process.
Ez way to do that is to use  SetWindowsHookEx and then inside this hook proc u can use the SetWindowLong to subclass.

I think this should work
Anar
0
 
LVL 5

Author Comment

by:DeerBear
ID: 9837466
Hi Fanar,

I decided to close the question and assign you the points!

Thank you for your interest!

Andrew
0

Featured Post

[Live Webinar] The Cloud Skills Gap

As Cloud technologies come of age, business leaders grapple with the impact it has on their team's skills and the gap associated with the use of a cloud platform.

Join experts from 451 Research and Concerto Cloud Services on July 27th where we will examine fact and fiction.

Question has a verified solution.

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

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
Suggested Courses
Course of the Month6 days, 11 hours left to enroll

636 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