Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Drag&Drop von Dateien auf TrayIcon (https://www.delphipraxis.net/111663-drag-drop-von-dateien-auf-trayicon.html)

der_kumpel 7. Apr 2008 15:14


Drag&Drop von Dateien auf TrayIcon
 
Ich führe hier mal eine spezielle Frage zum CoolTrayIcon weiter:

Mein Problem ist, dass ich gerne per Drag&Drop eine Datei
(oder auch mehrere) aus dem Windows-Explorer auf mein TrayIcon
ziehen möchte, damit ich diese analysieren kann.

Auf meine Frage hat toms in diesem Tutorial für das CoolTrayIcon diesen Link gepostet.

Jetzt hab ich aber ein Problem den ganzen Spaß umzusetzen:

Die function auf der Seite, die das WindowHandle sucht,
hab ich glaub ich soweit erfolgreich in Delphi umgesetzt
(war gar nicht so schwer wie ich gedacht hatte :mrgreen: ):


Delphi-Quellcode:
function FindTrayHWND: hWnd;
var
  MyhWnd: hWnd;
begin
  MyhWnd:=FindWindow('Shell_TrayWnd', nil);
  if (MyhWnd <> 0) then
    begin
      MyhWnd:=FindWindowEx(MyhWnd, 0, 'TrayNotifyWnd', nil);
      if (MyhWnd <> 0) then
        begin
          MyhWnd:=FindWindowEx(MyhWnd, 0, 'SysPager', nil);
          if (MyhWnd <> 0) then
            begin
              MyhWnd:=FindWindowEx(MyhWnd, 0, 'ToolbarWindow32', nil);
            end;
        end;
    end;
  result:=MyhWnd;
end;
Aber wie gehts jetzt weiter?

toms 7. Apr 2008 15:27

Re: Drag&Drop von Dateien auf TrayIcon
 
Liste der Anhänge anzeigen (Anzahl: 1)
Weiter geht's so:

Zitat:

After the window is found, you need to figure out the correct icon. This is done by using the POINT send with the WM_DROPFILES and looping through all icons, which are actually buttons. This way one can figure out on which icon you dropped the files.

Using the code
The code is splitt into 2 files. One exe file that represents the tray icon app and a message hook dll. The dll installs a message hook to catch the WM_DROPFILES message and will check if we dropped anything on our tray icon. Then I send the message to the window that belongs to our tray icon app.
Als nächstes gilt es also, die C-Sourcen zu studieren.
Habe diese mal als Anhang hochgeladen, falls du kein Konto bei codeproject hast.

der_kumpel 7. Apr 2008 17:54

Re: Drag&Drop von Dateien auf TrayIcon
 
Danke für deine Mühe, aber da blick ich überhaupt nicht durch.

Ich vermute mal, dass der wichtige Teil in der Drag-Drop.cpp steht,
allerdings versteh ich da kaum was. :(

toms 8. Apr 2008 22:14

Re: Drag&Drop von Dateien auf TrayIcon
 
Zitat:

Zitat von der_kumpel
Ich vermute mal, dass der wichtige Teil in der Drag-Drop.cpp steht,
allerdings versteh ich da kaum was. :(

Genau, dort befindet sich der HOOK.
Ist ein WH_GETMESSAGE Hook.

Probiere mal einige Funktionen zu übersetzen.
Diese sollte nicht allzu schwer sein.

Code:
BOOL FileDroppedAtIcon(const HWND a_hWndOwner, const int a_iButtonID, const PPOINT pPoint)
{
    HWND hWndTray = FindTrayToolbarWindow();

    //now we have to get an ID of the parent process for system tray
    DWORD dwTrayProcessID = -1;
    GetWindowThreadProcessId(hWndTray, &dwTrayProcessID);

    //here we get a handle to tray application process
    HANDLE hTrayProc = OpenProcess(PROCESS_ALL_ACCESS, 0, dwTrayProcessID);
 
    //now we check how many buttons is there - should be more than 0
    int iButtonsCount = SendMessage(hWndTray, TB_BUTTONCOUNT, 0, 0);

    //We want to get data from another process - it's not possible
    //to just send messages like TB_GETBUTTON with a locally
    //allocated buffer for return data. Pointer to locally allocated
    //data has no usefull meaning in a context of another
    //process (since Win95) - so we need
    //to allocate some memory inside Tray process.
    //We allocate sizeof(TBBUTTON) bytes of memory - 
    //because TBBUTTON is the biggest structure we will fetch.
    //But this buffer will be also used to get smaller
    //pieces of data like RECT structures.
    LPVOID lpData = VirtualAllocEx(hTrayProc, NULL,
                    sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);

    BOOL bIconFound = FALSE;

    for(int iButton=0; iButton<iButtonsCount; iButton++)
    {
        //first let's read TBUTTON information
        //about each button in a task bar of tray

        DWORD dwBytesRead = -1;
        TBBUTTON buttonData;
        SendMessage(hWndTray, TB_GETBUTTON, iButton, (LPARAM)lpData);

        //we filled lpData with details of iButton icon of toolbar
        //- now let's copy this data from tray application
        //back to our process
        ReadProcessMemory(hTrayProc, lpData, &buttonData, sizeof(TBBUTTON), &dwBytesRead);

        //let's read extra data of each button:
        //there will be a HWND of the window that
        //created an icon and icon ID
        DWORD dwExtraData[2] = { 0,0 };
        ReadProcessMemory(hTrayProc, (LPVOID)buttonData.dwData,dwExtraData, sizeof(dwExtraData), &dwBytesRead);

        HWND hWndOfIconOwner = (HWND) dwExtraData[0];
        int iIconId        = (int) dwExtraData[1];

        if(hWndOfIconOwner != a_hWndOwner || iIconId != a_iButtonID)
        {
            continue;
        }

        //we found our icon - in WinXP it could be hidden - let's check it:
        if( buttonData.fsState & TBSTATE_HIDDEN )
        {
            break;
        }

        //now just ask a tool bar of rectangle of our icon
        RECT rcPosition = {0,0};
        SendMessage(hWndTray, TB_GETITEMRECT, iButton, (LPARAM)lpData);
       // ReadProcessMemory(hTrayProc, lpData, lprcPosition/*&rcPosition*/, sizeof(RECT), &dwBytesRead);
      ReadProcessMemory(hTrayProc, lpData, &rcPosition, sizeof(RECT), &dwBytesRead);

      MapWindowRect(hWndTray,NULL,&rcPosition);

      if (pPoint->x > rcPosition.left && pPoint->x < rcPosition.right &&
         pPoint->y > rcPosition.top && pPoint->y < rcPosition.bottom)
      {
         OutputDebugString("Stuff dropped at our icon...!!!");   

         bIconFound = TRUE;
         break;
      }

        break;
    }

    VirtualFreeEx(hTrayProc, lpData, NULL, MEM_RELEASE);
    CloseHandle(hTrayProc);

    return bIconFound;
}

der_kumpel 9. Apr 2008 16:55

Re: Drag&Drop von Dateien auf TrayIcon
 
Hui, das war vielleicht ein Akt. Und so alles verstanden hab ich auch noch nicht, manches konnte man ja auch simpel übernehmen...

Delphi-Quellcode:
function FileDroppedAtIcon(const a_hWndOwner: HWND; const a_iButtonID: integer; const PPoint: TPoint): boolean;
var
  hWndTray, hWndOfIconOwner: HWND;
  dwTrayProcessID, dwBytesRead: DWORD;
  hTrayProc: THandle;
  iButtonsCount, iButton, iIconId: integer;
  lpData: Pointer;
  buttonData: TTBBUTTON;
  bIconFound: BOOL;
  dwExtraData: array[0..1] of DWORD;
  rcPosition: TRect;
begin
  hWndTray:=FindTrayHWND; {FindTrayHWND s.o.}

  //now we have to get an ID of the parent process for system tray
  dwTrayProcessID:=DWORD(-1);
  GetWindowThreadProcessId(hWndTray, dwTrayProcessID);

  //here we get a handle to tray application process
  hTrayProc:=OpenProcess(PROCESS_ALL_ACCESS, false, dwTrayProcessID);

  //now we check how many buttons is there - should be more than 0
  iButtonsCount:=SendMessage(hWndTray, TB_BUTTONCOUNT, 0, 0);

  //We want to get data from another process - it's not possible
  //to just send messages like TB_GETBUTTON with a locally
  //allocated buffer for return data. Pointer to locally allocated
  //data has no usefull meaning in a context of another
  //process (since Win95) - so we need
  //to allocate some memory inside Tray process.
  //We allocate sizeof(TBBUTTON) bytes of memory -
  //because TBBUTTON is the biggest structure we will fetch.
  //But this buffer will be also used to get smaller
  //pieces of data like RECT structures.
  lpData:=VirtualAllocEx(hTrayProc, nil, SizeOf(TTBBUTTON), MEM_COMMIT, PAGE_READWRITE);

  bIconFound:=false;

  for iButton := 0 to iButtonsCount - 1 do
    begin
      //first let's read TBUTTON information
      //about each button in a task bar of tray
      dwBytesRead:=DWORD(-1);
      SendMessage(hWndTray, TB_GETBUTTON, iButton, LPARAM(lpData));

      //we filled lpData with details of iButton icon of toolbar
      //- now let's copy this data from tray application
      //back to our process
      ReadProcessMemory(hTrayProc, lpData, @buttonData, SizeOf(TTBBUTTON), dwBytesRead);

      //let's read extra data of each button:
      //there will be a HWND of the window that
      //created an icon and icon ID
      dwExtraData[0] := 0;
      dwExtraData[1] := 0;

      ReadProcessMemory(hTrayProc, Pointer(buttonData.dwData), @dwExtraData, SizeOf(dwExtraData), dwBytesRead);

      hWndOfIconOwner:=HWND(dwExtraData[0]);
      iIconId:=Integer(dwExtraData[1]);

      if (hWndOfIconOwner <> a_hWndOwner) or (iIconId <> a_iButtonID) then
        begin
          Continue; {sollte man hier nicht lieber den nachfolgenden Code
                      reinschreiben, anstatt eine if Abfrage später auf
                      Break zu prüfen?}
        end;

      //we found our icon - in WinXP it could be hidden - let's check it:
      if (buttonData.fsState and TBSTATE_HIDDEN) > 0 then
        begin
          Break;
        end;

      //now just ask a tool bar of rectangle of our icon
      SendMessage(hWndTray, TB_GETITEMRECT, iButton, LPARAM(lpData));
      ReadProcessMemory(hTrayProc, lpData, @rcPosition, SizeOf(TRECT), dwBytesRead);

      MapWindowPoints(hWndTray, 0, rcPosition, 2);

      if (PPoint.X > rcPosition.Left) and (PPoint.X < rcPosition.Right) and
         (PPoint.Y > rcPosition.Top) and (PPoint.Y < rcPosition.Bottom) then
        begin
          //stuff dropped at our icon
          bIconFound:=true;
          Break;
        end;
    end;

  VirtualFreeEx(hTrayProc, lpData, 0, MEM_RELEASE);
  CloseHandle(hTrayProc);

  result:=bIconFound;
end;
Vermutung: Könnte man nicht jetzt schon die
Delphi-Quellcode:
procedure WMDropFiles(var Msg: TMessage); Message WM_DropFiles;
einsetzen? Da man ja weiß, dass etwas gedroppt wurde, braucht man doch jetzt nur noch die Pfade der gedropten Datei(en). :gruebel:

Btw, ist das erste Mal, dass ich so windowsnah unterwegs bin. :!:

toms 12. Apr 2008 15:01

Re: Drag&Drop von Dateien auf TrayIcon
 
Bist du inzwischen schon weiter gekommen?

der_kumpel 16. Apr 2008 20:11

Re: Drag&Drop von Dateien auf TrayIcon
 
Nein, bisher leider nicht. :(

Könntest du mir verraten, welche Funktionen ich aus der Drag-Drop.cpp und der DDHook.cpp genau brauche?
Das mit der .dll hab ich nämlich nicht verstanden: braucht das Programm diese .dll, um den Drop zu erkennen?

Und wie ich die einzelnen Funktionen zusammensetzte hab ich auch noch nicht herausgefunden. Nach welchem Ereignis muss ich den Ausschau halten?


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:45 Uhr.

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