ShellExecute i obsługa wywoływanego programu

0

Witam,
jestem nowy na tym forum, ale przez ostatnie kilka dni dobrze je poznałem, od razu napiszę iż w Delphi jestem początkujący i spędziłem sporo czasu na szukaniu rozwiązania tutaj oraz metodą prób i błędów, jednak potrzebuję Waszej pomocy.

Mianowicie, można z poziomu aplikacji Delphi uruchomić inną aplikację za pomocą shellExecute, pytanie brzmi jak później obsłużyć wywołaną aplikację. tzn. mieć dostęp do okna, żeby np. je przesunąć, zminimalizować itp.. Wiem, że są uchwyty okien, możliwość pobrania po klasie, nazwie itp. Ale nie potrafię tego pożenić. Proszę o pomoc na przykładzie np. wywołanie chrome z jakimś adresem, a następnie wpisanie innego adresu z poziomu delphi do wywołanego chrome lub notatnika...

z góry dzięki.

0

Uzyskać uchwyt do okna głownego na podstawie PID'u, poniższym kodem.

unit get_hwnd_from_pid;

interface

uses
  Windows;

function PidToHandle(SourcePid : DWORD) : HWND;

implementation

type
  TEnumClass = class
  private
    TempH : HWND;
    DestPid : DWORD;
    function SearchForHandle(SourcePid : DWORD) : HWND;
  end;

function EnumWindowsProc(AHandle : HWND; ALParam : LParam) : LongBool; stdcall;
var
  Pid : DWORD;
  EC : TEnumClass;
begin
  Result := True;
  EC := TEnumClass(ALParam);
  GetWindowThreadProcessId(AHandle, Pid);
  if Pid = EC.DestPid then
  begin
    if (GetWindowLong(AHandle, GWL_HWNDPARENT) = 0) and (IsWindowVisible(AHandle) or IsIconic(AHandle)) then
    begin
      EC.TempH := AHandle;
      Result := False;
    end;
  end;
end;

function TEnumClass.SearchForHandle(SourcePid : DWORD) : HWND;
begin
  DestPid := SourcePid;
  EnumWindows(@EnumWindowsProc, LParam(Self));
  Result := TempH;
end;

function PidToHandle(SourcePid : DWORD) : HWND;
var
  EC : TEnumClass;
begin
  Result := 0;
  if SourcePid > 0 then
  begin
    EC := TEnumClass.Create;
    EC.DestPid := SourcePid;
    Result := EC.SearchForHandle(SourcePid);
    EC.Free;
  end;
end;

end.

A PID masz z pola rekordu dwProcessId struktury ostatniego parametru przekazanego do funkcji CreateProcess. Jeżeli jednak potrzebujesz PID koniecznie ze ShellExecute to jest troche cięzej. Powyższy kod działa z Delphi 7, jak również poniższy. Chociaż są pewnie inne metody. Zawsze można po uruchomieniu sprawdzać enumerując uchwyty jak poniżej i na podstawie PIDu sprawdzanego jak powyżej, otrzymać też nazwę procesu.

unit mini_shellapi;

interface

uses
  WIndows;

type
  HDROP = Longint;

const
{$IFDEF MSWINDOWS}
  shell32 = 'shell32.dll';
{$ENDIF}
{$IFDEF LINUX}
  shell32 = 'libshell32.borland.so';
{$ENDIF}
type
  PSHFileInfoA = ^TSHFileInfoA;
  PSHFileInfoW = ^TSHFileInfoW;
  PSHFileInfo = PSHFileInfoA;
  _SHFILEINFOA = record
    hIcon : HICON;
    iIcon : Integer;
    dwAttributes : DWORD;
    szDisplayName : array[0..MAX_PATH - 1] of AnsiChar;
    szTypeName : array[0..79] of AnsiChar;
  end;
  _SHFILEINFOW = record
    hIcon : HICON;
    iIcon : Integer;
    dwAttributes : DWORD;
    szDisplayName : array[0..MAX_PATH - 1] of WideChar;
    szTypeName : array[0..79] of WideChar;
  end;
  _SHFILEINFO = _SHFILEINFOA;
  TSHFileInfoA = _SHFILEINFOA;
  TSHFileInfoW = _SHFILEINFOW;
  TSHFileInfo = TSHFileInfoA;
  SHFILEINFOA = _SHFILEINFOA;
  SHFILEINFOW = _SHFILEINFOW;
  SHFILEINFO = SHFILEINFOA;
  PNotifyIconDataA = ^TNotifyIconDataA;
  PNotifyIconDataW = ^TNotifyIconDataW;
  PNotifyIconData = PNotifyIconDataA;
  _NOTIFYICONDATAA = record
    cbSize : DWORD;
    Wnd : HWND;
    uID : UINT;
    uFlags : UINT;
    uCallbackMessage : UINT;
    hIcon : HICON;
    szTip : array[0..63] of AnsiChar;
  end;
  _NOTIFYICONDATAW = record
    cbSize : DWORD;
    Wnd : HWND;
    uID : UINT;
    uFlags : UINT;
    uCallbackMessage : UINT;
    hIcon : HICON;
    szTip : array[0..63] of WideChar;
  end;
  _NOTIFYICONDATA = _NOTIFYICONDATAA;
  TNotifyIconDataA = _NOTIFYICONDATAA;
  TNotifyIconDataW = _NOTIFYICONDATAW;
  TNotifyIconData = TNotifyIconDataA;
  NOTIFYICONDATAA = _NOTIFYICONDATAA;
  NOTIFYICONDATAW = _NOTIFYICONDATAW;
  NOTIFYICONDATA = NOTIFYICONDATAA;
  PShellExecuteInfoA = ^TShellExecuteInfoA;
  PShellExecuteInfoW = ^TShellExecuteInfoW;
  PShellExecuteInfo = PShellExecuteInfoA;
  _SHELLEXECUTEINFOA = record
    cbSize : DWORD;
    fMask : ULONG;
    Wnd : HWND;
    lpVerb : PAnsiChar;
    lpFile : PAnsiChar;
    lpParameters : PAnsiChar;
    lpDirectory : PAnsiChar;
    nShow : Integer;
    hInstApp : HINST;
    lpIDList : Pointer;
    lpClass : PAnsiChar;
    hkeyClass : HKEY;
    dwHotKey : DWORD;
    hIcon : THandle;
    hProcess : THandle;
  end;
  _SHELLEXECUTEINFOW = record
    cbSize : DWORD;
    fMask : ULONG;
    Wnd : HWND;
    lpVerb : PWideChar;
    lpFile : PWideChar;
    lpParameters : PWideChar;
    lpDirectory : PWideChar;
    nShow : Integer;
    hInstApp : HINST;
    lpIDList : Pointer;
    lpClass : PWideChar;
    hkeyClass : HKEY;
    dwHotKey : DWORD;
    hIcon : THandle;
    hProcess : THandle;
  end;
  _SHELLEXECUTEINFO = _SHELLEXECUTEINFOA;
  TShellExecuteInfoA = _SHELLEXECUTEINFOA;
  TShellExecuteInfoW = _SHELLEXECUTEINFOW;
  TShellExecuteInfo = TShellExecuteInfoA;
  SHELLEXECUTEINFOA = _SHELLEXECUTEINFOA;
  SHELLEXECUTEINFOW = _SHELLEXECUTEINFOW;
  SHELLEXECUTEINFO = SHELLEXECUTEINFOA;

type
  PROCESS_BASIC_INFORMATION = packed record
    Reserved1 : Pointer;
    PebBaseAddress : Pointer;
    Reserved2 : array[0..1] of Pointer;
    UniqueProcessId : DWORD;
    Reserved3 : Pointer;
  end;

const
  SEE_MASK_FLAG_NO_UI = $400;
  SEE_MASK_NOCLOSEPROCESS = $00000040;
const
  NIM_ADD = $00000000;
  NIM_MODIFY = $00000001;
  NIM_DELETE = $00000002;
  NIF_MESSAGE = $00000001;
  NIF_ICON = $00000002;
  NIF_TIP = $00000004;
  SHGFI_ICON = $000000100;
  SHGFI_DISPLAYNAME = $000000200;
  SHGFI_TYPENAME = $000000400;
  SHGFI_ATTRIBUTES = $000000800;
  SHGFI_ICONLOCATION = $000001000;
  SHGFI_EXETYPE = $000002000;
  SHGFI_SYSICONINDEX = $000004000;
  SHGFI_LINKOVERLAY = $000008000;
  SHGFI_SELECTED = $000010000;
  SHGFI_LARGEICON = $000000000;
  SHGFI_SMALLICON = $000000001;
  SHGFI_OPENICON = $000000002;
  SHGFI_SHELLICONSIZE = $000000004;
  SHGFI_PIDL = $000000008;
  SHGFI_USEFILEATTRIBUTES = $000000010;

function ShellExecAndGetPid(CommandToExec, Params : string; CmdShow : LongWord) : Cardinal;

procedure DragFinish(Drop : HDROP); stdcall;
procedure DragAcceptFiles(Wnd : HWND; Accept : BOOL); stdcall;
function DragQueryPoint(Drop : HDROP; var Point : TPoint) : BOOL; stdcall;
function DragQueryFile(Drop : HDROP; FileIndex : UINT; FileName : PChar; cb : UINT) : UINT; stdcall;
function ShellExecute(hWnd : HWND; Operation, FileName, Parameters, Directory : PChar; ShowCmd : Integer) : HINST; stdcall;
function ShellExecuteEx(lpExecInfo : PShellExecuteInfo) : BOOL; stdcall;
function Shell_NotifyIcon(dwMessage : DWORD; lpData : PNotifyIconData) : BOOL; stdcall;
function Shell_NotifyIconA(dwMessage : DWORD; lpData : PNotifyIconDataA) : BOOL; stdcall;
function Shell_NotifyIconW(dwMessage : DWORD; lpData : PNotifyIconDataW) : BOOL; stdcall;
function SHGetFileInfo(pszPath : PAnsiChar; dwFileAttributes : DWORD;
  var psfi : TSHFileInfo; cbFileInfo, uFlags : UINT) : DWORD; stdcall;
function SHGetFileInfoA(pszPath : PAnsiChar; dwFileAttributes : DWORD;
  var psfi : TSHFileInfoA; cbFileInfo, uFlags : UINT) : DWORD; stdcall;
function SHGetFileInfoW(pszPath : PAnsiChar; dwFileAttributes : DWORD;
  var psfi : TSHFileInfoW; cbFileInfo, uFlags : UINT) : DWORD; stdcall;

procedure DragFinish; external shell32 name 'DragFinish';
function ShellExecute; external shell32 name 'ShellExecuteA';
function DragQueryFile; external shell32 name 'DragQueryFileA';
function DragQueryPoint; external shell32 name 'DragQueryPoint';
procedure DragAcceptFiles; external shell32 name 'DragAcceptFiles';
function ShellExecuteEx; external shell32 name 'ShellExecuteExA';
function Shell_NotifyIcon; external shell32 name 'Shell_NotifyIconA';
function Shell_NotifyIconA; external shell32 name 'Shell_NotifyIconA';
function Shell_NotifyIconW; external shell32 name 'Shell_NotifyIconW';
function SHGetFileInfo; external shell32 name 'SHGetFileInfoA';
function SHGetFileInfoA; external shell32 name 'SHGetFileInfoA';
function SHGetFileInfoW; external shell32 name 'SHGetFileInfoW';
function GetProcessId(Process : THandle) : DWORD; stdcall; external kernel32 name 'GetProcessId';

implementation

function NtQueryInformationProcess(hProcess : DWORD; InfoClass : Integer; ProcessInfo : Pointer; ProcessInfoLen : Integer; ReturnLen : Pointer) : Integer; stdcall; external 'ntdll.dll';

function ShellExecAndGetPid(CommandToExec, Params : string; CmdShow : LongWord) : Cardinal;
var
  SHI : TShellExecuteInfo;
  PBI : PROCESS_BASIC_INFORMATION;
begin
  FillChar(SHI, SizeOf(SHI), 0);
  SHI.cbSize := SizeOf(SHI);
  SHI.fMask := SEE_MASK_FLAG_NO_UI or SEE_MASK_NOCLOSEPROCESS;
  SHI.lpVerb := 'open';
  SHI.lpFile := PChar(CommandToExec);
  SHI.lpParameters := PChar(Params);
  SHI.nShow := CmdShow;
  ShellExecuteEx(@SHI);
  if GetLastError = ERROR_FILE_NOT_FOUND then
  begin
    Result := 0;
  end
  else
  begin
    NtQueryInformationProcess(SHI.hProcess, 0, @PBI, SizeOf(PBI), nil);
    Result := PBI.UniqueProcessId;
  end;
end;

end.

Pełne ściezki na podstawie PIDu można ustalić na przykład tak:

function ProcessFullPath(PID : DWORD) : string;
var
  AHandle : THandle;
begin
  Result := '';
  AHandle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
  if AHandle <> 0 then
  try
    SetLength(Result, MAX_PATH);
    if GetModuleFileNameEx(AHandle, 0, PChar(Result), MAX_PATH) > 0 then
      SetLength(Result, StrLen(PChar(Result)))
    else
      Result := '';
  finally
    CloseHandle(AHandle);
  end;
end;

function ProcessFullPath64Bit(PID : DWORD) : string;
const
  PROCESS_QUERY_LIMITED_INFORMATION = $1000;
var
  Len : DWord;
  AHandle, DllHandle : THandle;
  QueryFullProcessImageNameA : function(HProcess : THandle; dwFlags : DWord; lpExeName : PAnsiChar; lpdwSize : PDWord) : Bool; stdcall;
begin
  Result := '';
  DllHandle := LoadLibrary('kernel32.dll');
  if DllHandle > 0 then
  begin
    QueryFullProcessImageNameA := GetProcAddress(DllHandle, 'QueryFullProcessImageNameA');
    if Assigned(QueryFullProcessImageNameA) then
    begin
      AHandle := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, PID);
      if AHandle <> 0 then
      begin
        Len := MAX_PATH;
        SetLength(Result, Len - 1);
        QueryFullProcessImageNameA(AHandle, 0, PAnsiChar(Result), @len);
        SetLength(Result, Len);
        CloseHandle(AHandle);
      end;
    end;
    FreeLibrary(DllHandle);
  end;
end;

Ktoś może jeszcze Tobie tutaj lepiej doradzi. Sorry za rozpisanie się, ale chciałem jakoś podpowiedzieć rozwiązania jakie znam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1