下面给出获取所有托盘图标的hint,但是要怎么样才可以通过这个获取到对应的进程PID呢,高手请帮忙 ,小弟感激不尽!
function TrayHWnd: HWND;
var
  h,hTmp: HWND;
begin
  h := FindWindow('Shell_TrayWnd', nil);
  h := FindWindowEx(h, 0, 'TrayNotifyWnd', nil);
  hTmp := FindWindowEx(h, 0, 'SysPager', nil);
  if hTmp <> 0 then h := hTmp;
  hTmp := FindWindowEx(h, 0, 'ToolbarWindow32', nil);
  if hTmp <> 0 then h := hTmp;
  Result := h;
end;
{提取列表}
procedure TForm1.Button1Click(Sender: TObject);
var
  h: HWND;
  count,size,num: Cardinal;
  pid, ph: Cardinal;
  p: Pointer;
  icoBtn: TTBButton;
  buf: array[0..255] of WideChar;
  i: Integer;
  item: TListItem;
begin
  h := TrayHWnd;
  count := SendMessage(h, TB_BUTTONCOUNT, 0, 0);
  size := SizeOf(TTBButton);  GetWindowThreadProcessId(h, pid);
  ph := OpenProcess(PROCESS_VM_READ, False, pid);  for i := 0 to count - 1 do
  begin
    SendMessage(h, TB_GETBUTTON, i, DWORD(p));
    ReadProcessMemory(ph, p, @icoBtn, size, num);
    ReadProcessMemory(ph, Pointer(icoBtn.iString), @buf, Length(buf)*SizeOf(buf[0]), num);
    item := ListView1.Items.Add;
    item.Caption := buf;
  end;
  CloseHandle(ph);  Button2.Enabled := True;
  Button3.Enabled := True;
end;

解决方案 »

  1.   

    托盘区域这个TTBButton结构的dwData实际上是指向用于接收对应图标的通知消息的窗口句柄(即NOTIFYICONDATA结构的hWnd)的指针,根据此句柄就可以得到PID了!
    还有个小问题,就是应当事先分配内存p。以下红色部分是新增加的内容。
    procedure TForm1.Button1Click(Sender: TObject);
    var
      h: HWND;
      count,size,num: Cardinal;
      pid, ph: Cardinal;
      p: Pointer;
      icoBtn: TTBButton;
      buf: array[0..255] of WideChar;
      i: Integer;
      item: TListItem;
      dwData: DWORD;
    begin
      h := TrayHWnd;
      count := SendMessage(h, TB_BUTTONCOUNT, 0, 0);
      size := SizeOf(TTBButton);  GetWindowThreadProcessId(h, pid);
      ph := OpenProcess(PROCESS_VM_READ {or PROCESS_VM_WRITE} or PROCESS_VM_OPERATION, False, pid);
      p := VirtualAllocEx(ph, nil, size, MEM_COMMIT, PAGE_READWRITE);  for i := 0 to count - 1 do
      begin
        SendMessage(h, TB_GETBUTTON, i, DWORD(p));
        ReadProcessMemory(ph, p, @icoBtn, size, num);
        ReadProcessMemory(ph, Pointer(icoBtn.iString), @buf, Length(buf)*SizeOf(buf[0]), num);
        ReadProcessMemory(ph, Pointer(icoBtn.dwData), @dwData, SizeOf(dwData), num);
        GetWindowThreadProcessId(dwData, pid);

        item := ListView1.Items.Add;
        item.Caption := buf;
        item.SubItems.Add(IntToStr(pid))
      end;
      VirtualFreeEx(ph, nil, 0, MEM_RELEASE);
      CloseHandle(ph);  Button2.Enabled := True;
      Button3.Enabled := True;
    end;
      

  2.   

    只要有句柄就可以获取进程唯一的PID了。但反过来不行,因为一个PID可能对应多个窗口,多个句柄。