Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Handle einer Form aus Taskbareintrag erhalten (https://www.delphipraxis.net/90693-handle-einer-form-aus-taskbareintrag-erhalten.html)

Mazel 22. Apr 2007 10:12


Handle einer Form aus Taskbareintrag erhalten
 
Hallo,

ich suche nach einer Möglichkeit, über ein Klick mit der mittleren Maustaste auf ein Taskbareintrag einer Form, das Handle der jeweiligen Form zu ermitteln.
Ich habe folgendes ausprobiert, jedoch bekomme ich da selber nur das Handle der Taskbar und nicht der einzelnen Einträge:
Delphi-Quellcode:
GetCursorPos(Pos);
Wnd := WindowFromPoint(Pos);
Ein Klick mit der Mausstaste fange ich folgendermaßen ab:
Delphi-Quellcode:
{--[MouseHookProc]-------------------------------------------------------------}

function MouseHookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
  If nCode = HC_ACTION then
   begin
    If lParam <> 0 then with PEventMsg(lParam)^ do
     begin
      If Message = WM_MBUTTONDOWN then
       begin
        GetCursorPos(Pos);
        Wnd := WindowFromPoint(Pos);
       end;
     end;
   end;
  Result := CallNextHookEx(Main.MouseHook, nCode, wParam, lParam);
end;
Hat jemand einen Rat für mich?

Gruß
Mazel

toms 22. Apr 2007 11:16

Re: Handle einer Form aus Taskbareintrag erhalten
 
Hallo Mazel

Zitat:

Zitat von msdn2.microsoft.com
TB_HITTEST Message
Determines where a point lies in a toolbar control.

Zudem musst du mit OpenProcess / VirtualAllocEx / WriteProcessMemory arbeiten.

Habe ein Beispiel in C gefunden.

Code:
  POINT pt;
    GetCursorPos(&pt);
    if (WindowFromPoint(pt)!=hwndTW) return 0;
    ScreenToClient(hwndTW,&pt);
    HANDLE hProc=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pidTB);// pidTB is the process ID of the taskbar
    LPVOID lpPoint=VirtualAllocEx(hProc,NULL,sizeof(POINT),MEM_COMMIT,PAGE_READWRITE);
    WriteProcessMemory(hProc,lpPoint,&pt,sizeof(POINT),NULL);
    int i=(int)SendMessage(hwndTW,TB_HITTEST,0,(LPARAM)(LPPOINT)lpPoint);
    VirtualFreeEx(hProc,lpPoint,NULL,MEM_RELEASE);
    CloseHandle(hProc);

Meine Delphi Umsetzung ist wahrscheinlich noch nicht ganz richtig. Konnte sie auch nicht testen.


Delphi-Quellcode:
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;
  ReBarWindow32 := FindWindowEx(ShellTrayWnd, 0, 'ReBarWindow32', nil);
  if ReBarWindow32 = 0 then begin ShowMessage('Error with taskbar'); Exit; end;
  MSTaskSwWClass := FindWindowEx(ReBarWindow32, 0, 'MSTaskSwWClass', nil);
  if MSTaskSwWClass = 0 then begin ShowMessage('Error inside taskbar'); Exit; end;
  Result := FindWindowEx(MSTaskSwWClass, 0, 'ToolbarWindow32', nil); // not for Win95 *
 end;
end;
Delphi-Quellcode:
var
  pt: TPOINT;
  TaskbarHWND: HWND;
  hProc: THandle;
  PID: THandle;
  lpNumberOfBytesWritten: DWORD;
  i: Integer;
  lpPoint: Pointer;
begin
 Sleep(2000);
  TaskbarHWND := getTaskbarHWND;
  GetCursorPos(pt);
  if (WindowFromPoint(pt) <> TaskbarHWND) then Exit;
  Windows.ScreenToClient(TaskbarHWND, pt);

  GetWindowThreadProcessId(TaskbarHWND, @PID);
  hProc := OpenProcess(PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE, False, PID);
  lpPoint := VirtualAllocEx(hProc, nil, SizeOf(TPoint), MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);

  FillChar(pt, SizeOf(TPOINT), 0);
  lpNumberOfBytesWritten := 0;

  WriteProcessMemory(hProc, lpPoint, @pt, SizeOf(TPOINT), lpNumberOfBytesWritten);
  i := SendMessage(TaskbarHWND, TB_HITTEST, 0, lParam(lpPoint)); //????
  Caption := IntToStr(i);
  VirtualFreeEx(hProc, lpPoint, NULL, MEM_RELEASE);
  CloseHandle(hProc);
Danach muesste man den Code mit folgendem Kombinieren, um an das Window Handle zu kommen:

Code:
// find Windows Taskbar (Note: works under XP and 2k3)
HWND hwndTaskbar = FindWindow("Shell_TrayWnd", NULL);
hwndTaskbar = FindWindowEx(hwndTaskbar, NULL, "ReBarWindow32", NULL);
hwndTaskbar = FindWindowEx(hwndTaskbar, NULL, "MSTaskSwWClass", NULL);
hwndTaskbar = FindWindowEx(hwndTaskbar, NULL, "ToolbarWindow32", NULL);i - &#1101;&#1090;&#1086; &#1080;&#1085;&#1076;&#1077;&#1082;&#1089; &#1082;&#1085;&#1086;&#1087;&#1082;&#1080; &#1085;&#1072; &#1090;&#1072;&#1089;&#1082;&#1073;&#1072;&#1088;&#1077;
// variables that needed to open taskbar (explorer) process
DWORD taskbarProcessID;
const int BUFFER_SIZE = 0x1000;

// obtain taskbar process id - by window
GetWindowThreadProcessId(hwndTaskbar, &taskbarProcessID);
// open taskbar process
HANDLE taskbarProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, taskbarProcessID);

// variable that helds pointer to a remote buffer in taskbar process
DWORD_PTR taskbarProcessBuffer;

// allocate space for remote buffer in taskbar process
taskbarProcessBuffer = (DWORD_PTR)VirtualAllocEx(taskbarProcessHandle, NULL, BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE);

// declare and prepare variables that will held data
// about PRESSED button in a taskbar
TBBUTTON tbButton;
TBBUTTON* pTBButton = &tbButton;
DWORD_PTR lpTBButton = (DWORD_PTR)pTBButton;

// Now, retrieve information about the PRESSED button in a taskbar
// Note: data is placed in remote buffer
SendMessage(hwndTaskbar, TB_GETBUTTON, i, taskbarProcessBuffer);

// And now, the remote data about PRESSED button is transferred to a local variable
DWORD dwBytesRead = 0;
ReadProcessMemory(taskbarProcessHandle, (LPVOID)taskbarProcessBuffer, (LPVOID)lpTBButton, sizeof(TBBUTTON), &dwBytesRead);

// ------------------------------------------------------------------
// Where is keeped the window handle?
// It is in dwData field of TBBUTTON structure (the first 4 bytes) :))
// MSDN doesn't specify anything about this!
// ------------------------------------------------------------------

// Retrieve window handle of pressed btn
BYTE localBuffer[BUFFER_SIZE];
BYTE* pLocalBuffer = localBuffer;
DWORD_PTR ipLocalBuffer = (DWORD_PTR)pLocalBuffer;

// window handle
pLocalBuffer = localBuffer;
ipLocalBuffer = (DWORD_PTR)pLocalBuffer;

// initialize remote buffer
DWORD_PTR lpRemoteData = (DWORD_PTR)tbButton.dwData;

// and read the dwData fields of a TBBUTTON from remote process
ReadProcessMemory(taskbarProcessHandle, (LPVOID)lpRemoteData, (LPVOID)ipLocalBuffer, sizeof(DWORD_PTR), &dwBytesRead);

// obtain window handle
// copy first 4 bytes
HWND windowHandle;
memcpy(&windowHandle, (void *)ipLocalBuffer, 4);

Mazel 22. Apr 2007 12:52

Re: Handle einer Form aus Taskbareintrag erhalten
 
Hallo,

danke für die schnelle Antwort. :thumb:

Zunächst werde ich versuchen müssen, den C Code in Delphi zu übersetzten. Da ich keinerlei Kentnisse in C habe, wird das sicher lange dauern, aber ich versuche es, denn ein paar kleine Dinge sind in Dephi nicht viel anders, dennoch werde ich da Hilfe brauchen.

Was ich gleich nicht verstanden habe ist: DWORD_PTR taskbarProcessBuffer;
Was beudetet PTR? Das selbe finde sich auch in der TBBUTTON Struktur.

Gruß
Mazel

DGL-luke 22. Apr 2007 12:54

Re: Handle einer Form aus Taskbareintrag erhalten
 
Das ist ein Pointer auf ein DWORD, also sowas wie "CardinalPtr", glaub ich. Die ganze Zeile ist eine Variablendeklaration.

EDIT: Wenn Delphi keine passenden Typ dafür hat, kannst du es auch als Pointer oder gleich als Cardinal deklarieren. Jenachdem, was in C alles damit gemacht wird, ist das eien oder das andere besser.

Mazel 22. Apr 2007 13:46

Re: Handle einer Form aus Taskbareintrag erhalten
 
Danke DGL-luke, diese Bezeichnung war mir nicht bekannt.

Ich habe mal in der Suche etwas herumgesucht und dabei folgendes Thema gefunden:
Taskbar aktualisieren

Nun kann man sicher den Code so umstellen, dass zumdindest ein paar Teile genutzt werden können. Ich habe das eben probiert, aber mir ist mein Rechner abgestürzt. Daher ist auch der von mir schon teilweise angepasste Code aus dem übernommen Code weg. Jetzt brauch ich erstmal Abstand um später einen neuen Versuch zu starten.

Eventuell weis jemand von euch, wie ich den Code am besten zusammensetze.

Gruß
Mazel

toms 22. Apr 2007 17:51

Re: Handle einer Form aus Taskbareintrag erhalten
 
Vielleicht koennte jemand noch helfen, diese 3 Codefragemente nach Delphi zu uebersetzen :?:

1.
Code:
SendMessage(hwndTW,TB_HITTEST,0,(LPARAM)(LPPOINT)lpPoint);
2.
Code:
TBBUTTON tbButton;
TBBUTTON* pTBButton = &tbButton;
DWORD_PTR lpTBButton = (DWORD_PTR)pTBButton;
3.
Code:
// Retrieve window handle of pressed btn
BYTE localBuffer[BUFFER_SIZE];
BYTE* pLocalBuffer = localBuffer;
DWORD_PTR ipLocalBuffer = (DWORD_PTR)pLocalBuffer;
pLocalBuffer = localBuffer;
ipLocalBuffer = (DWORD_PTR)pLocalBuffer

DGL-luke 22. Apr 2007 18:26

Re: Handle einer Form aus Taskbareintrag erhalten
 
1.
Delphi-Quellcode:
SendMessage(hwndTW,TB_HITTEST,0,Integer(lpPoint));
2.
Delphi-Quellcode:
var
  tbButton: TBButton;
  PtbButton: Pointer;

PtbButton := @TBButton;
3.
Delphi-Quellcode:
// Retrieve window handle of pressed btn
var
  localBuffer: array[0..BUFFER_SIZE-1] of Byte;
  pLocalBuffer: ^Byte; //"BytePointer", könnte sein dass Delphi schon "PByte" definiert hat, das ist dann schöner
  ipLocalBuffer: Pointer;

pLocalBuffer := @localBuffer[0];
ipLocalBuffer := pLocalBuffer;
WObei mir die etwas sinnlos erscheinen, die Codestückchen, insbesondere wenn man was erst initialisiert und ihm dann den sleben wert nochmal zuweist.

toms 22. Apr 2007 18:30

Re: Handle einer Form aus Taskbareintrag erhalten
 
Danke erstmal. Habe das 1. Codestueck ueberarbeitet und es liefert schonmal erfolgreich den Index des Buttons unter der Maus.

Delphi-Quellcode:
var
  pt: TPOINT;
  TaskbarHWND: HWND;
  hProc: THandle;
  PID: THandle;
  NumBytes: DWORD;
  iButtonIndex : Integer;
  lpPoint: Pointer;
begin
  TaskbarHWND := getTaskbarHWND;
  GetCursorPos(pt);
  if (WindowFromPoint(pt) <> TaskbarHWND) then Exit;
  Windows.ScreenToClient(TaskbarHWND, pt);
  PID := 0;
  GetWindowThreadProcessId(TaskbarHWND, @PID);
  hProc := OpenProcess(PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE, False, PID);
  if hProc <> 0 then
  try
    lpPoint := VirtualAllocEx(hProc, nil, SizeOf(TPoint), MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
    NumBytes := 0;
    WriteProcessMemory(hProc, lpPoint, @pt, SizeOf(TPOINT), NumBytes);
    // Index ermittlen
    iButtonIndex := SendMessage(TaskbarHWND,TB_HITTEST,0,Integer(lpPoint));
    Caption := IntToStr(iButtonIndex );
    if Assigned(lpPoint) then
      VirtualFreeEx(hProc, lpPoint, 0, MEM_RELEASE);
  finally
    CloseHandle(hProc);
  end;

toms 22. Apr 2007 18:39

Re: Handle einer Form aus Taskbareintrag erhalten
 
Anbei schonmal ein Entwurf meiner Delphi Uebersetzung des 2. Codefragmentes.
Es liefert von einem gegebenem Buttonindex das Handle des zugehoerigen Fensters.


Delphi-Quellcode:
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;

Mazel 22. Apr 2007 19:00

Re: Handle einer Form aus Taskbareintrag erhalten
 
Das ist ja wirklich super :thumb:

Ich habe eben den ersten Codeabschnitt kopiert und eingefügt und das funktioniert auch ohne Probleme. Der 2. Abschnitt geht aber noch nicht ganz. Egal welchen Button ich betätige, es wird immer der selbe Wert zurückgegeben.
Ich bin sicher, das Problem wird auch noch gelöst. Jetzt werde ich aber nichts mehr machen, morgen steht Geschichte Abi-Prüfung an.

Gruß
Mazel


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:59 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz