External process injection lazarus / 8-Other ---------------------------------------------------------------------- cyber_python · 2007-11-21 14:26 I am trying to figure out a way to get the titles of the application- buttons in the Windows taskbar (WinXP) and the handle to their corresponding window. It seems that I have to get a pointer to a structure with some button- related info but that structure must be allocated in the explorer's memory - so I tried to use OpenProcess, VirtualAllocEx() and VirtualFreeEx() API functions to achieve this. I found out that they are not declared so I declared them myself (in the parameters list thre was a type called SIZE_T which I changed to DWORD) and the program compiles but when it runs I get an "external SIGSEV" error. Could anyone please tell me what I've done wrong? The code below uses a form with a TButton , a TEdit and one TListBox and parts of it where found around the net. Code: [Select] unit unit1; {$mode objfpc}{$H+} interface uses   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,   Buttons, windows; type   { TForm1 }   TForm1 = class(TForm)     Button1: TButton;     Button2: TButton;     Edit1: TEdit;     ListBox1: TListBox;     procedure Button1Click(Sender: TObject);   private     { private declarations }   public     { public declarations }   end;     function VirtualFreeEx(hProcess:HANDLE; lpAddress:LPVOID; dwSize:DWORD ; dwFreeType : DWORD):WINBOOL; external 'kernel32' name 'VirtualFreeEx'; function VirtualAllocEx(hProcess:HANDLE; lpAddress:LPVOID; dwSize:DWORD ; flAllocationType : DWORD;  flProtect : DWORD):POINTER; external 'kernel32' name 'VirtualAllocEx'; var   Form1: TForm1; implementation { TForm1 } procedure saveCapture(wnd : HWND; filename : string); var DCDesk: HDC; bmp: Graphics.TBitmap; w,h : integer; r : TRect; begin   bmp := Graphics.TBitmap.Create;   bmp.Height := 1050;   bmp.Width := 1680;   DCDesk := GetWindowDC(wnd);   GetWindowRect(wnd,r) ;   w := r.Right - r.Left;   h := r.Bottom - r.Top;   try     bmp.Width := w;     bmp.Height := h;     BitBlt(bmp.Canvas.Handle,            0,            0,            bmp.Width,            bmp.Height,            DCDesk,            0,            0,            SRCCOPY) ;     bmp.SaveToFile(filename);    finally     ReleaseDC(wnd, DCDesk);     bmp.Free;    end; end; function getTaskbarHWND: HWND; var   ShellTrayWnd: HWnd;   ReBarWindow32: HWnd;   MSTaskSwWClass: HWnd; begin   Result := 0;   ShellTrayWnd := FindWindow('Shell_TrayWnd', nil);   if ShellTrayWnd = 0 then   begin        ShowMessage('No taskbar found');        Exit;   end;   saveCapture(ShellTrayWnd , 'D:\tmp\taskbar.bmp');         ReBarWindow32 := FindWindowEx(ShellTrayWnd, 0, 'ReBarWindow32', nil);   if ReBarWindow32 = 0 then   begin        ShowMessage('Error with taskbar');        Exit;   end;   saveCapture(ReBarWindow32 , 'D:\tmp\rebar.bmp');       MSTaskSwWClass := FindWindowEx(ReBarWindow32, 0, 'MSTaskSwWClass', nil);   if MSTaskSwWClass = 0 then   begin        ShowMessage('Error inside taskbar');        Exit;   end;   saveCapture(MSTaskSwWClass , 'D:\tmp\runningapps.bmp');       Result := FindWindowEx(MSTaskSwWClass, 0, 'ToolbarWindow32', nil); // not for Win95 * end; function getNumberOfButtons(ToolbarWindowHandle : HWND) : integer; var  count : integer; begin  count := SendMessage( ToolbarWindowHandle, TB_BUTTONCOUNT, 0, 0 );  result:=count; end; function GetHandleFromButtonIndex(ButtonIndex: Word): HWND; const   BUFFER_SIZE = $1000; var   hwndTaskbar: HWND;   // variables that needed to open taskbar (explorer) process   taskbarProcessID: DWORD;   taskbarProcessHandle: THandle; // variable that helds pointer to a remote buffer in taskbar process   taskbarProcessBuffer: Pointer;   i: Integer;   dwBytesRead: DWORD;   lpRemoteData: Pointer;   tbButton: TTBBUTTON;   PtbButton: Pointer;   localBuffer: array[0..BUFFER_SIZE - 1] of Byte;   pLocalBuffer: ^Byte;   ipLocalBuffer: Pointer;   btnWindowHandle: HWND; begin   Result := 0;   // find Windows Taskbar   hwndTaskbar := getTaskbarHWND;   if hwndTaskbar <> 0 then   begin     // obtain taskbar process id - by window     GetWindowThreadProcessId(hwndTaskbar, @taskbarProcessID);     // open taskbar process     taskbarProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False, taskbarProcessID);     if taskbarProcessHandle <> 0 then     try       // allocate space for remote buffer in taskbar process       taskbarProcessBuffer := VirtualAllocEx(taskbarProcessHandle, nil, BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE);       if Assigned(taskbarProcessBuffer) then       begin         // declare and prepare variables that will held data         // about PRESSED button in a taskbar         PtbButton := @tbButton;         // Now, retrieve information about the PRESSED button in a taskbar / data is placed in remote buffer         SendMessage(hwndTaskbar, TB_GETBUTTON, ButtonIndex, Integer(taskbarProcessBuffer));         // And now, the remote data about PRESSED button is transferred to a local variable         dwBytesRead := 0;         ReadProcessMemory(taskbarProcessHandle, taskbarProcessBuffer, PtbButton, SizeOf(TBBUTTON), dwBytesRead);         // the window handle is in dwData field of TBBUTTON structure (the first 4 bytes)         pLocalBuffer := @localBuffer[0];         ipLocalBuffer := pLocalBuffer;         // initialize remote buffer         lpRemoteData := @tbButton.dwData;         // and read the dwData fields of a TBBUTTON from remote process         dwBytesRead := 0;         ReadProcessMemory(taskbarProcessHandle, lpRemoteData, ipLocalBuffer, SizeOf(Pointer), dwBytesRead);         // obtain window handle, copy first 4 bytes         Move(ipLocalBuffer, btnWindowHandle, 4);         Result := btnWindowHandle;         if Assigned(taskbarProcessBuffer) then           VirtualFreeEx(taskbarProcessHandle, taskbarProcessBuffer, 0, MEM_RELEASE);       end;     finally       CloseHandle(taskbarProcessHandle);     end;   end; end; procedure TForm1.Button1Click(Sender: TObject); var  count : integer;  i : integer;  h, w : HWND; begin   h:=  getTaskbarHWND;   count:=getNumberOfButtons(h);   edit1.Text:=inttostr(count);   for i:=0 to count-1 do   begin       w:= GetHandleFromButtonIndex(i);       saveCapture(w , 'D:\tmp\window__'+inttostr(i)+'.bmp');   end; end; initialization   {$I unit1.lrs} end. ---------------------------------------------------------------------- Marc · 2007-11-21 16:17 If it are real buttons, you should be able to retrieve the text by sending a WM_GETWINDOWTEXT the a control. Accessing the memory of the taskbar process (explorer.exe) it tricky since it requires you to know where exactly that data in memory is allocated. IOW, you need internal kowledge. Something which might change on the next SP. ---------------------------------------------------------------------- cyber_python · 2007-11-23 18:25 First of all, I would like to thank you Marc, for your help. I tried to use SendMessage with TB_GETBUTTONTEXT (the taskbar (only the part that hosts the buttons) is a ToolbarWindow32 class window)  but I couldn't get it to work. The following code gets the handle of the toolbar inside the Taskbar but I cannot access the buttons : Code: [Select] function getTaskbarHWND: HWND; var   ShellTrayWnd: HWnd;   ReBarWindow32: HWnd;   MSTaskSwWClass: HWnd; begin   Result := 0;   ShellTrayWnd := FindWindow('Shell_TrayWnd', nil);   if ShellTrayWnd = 0 then   begin        ShowMessage('No taskbar found');        Exit;   end;   saveCapture(ShellTrayWnd , 'D:\tmp\taskbar.bmp');         ReBarWindow32 := FindWindowEx(ShellTrayWnd, 0, 'ReBarWindow32', nil);   if ReBarWindow32 = 0 then   begin        ShowMessage('Error with taskbar');        Exit;   end;   saveCapture(ReBarWindow32 , 'D:\tmp\rebar.bmp');       MSTaskSwWClass := FindWindowEx(ReBarWindow32, 0, 'MSTaskSwWClass', nil);   if MSTaskSwWClass = 0 then   begin        ShowMessage('Error inside taskbar');        Exit;   end;   saveCapture(MSTaskSwWClass , 'D:\tmp\runningapps.bmp');       Result := FindWindowEx(MSTaskSwWClass, 0, 'ToolbarWindow32', nil); // not for Win95 * end; What I am trying to do is take pictures of all the windows that are open. I cannot use EnumWindows because it gives me all the open windows - even invisible, the taskbar, tray iocns and other things.... My idea was to get the  handle of each open windos that have a corresponding button in the task bar.  Then I would use that handle to take a screenshot of the window. I've been trying the last 3 days, searched all over the Internet but I seem unable to get anything to work....... Please help me... It must be possible someway. ---------------------------------------------------------------------- Marc · 2007-11-26 09:53 The piece of code should indeed give you the toolbar inside the taskbar. But what then ? How to know which button corresponds to what allpication ? And what about grouped taskbar buttons ? Enum windows is the way to do it. Really. Check if the window is visible, check its windows style, its state etc.. ---------------------------------------------------------------------- cyber_python · 2007-11-26 11:43 Thanks Marc! I'll try and if I get anything to work, I'll post the code here so if anyone wants to do something similar has a starting point. ---------------------------------------------------------------------- duncanparsons · 2007-11-28 12:48 You might want to look at the first item in here: http://www.ntwind.com/software/taskswitchxp/faq.html Your method of doing this is admirable, not not entirely supported by Win32 in all versions! DSP ---------------------------------------------------------------------- cyber_python · 2007-11-28 23:02 Thanks duncanparsons!!!! I followed the link above, and with alittle research about the WinAPI function printWindow I came up with the following code (whick could be very useful to others too - I think it was Windy that was looking for something like this) : Code: [Select] // //---- Don't forget to add windows in your uses clause. // // Add this line before the var section (right after your form's declaration in interfaces section) function PrintWindow(SourceWindow: hwnd; Destination: hdc; nFlags: cardinal): bool; stdcall; external 'user32.dll' name 'PrintWindow'; //Add this in your implementation : //The following procedure creates a bitmap out of the window with handle "wnd" //and saves it in a file specified by filename. procedure printMyWindow(wnd : HWND; filename : string); var   bmp : Graphics.TBitmap;   rec : TRect; begin   GetWindowRect(wnd, rec);   bmp := Graphics.TBitmap.Create;   try     bmp.Width := rec.Right - rec.Left;     bmp.Height := rec.Bottom - rec.Top;     bmp.PixelFormat := pf24bit;     PrintWindow(wnd, bmp.Canvas.Handle, 0);     bmp.SaveToFile(filename);   finally     bmp.Free;   end; end; also, thanks to Marc's hint I came up with the following to get only the windows that would be normally shown in a taskbar : Code: [Select] function EnumWindowsProc(Wnd: HWND; lParam: lParam): BOOL; stdcall; var  interesting : boolean;  fname : string; begin   Result := True;   interesting:= IsWindowVisible(Wnd);// or IsIconic(wnd);   interesting:= interesting and  ((GetWindowLong(Wnd, GWL_HWNDPARENT) = 0) or (GetWindowLong(Wnd, GWL_HWNDPARENT) = GetDesktopWindow));   interesting:= interesting and  (GetWindowLong(Wnd, GWL_EXSTYLE) and WS_EX_TOOLWINDOW = 0) ;     if(interesting) then   begin     fname:= 'D:\tmp\windows\window_'+inttostr(wnd)+'.bmp';     printMyWindow(wnd, fname);   end; end; procedure TForm1.Button1Click(Sender: TObject); begin   listbox1.Clear;   enumWIndows(@enumWindowsProc, 0); end; ---------------------------------------------------------------------- duncanparsons · 2007-11-30 13:41 glad to be of service I might even 'borrow' your code in the future! DSP ---------------------------------------------------------------------- anna · 2013-09-01 15:37 Quote from: cyber_python on November 21, 2007, 03:26:30 pmCode: [Select]... function VirtualFreeEx(hProcess:HANDLE; lpAddress:LPVOID; dwSize:DWORD ; dwFreeType : DWORD):WINBOOL; external 'kernel32' name 'VirtualFreeEx'; function VirtualAllocEx(hProcess:HANDLE; lpAddress:LPVOID; dwSize:DWORD ; flAllocationType : DWORD;  flProtect : DWORD):POINTER; external 'kernel32' name 'VirtualAllocEx'; ... ... The error is here . VirtualAllocEx must have 5 arguments , but as I see in OllyDBG Lazarus compiler makes only 3 arguments to be sent . Delete this assigning (this functions already assigned correctly in func.inc module ) Besides you  put wrong address of explorer's address space to ReadProcessMemory Besides your screencast gives black rectangles. ---------------------------------------------------------------------- Dick, from the internet · 2013-09-02 05:36 I certainly hope OP hasn't been sitting on his hands for the last six years waiting for your answer!    v/r     geno ---------------------------------------------------------------------- anna · 2013-09-02 15:22 Quote from: geno on September 02, 2013, 07:36:27 amI certainly hope OP hasn't been sitting on his hands for the last six years waiting for your answer!    v/r     geno I just hit same task. And I just wrote some notes for other people. Them may be useful. ---------------------------------------------------------------------- Dick, from the internet · 2013-09-02 19:05 QuoteI just hit same task. And I just wrote some notes for other people. Them may be useful.I kinda figured as much, I was just being facetious   v/r     geno