Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > handle of the application в handle of the window


Автор: Fedia 5.9.2006, 02:48
Приветствую всех !
Задачка такая: запускаю приложение через ShellExecute и как результат функции ShellExecute получаю его указатель. Например:
Код

var
  hApp: Cardinal;
//....
hApp:=ShellExecute(0, 'open', 'C:\text.exe', nil, nil, SW_SHOWNORMAL)

Необходимо по указателю hApp получить хендл активного окна запущенного приложения в том виде, в котором его возвращает функция FindWindow. Например:
Код

var
  AHWND: HWND;
//....
AHWND:=FindWindow(nil, 'Тест'); //'Тест' - заголовок нужного мне окна приложения

Т.е. мне необходимо из hApp получить AHWND. Возможно ли это реализовать ?

Автор: bazzzman 5.9.2006, 03:10
Не совсем понял вопрос...
Если надо найти дочернее окно какого-то конкретного окна, то:
1. GetWindow
2. EnumChildWindows
3. FindWindowEx

Автор: Fedia 5.9.2006, 04:18
Цитата(bazzzman @  5.9.2006,  03:10 Найти цитируемый пост)
Если надо найти дочернее окно какого-то конкретного окна, то:

Мне нужно найти хендл активного окна приложения, зная хендл самого приложения. Хендл приложения получаю при его запуске посредством ShellExecute.

Автор: dumb 5.9.2006, 04:32
CreateProcess + EnumThreadWindows( pi.dwThreadId, ...

Автор: bazzzman 5.9.2006, 04:42
Цитата(dumb @ 5.9.2006,  04:32)
CreateProcess + EnumThreadWindows( pi.dwThreadId, ...

Это не то... При чем тут CreateProcess, если "нужно найти хендл активного окна приложения, зная хендл самого приложения"?

Вот как это делаю я:
Код

function GetFocusWindow(hWnd:THandle=0) : THandle;
var FgThreadID: Integer;
begin
 if hWnd=0 then hWnd:=GetForegroundWindow;

 FgThreadID := GetWindowThreadProcessID(hWnd, nil);
 if AttachThreadInput(GetCurrentThreadID, FgThreadID, True) then
  begin
    Result := GetFocus;
    AttachThreadInput(GetCurrentThreadID, FgThreadID, False);
  end else Result := GetFocus;
end;


По-хорошему надо сделать более серьезную проверку ошибок...  smile 

Автор: Fedia 5.9.2006, 05:33
Цитата(bazzzman @  5.9.2006,  04:42 Найти цитируемый пост)
Вот как это делаю я:

Не работает. Проверяю так:
Код

var
  hAp: Cardinal;
  AHWND, AHWND_test: HWND;
begin
  hAp:=ShellExecute(0, 'open', 'C:\test.exe', nil, nil, SW_SHOWNORMAL);
  AHWND:=FindWindow(nil, 'Тест');
  AHWND_test:=GetFocusWindow(hAp);
  if AHWND = AHWND_test then
  ShowMessage('1');
end;


bazzzman, кстати сейчас проверил, твоя функция возвращает хендл окна, запустившего приложение.

Автор: bazzzman 5.9.2006, 06:12
Значит это окно имеет фокус ввода. Что не так?

Надо что-то другое? Тогда сформулируй нормально вопрос. 

hAp:=ShellExecute(0, 'open', 'C:\test.exe', nil, nil, SW_SHOWNORMAL); - возвращает не handle окна:
Цитата

Returns a value greater than 32 if successful, or an error value that is less than or equal to 32 otherwise. The following table lists the error values. The return value is cast as an HINSTANCE for backward compatibility with 16-bit Windows applications. It is not a true HINSTANCE, however. The only thing that can be done with the returned HINSTANCE is to cast it to an int and compare it with the value 32 or one of the error codes below.


Значит GetWindowThreadProcessID(hWnd, nil); мы не можем сделать. Нежен threadId => CreateProcess как и предлагал dumb или ShellExecuteEx. И уже потом AttachThreadInput.

Думаю информации и так уже достаточно, чтобы ты самостоятельно с этим разобрался. Читай MSDN.


Автор: Fedia 5.9.2006, 06:34
Цитата(bazzzman @  5.9.2006,  06:12 Найти цитируемый пост)
Надо что-то другое? Тогда сформулируй нормально вопрос. 

Вопрос я вроде сформулировал довольно четко:
Цитата(Fedia @  5.9.2006,  04:18 Найти цитируемый пост)
Мне нужно найти хендл активного окна приложения, зная хендл самого приложения. Хендл приложения получаю при его запуске посредством ShellExecute.

Твоя функция возвращает:
Цитата(Fedia @  5.9.2006,  05:33 Найти цитируемый пост)
хендл окна, запустившего приложение.
,
а нужно: хендл активного окна запущенного через ShellExecute приложения. Разница надеюсь понятна ?

Цитата(bazzzman @  5.9.2006,  06:12 Найти цитируемый пост)
Думаю информации и так уже достаточно, чтобы ты самостоятельно с этим разобрался. Читай MSDN.

Как раз разбираюсь. За советы спасибо. Думаю перечисленных в этой ветке функций точно хватит для реализации сабжа.

Цитата(bazzzman @  5.9.2006,  06:12 Найти цитируемый пост)
Значит GetWindowThreadProcessID(hWnd, nil); мы не можем сделать.

А еще спрашиваешь, что не так ...
Значит если запускать приложение посредством ShellExecute, то по результату, возвращаемому этой функцией хендл активного окна запущенного (именно через ShellExecute) приложения не получить ?

Автор: Romikgy 5.9.2006, 10:21
Цитата(Fedia @  5.9.2006,  05:34 Найти цитируемый пост)
Значит если запускать приложение посредством ShellExecute, то по результату, возвращаемому этой функцией хендл активного окна запущенного (именно через ShellExecute) приложения не получить ?

почему? можно 

Цитата(Fedia @  5.9.2006,  01:48 Найти цитируемый пост)
var
  hApp: Cardinal;
//....
hApp:=ShellExecute(0, 'open', 'C:\text.exe', nil, nil, SW_SHOWNORMAL)

здесь надо заюзать ф-цию 
pid:=GetProcessId(hApp);
дабы поличить пид, а далее юзая
Цитата(dumb @  5.9.2006,  03:32 Найти цитируемый пост)
EnumThreadWindows( pi.dwThreadId, ...

EnumThreadWindows(pid,....

Добавлено @ 10:25 
правда
Код

GetProcessId

Retrieves the process identifier of the specified process.

DWORD WINAPI GetProcessId(
  HANDLE Process
);

Parameters

Process
    [in] A handle to the process. The handle must have the PROCESS_QUERY_INFORMATION access right. 

Return Values

If the function succeeds, the return value is the process identifier of the specified process.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Until a process terminates, its process identifier uniquely identifies it on the system. For more information about access rights, see Process Security and Access Rights.
Requirements
Client    Requires Windows Vista or Windows XP SP1.
Server    Requires Windows Server "Longhorn" or Windows Server 2003.
Header    

Declared in Winbase.h; include Windows.h.
Library    

Use Kernel32.lib.
DLL    Requires Kernel32.dll.

Автор: Fedia 5.9.2006, 23:06
Цитата(Romikgy @  5.9.2006,  10:21 Найти цитируемый пост)
pid:=GetProcessId(hApp);

Цитата(Romikgy @  5.9.2006,  10:21 Найти цитируемый пост)
Declared in Winbase.h; include Windows.h.

По этой функции ничего нет в справке Windows SDK. Модуль Winbase также отсутствует. Не могу найти модуль, который необходимо было бы подключить, для использования этой функции.
Кроме того, функция ShellExecute возвращает:
Цитата

return value is the instance handle of the application that was run, or the handle of a dynamic data exchange (DDE) server application.
, а в качестве параметра функция GetProcessId требует:
Цитата

A handle to the process
 Это разве одно и тоже ?
ЗЫ: спасибо, что отвечаешь, хочу таки добить этот вопрос, давно меня волновавший.

Автор: Romikgy 6.9.2006, 08:45
Цитата(Fedia @  5.9.2006,  22:06 Найти цитируемый пост)
Это разве одно и тоже ?

получается да , т.к. я видел что для получения своего хистенса надо юзать GetModuleHandle с параметром nil (хотя я и не разобрался конкретно что есть этот инстанс smile)
Цитата(Fedia @  5.9.2006,  22:06 Найти цитируемый пост)
По этой функции ничего нет в справке Windows SDK. Модуль Winbase также отсутствует. Не могу найти модуль, который необходимо было бы подключить, для использования этой функции.

А ключевая фраза здесь вот какая
Цитата(Romikgy @  5.9.2006,  09:21 Найти цитируемый пост)
Client    Requires Windows Vista or Windows XP SP1.

ниже ХР СП1 этой фичи нет!
(имхо если этой ф-ции нет то проще будет перечислить все процессы в системе и от них взять хендлы и сравнить с нужным)

Автор: Fedia 6.9.2006, 09:07
Цитата(Romikgy @  6.9.2006,  08:45 Найти цитируемый пост)
А ключевая фраза здесь вот какая

Я вообще не придал этой фразе значения, потому, что у меня Windows XP SP2 smile

Цитата(Romikgy @  6.9.2006,  08:45 Найти цитируемый пост)
имхо если этой ф-ции нет то проще будет перечислить все процессы в системе и от них взять хендлы и сравнить с нужным

Ок. Завтра попробую, если время на это будет.

Автор: Romikgy 6.9.2006, 09:25
Цитата(Fedia @  6.9.2006,  08:07 Найти цитируемый пост)
Я вообще не придал этой фразе значения, потому, что у меня Windows XP SP2

тогда это в кернеле32, есть такая ф-ция, можно динамически открыть ее через лоадлибрари и попросить адрес этой ф-ции

Автор: Fedia 11.9.2006, 05:55
Цитата(Romikgy @  6.9.2006,  09:25 Найти цитируемый пост)
тогда это в кернеле32, есть такая ф-ция, можно динамически открыть ее через лоадлибрари и попросить адрес этой ф-ции

Добрался я таки и до этой части. В общем ты частично прав, в библиотеке kernel32.dll есть функция GetProcessId. Правда если в качестве параметра ей передавать результат возвращаемый функцией ShellExecute, то GetProcessId возвращает 0. Следовательно, не такой параметр ей требуется.

Автор: Romikgy 11.9.2006, 08:49
Код

DWORD WINAPI GetProcessId(
  HANDLE Process
);

Код

HINSTANCE ShellExecute(

    HWND hwnd,    // handle to parent window
    LPCTSTR lpOperation,    // pointer to string that specifies operation to perform
    LPCTSTR lpFile,    // pointer to filename or folder name string
    LPCTSTR lpParameters,    // pointer to string that specifies executable-file parameters 
    LPCTSTR lpDirectory,    // pointer to string that specifies default directory
    INT nShowCmd    // whether file is shown when opened
   );

GetProcessId требует хендл процесса , а не его хистенс

Добавлено @ 08:56 
http://www.codeproject.com/win32/Remote.asp

Автор: Fedia 11.9.2006, 11:47
Цитата(Romikgy @  11.9.2006,  08:49 Найти цитируемый пост)
GetProcessId требует хендл процесса , а не его хистенс

Я же уже подводил к этому smile
Цитата(Romikgy @  6.9.2006,  08:45 Найти цитируемый пост)
Цитата(Fedia @  5.9.2006,  22:06 )    
Это разве одно и тоже ?    

получается да

Или я тебя не понял ?

Автор: Romikgy 11.9.2006, 12:59
скорее всего smile
Цитата(Romikgy @  11.9.2006,  07:49 Найти цитируемый пост)
http://www.codeproject.com/win32/Remote.asp 

смотрел?

Автор: Fedia 12.9.2006, 01:33
Цитата(Romikgy @  11.9.2006,  12:59 Найти цитируемый пост)
смотрел?

Посмотрел. Не нашел там прямого указания, как вообще можно использовать HINSTANCE от ShellExecute. Кроме того заинтересовала терминология, озвученная автором статьи. Имеем:
Цитата

- TDB (Thread Database);
- pointer to the Process Database (PDB);
- pointer to the thread object (pTDB);
- process identifier (PID);
- process handle;
- pointer to a process object (PDB);
- thread identifier (TID);

Является ли результат, возвращаемый ShellExecute чем-то из вышеперечисленного ? Мне кажется что нет.

Romikgy, в общем, хватит говорить загадками, колись, что хотел сказать smile

Автор: Romikgy 12.9.2006, 08:54
Цитата(Fedia @  12.9.2006,  00:33 Найти цитируемый пост)
хватит говорить загадками, колись, что хотел сказать

Че ?! да ни че просто помочь хотел, а там есть 3 способа получения пида чужего процесса
Код

GetProcessId

GetProcessId() returns the process identifier (PID) of the specified process. It's a convenient way of converting a process handle to the corresponding PID. The Kernel32 function GetProcessId() is only implemented on Win XP or higher. On Windows NT, the semi-documented NTDLL function NtQueryInformationProcess() can be used to emulate GetProcessId():
Collapse

DWORD WINAPI GetProcessIdNT(HANDLE hProcess)
{
    NTSTATUS                  Status;
    PROCESS_BASIC_INFORMATION pbi;
    HANDLE                    hDupHandle;
    HANDLE                    hCurrentProcess;

    hCurrentProcess = GetCurrentProcess();

    // Use DuplicateHandle() to get PROCESS_QUERY_INFORMATION access right
    if (!DuplicateHandle(hCurrentProcess,
                         hProcess,
                         hCurrentProcess,
                         &hDupHandle,
                         PROCESS_QUERY_INFORMATION,
                         FALSE,
                         0))
    {
        SetLastError(ERROR_ACCESS_DENIED);
        return 0;
    }

    Status = NtQueryInformationProcess(hDupHandle,
                                       ProcessBasicInformation,
                                       &pbi,
                                       sizeof(pbi),
                                       NULL);

    CloseHandle(hDupHandle);

    if (!NT_SUCCESS(Status))
    {
        SetLastError(RtlNtStatusToDosError(Status));
        return 0;
    }

    // Return PID
    return pbi.UniqueProcessId;
}

It's advisable to use the DuplicateHandle() function to obtain the PROCESS_QUERY_INFORMATION access right before calling NtQueryInformationProcess() (because the passed hProcess could not have this access right).

In Win9x, a PID is in reality a pointer to a process object (PDB) (actually XORed with a DWORD called "Obfuscator") [for a detailed explanation of the process object and how to obtain a pointer to it, see the GetPDB() function description below; and for an explanation of the meaning of "Obfuscator", see the GetObsfucator() function below]. Using the process handle as an index to the handle table, we retrieve a pointer to the process object. This pointer XORed with the Obfuscator provides the PID.

DWORD GetProcessId9x(HANDLE hProcess)
{
    PPDB           pPDB, pObject;
    PHANDLE_TABLE  pHandleTable;
    int            index;

    // Current PDB
    pPDB = GetPDB();

    // Handle table index
    if (OSWin95)
        index = hProcess;
    else if (OSWin98)
        index = hProcess / 4;

    // Handle table pointer
    pHandleTable = pPDB->pHandleTable;

    // Pointer to process database
    pObject = pHandleTable->array[index].pObject;

    // Return PID
    return pObject ^ dwObsfucator;
}

An alternative method that works for all Windows versions is to call GetCurrentProcessId() in the context of the specified process:

DWORD _GetProcessId(HANDLE hProcess)
{
    HANDLE  hThread;
    DWORD   Pid;

    GetCurrentProcessId = GetProcAddress(GetModuleHandle("Kernel32.dll"),
                                         "GetCurrentProcessId");

    hThread = _CreateRemoteThread(hProcess,
                                  NULL,
                                  0,
                                  (LPTHREAD_START_ROUTINE)GetCurrentProcessId,
                                  NULL,
                                  0,
                                  NULL);
    if (!hThread)
        return 0;
    else
    {
        WaitForSingleObject(hThread, INFINITE);
        // Exit code of remote thread is the PID
        GetExitCodeThread(hThread, &Pid);
        CloseHandle(hThread);
        return Pid;
   }
}

Цитата(Fedia @  12.9.2006,  00:33 Найти цитируемый пост)
Является ли результат, возвращаемый ShellExecute чем-то из вышеперечисленного ? Мне кажется что нет.

ща посмотрю

Автор: Romikgy 12.9.2006, 09:29
Цитата(Fedia @  5.9.2006,  01:48 Найти цитируемый пост)
ShellExecute

кса а вместо этого , вот это юзать не?
ShellExecuteEx
Код

WINSHELLAPI BOOL WINAPI ShellExecuteEx(

    LPSHELLEXECUTEINFO lpExecInfo    // pointer to SHELLEXECUTEINFO structure
   );    
 

Parameters

lpExecInfo

Pointer to a SHELLEXECUTEINFO structure that contains and receives information about the application to start. 

Код

typedef struct _SHELLEXECUTEINFO {   // sei  
    DWORD     cbSize; 
    ULONG     fMask; 
    HWND      hwnd; 
    LPCSTR    lpVerb; 
    LPCSTR    lpFile; 
    LPCSTR    lpParameters; 
    LPCSTR    lpDirectory; 
    int       nShow; 
    HINSTANCE hInstApp; 
 
    // Optional members 
    LPVOID lpIDList; 
    LPCSTR lpClass; 
    HKEY   hkeyClass; 
    DWORD  dwHotKey; 
    HANDLE hIcon; 
    HANDLE hProcess; 
} SHELLEXECUTEINFO, FAR *LPSHELLEXECUTEINFO;

Автор: dumb 12.9.2006, 10:43
извините, что влезаю: а чем CreateProcess то не угодил? к чему эти шаманские танцы с бубнами?.. user posted image

Автор: Fedia 12.9.2006, 11:26
Цитата(Romikgy @  12.9.2006,  08:54 Найти цитируемый пост)
Че ?! да ни че просто помочь хотел, а там есть 3 способа получения пида чужего процесса

Не просто хотел, а и помогаешь. Я думал, что у тебя уже есть решение задачи, и ты пытаешься натолкнуть меня на какую-то мысль. Так что надеюсь без обид.

Цитата(Romikgy @  12.9.2006,  09:29 Найти цитируемый пост)
кса а вместо этого , вот это юзать не?
ShellExecuteEx

Ну мне ж уже на самом деле dumb предлагал уже использовать CreateProcess. Если бы мне требовалось срочное решение проблемы, я бы этим вариантом воспользовался. А мне лишь хотелось узнать, можно ли использовать результат функции ShellExecute для поиска окон запущенного приложения.

Автор: Romikgy 12.9.2006, 12:27
Только у меня не получилось отделить хендл апликейшена smile
Код

function EnumWindowsProc(h: HWND; lp: LPARAM): BOOL; stdcall;
var sx,str: string;

pid,pidreq: DWORD;
begin
  SetLength(sx,300);
    begin
    GetWindowThreadProcessId(h,pid);
    GetWindowText(h,PChar(sx),255);
    if (pid=DWORD(lp)) then
    if  IsWindowEnabled(h) then
      Form1.ListBox1.Items.Add(IntToHex(h,8)+' '+inttostr(pid)+' '+strpas(PChar(sx)));
  end;
  Result:=True;
end;

procedure GetHWND_from_Histance(Hist: HMODULE);
var c1:Cardinal;
pe:TProcessEntry32;
histan: HMODULE;
s1:string;
x:integer;
 begin
 X:=0;
 c1:=CreateToolHelp32Snapshot(TH32CS_SnapProcess,0);
 if c1=INVALID_HANDLE_VALUE then
                begin
                 //Form1.Statusbar1.SimpleText:=('Èíôîðìàöèÿ î ïðîöåññàõ çàêðûòà.');
                exit;
                end;
try
pe.dwSize:=sizeof(pe);
if Process32First(c1,pe) then
repeat
inc(x);
s1:=ExtractFileName(pe.szExeFile);
histan:=GetModuleHandle(PChar(s1));
if  histan= Hist then
begin
 EnumWindows(@ EnumWindowsProc,pe.th32ProcessID);
end;
//ProcessId[x]:=pe.th32ProcessID;
until not Process32Next(c1,pe);
finally CloseHandle(c1); 
end;

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Listbox1.Clear;
 GetHWND_from_Histance(
 GetModuleHandle(nil));
end;

Автор: Fedia 13.9.2006, 00:57
Цитата(Romikgy @  12.9.2006,  12:27 Найти цитируемый пост)
Только у меня не получилось отделить хендл апликейшена

Да вообще, то, что называется 
Цитата

instance handle of the application
 в спавке по ShellExecute в SDK или 
Цитата

HINSTANCE for backward compatibility with 16-bit Windows applications
 в MSDN похоже довольно бесполезная штука, созданная для совместимости с 16-bit Windows. И использовать ее скорее всего не получиться.

Romikgy, Спасибо за помощь в рассмотрении этого вопроса  smile 

Автор: Romikgy 13.9.2006, 08:56
Fedia, Имхо я привел код который ищет то что те нужно по хистенсу, или нет?
А 
Цитата(Fedia @  12.9.2006,  23:57 Найти цитируемый пост)
хендл апликейшена

я имел ввиду, не хендл процесса апликейшена , а хендл окна апликейшена!
(я проверял на приложении написаном на дельфи!)
Ведь в этом приложении имеется окно апликухи и главная форма(окно) т.е. 2 окна и как определить какое окно относится к апликухе , а какое к форме , я пока не в курсе, но если знаешь название окна то можно по нему отсеят, тогда вопросов не будет!

Добавлено @ 08:57 
Цитата(Fedia @  12.9.2006,  23:57 Найти цитируемый пост)
Romikgy, Спасибо за помощь в рассмотрении этого вопроса

Пазям.
PS только я так и не понял помогло те это или нет?

Автор: Fedia 13.9.2006, 09:58
Цитата(Romikgy @  13.9.2006,  08:56 Найти цитируемый пост)
PS только я так и не понял помогло те это или нет?

Нет, просто эта ветка начинает напоминать сломанный телефон. Не исключаю, что я не могу точно сформулировать свой вопрос, возможно ты не можешь меня понять, возможно я не могу понять твои ответы (я ведь только принялся за изучение API). ХЗ в общем.
Цитата

HINSTANCE ShellExecute(          HWND hwnd,
    LPCTSTR lpOperation,
    LPCTSTR lpFile,
    LPCTSTR lpParameters,
    LPCTSTR lpDirectory,
    INT nShowCmd
);

HMODULE GetModuleHandle( 
LPCTSTR lpModuleName
);

Цитата(Romikgy @  13.9.2006,  08:56 Найти цитируемый пост)
я имел ввиду, не хендл процесса апликейшена , а хендл окна апликейшена!

Попробуй в качестве параметра функции GetHWND_from_Histance передать HINSTANCE от ShellExecute, а не HMODULE от GetModuleHandle. Хоть эти два типа и объявлены в Delphi как Саrdinal, но похоже разнятся по смыслу. Может тогда будет понятно, что я пытался реализовать. Ведь именно от HINSTANCE, возвращаемого ShellExecute я пытался получить перечень окон. И неоднократно об этом писал. 
Но все равно, благодаря твоим примерам и ссылкам на статьи я много чего полезного для себя подчеркнул. За это и +.

Автор: Romikgy 13.9.2006, 11:38
Цитата(Fedia @  13.9.2006,  08:58 Найти цитируемый пост)
Попробуй в качестве параметра функции GetHWND_from_Histance передать HINSTANCE от ShellExecute, а не HMODULE от GetModuleHandle. 

попробую когда домой дойду
а ф-ция ShellExecute у мя где то был исходник , так он юзает GetModuleHandle , найду выложу

Автор: Fedia 13.9.2006, 22:21
Цитата(Romikgy @  13.9.2006,  11:38 Найти цитируемый пост)
попробую когда домой дойду

Попробуй конечно.

Цитата(Romikgy @  13.9.2006,  11:38 Найти цитируемый пост)
ShellExecute у мя где то был исходник , так он юзает GetModuleHandle

Результирующие значения этих функций находятся в разном числовом диапазоне. Если HINSTANCE от ShellExecute как правило не больше 1000, то HMODULE от GetModuleHandle переваливает за миллион. А исходник посмотреть интересно было бы.

Автор: Romikgy 13.9.2006, 23:29
Код

HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation,LPCSTR lpFile,
                               LPCSTR lpParameters,LPCSTR lpDirectory, INT iShowCmd)
{
    SHELLEXECUTEINFOA sei;

    TRACE("%p,%s,%s,%s,%s,%d\n",
          hWnd, debugstr_a(lpOperation), debugstr_a(lpFile),
          debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd);

    sei.cbSize = sizeof(sei);
    sei.fMask = 0;
    sei.hwnd = hWnd;
    sei.lpVerb = lpOperation;
    sei.lpFile = lpFile;
    sei.lpParameters = lpParameters;
    sei.lpDirectory = lpDirectory;
    sei.nShow = iShowCmd;
    sei.lpIDList = 0;
    sei.lpClass = 0;
    sei.hkeyClass = 0;
    sei.dwHotKey = 0;
    sei.hProcess = 0;

    ShellExecuteExA (&sei);
    return sei.hInstApp;
}

Код

BOOL WINAPI ShellExecuteExA (LPSHELLEXECUTEINFOA sei)
{
    SHELLEXECUTEINFOW seiW;
    BOOL ret;
    WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL, *wClass = NULL;

    TRACE("%p\n", sei);

    memcpy(&seiW, sei, sizeof(SHELLEXECUTEINFOW));

    if (sei->lpVerb)
    seiW.lpVerb = __SHCloneStrAtoW(&wVerb, sei->lpVerb);

    if (sei->lpFile)
        seiW.lpFile = __SHCloneStrAtoW(&wFile, sei->lpFile);

    if (sei->lpParameters)
        seiW.lpParameters = __SHCloneStrAtoW(&wParameters, sei->lpParameters);

    if (sei->lpDirectory)
        seiW.lpDirectory = __SHCloneStrAtoW(&wDirectory, sei->lpDirectory);

    if ((sei->fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME && sei->lpClass)
        seiW.lpClass = __SHCloneStrAtoW(&wClass, sei->lpClass);
    else
        seiW.lpClass = NULL;

    ret = SHELL_execute( &seiW, SHELL_ExecuteW );

    sei->hInstApp = seiW.hInstApp;

    if (sei->fMask & SEE_MASK_NOCLOSEPROCESS)
        sei->hProcess = seiW.hProcess;

    if (wVerb) SHFree(wVerb);
    if (wFile) SHFree(wFile);
    if (wParameters) SHFree(wParameters);
    if (wDirectory) SHFree(wDirectory);
    if (wClass) SHFree(wClass);

    return ret;
}

Код

static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
                LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out)
{
    STARTUPINFOW  startup;
    PROCESS_INFORMATION info;
    UINT_PTR retval = 31;
    UINT gcdret = 0;
    WCHAR curdir[MAX_PATH];

    TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory));
    /* ShellExecute specifies the command from psei->lpDirectory
     * if present. Not from the current dir as CreateProcess does */
    if( psei->lpDirectory && psei->lpDirectory[0] )
        if( ( gcdret = GetCurrentDirectoryW( MAX_PATH, curdir)))
            if( !SetCurrentDirectoryW( psei->lpDirectory))
                ERR("cannot set directory %s\n", debugstr_w(psei->lpDirectory));
    ZeroMemory(&startup,sizeof(STARTUPINFOW));
    startup.cb = sizeof(STARTUPINFOW);
    startup.dwFlags = STARTF_USESHOWWINDOW;
    startup.wShowWindow = psei->nShow;
    if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT,
                       env, *psei->lpDirectory? psei->lpDirectory: NULL, &startup, &info))
    {
        /* Give 30 seconds to the app to come up, if desired. Probably only needed
           when starting app immediately before making a DDE connection. */
        if (shWait)
            if (WaitForInputIdle( info.hProcess, 30000 ) == WAIT_FAILED)
                WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
        retval = 33;
        if (psei->fMask & SEE_MASK_NOCLOSEPROCESS)
            psei_out->hProcess = info.hProcess;
        else
            CloseHandle( info.hProcess );
        CloseHandle( info.hThread );
    }
    else if ((retval = GetLastError()) >= 32)
    {
        TRACE("CreateProcess returned error %d\n", retval);
        retval = ERROR_BAD_FORMAT;
    }

    TRACE("returning %u\n", retval);

    psei_out->hInstApp = (HINSTANCE)retval;
    if( gcdret )
        if( !SetCurrentDirectoryW( curdir))
            ERR("cannot return to directory %s\n", debugstr_w(curdir));

    return retval;
}


Добавлено @ 23:31 
т.е. в конце все равно приходим к 
Код

if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT,
                       env, *psei->lpDirectory? psei->lpDirectory: NULL, &startup, &info))

Автор: Yanis 14.9.2006, 09:29
Цитата(Romikgy @  14.9.2006,  00:29 Найти цитируемый пост)
т.е. в конце все равно приходим к
Цитата(Romikgy @  14.9.2006,  00:29 Найти цитируемый пост)
CreateProcess


Кто бы сомневался smile

P. S. А вопрос то решён или вы за так ликбез устроили? smile 

Автор: Romikgy 14.9.2006, 10:34
Цитата(Yanis @  14.9.2006,  08:29 Найти цитируемый пост)
P. S. А вопрос то решён или вы за так ликбез устроили?

А че? человек спрашает , я отвечаю smile

Автор: Yanis 14.9.2006, 10:39
Цитата(Romikgy @  14.9.2006,  11:34 Найти цитируемый пост)
А че? человек спрашает , я отвечаю

Просто интересно стало. Тема досих пор не тонет и вопрос вроде не помечен как решённый.

P. S. Вдруг я тоже хочу поучавствовать smile

Автор: Fedia 17.9.2006, 23:57
Цитата(Yanis @  14.9.2006,  09:29 Найти цитируемый пост)
P. S. А вопрос то решён или вы за так ликбез устроили?

Оказалось, что вопрос скорее всего не имеет решения smile. Обходные пути есть (CreateProcess, ShellExecuteEx), а напрямую, после ShellExecute, по результатам этой функции получить перечень хэндлов окон запущенного приложения ни как. Таки помечу тему как решенную, дабы не вводить в заблуждение массы  smile

Автор: Romikgy 18.9.2006, 00:08
Еще одно предложение, напоследок, правда оно не будет иметь отношения к 
Цитата(Fedia @  17.9.2006,  22:57 Найти цитируемый пост)
ShellExecute

им только запускаешь файл,
а потом делаешь снимок всех процессов, и отбираешь те нужный по имени ехе файла, после этого перечисляешь все окна данного процесса и находишь нужно те окно ,и в конце получается и волки  сыты и овцы целы, т.е. юзаешь shellexecute и получаешь хендл окна  smile 

Автор: Fedia 18.9.2006, 00:17
Romikgy, это решение уже есть в моей копилке. Обсуждалось http://forum.vingrad.ru/index.php?showtopic=110766.  smile 

Автор: Romikgy 18.9.2006, 00:31
Цитата(Fedia @  17.9.2006,  23:17 Найти цитируемый пост)
это решение уже есть в моей копилке.

ну как знаешь  smile 

Автор: Yanis 18.9.2006, 10:56
Цитата(Fedia @  18.9.2006,  00:57 Найти цитируемый пост)
Обходные пути есть (CreateProcess, ShellExecuteEx), а напрямую, после ShellExecute, по результатам этой функции получить перечень хэндлов окон запущенного приложения ни как.

Так вот, что требуется то smile Я вот попробовал тут набросать немного кода.
Код
{ стили overlapped окон }
const
  aTrueWndStyles: array[1..6] of DWORD = (WS_OVERLAPPED, WS_POPUP, WS_MINIMIZE,
                                          WS_THICKFRAME, WS_CAPTION, WS_SYSMENU);

function EnumThreadWndProc(hwnd: DWORD; lParam: Integer): Boolean; stdcall;

{ ... }

function GetWindowText(hWnd: HWND): string;
begin
  SetLength(Result, MAX_PATH);
  Windows.GetWindowText(hWnd, Pchar(Result), MAX_PATH);
  Result := StrPas(Pchar(Result));
end;

function EnumThreadWndProc(hwnd: DWORD; lParam: Integer): Boolean; stdcall;
var
  dwWndStyle: DWORD;
  i: Integer;
begin
  Result := True;

  dwWndStyle := GetWindowLong(hwnd, GWL_STYLE);

  { теоретически, если в стиле окна есть хотя бы один из перечисленных флагов, то
    это overlapped окно }

//  if (((dwWndStyle and WS_OVERLAPPED) = WS_OVERLAPPED) or
//    ((dwWndStyle and WS_POPUP) = WS_POPUP) or
//    ((dwWndStyle and WS_MINIMIZE) = WS_MINIMIZE) or
//    ((dwWndStyle and WS_THICKFRAME) = WS_THICKFRAME) or
//    ((dwWndStyle and WS_CAPTION) = WS_CAPTION) or
//    ((dwWndStyle and WS_SYSMENU) = WS_SYSMENU)) and
//    ((dwWndStyle and WS_VISIBLE) = WS_VISIBLE) then

  for i := Low(aTrueWndStyles) to High(aTrueWndStyles) do
    if ((dwWndStyle and aTrueWndStyles[i]) = aTrueWndStyles[i]) and
       ((dwWndStyle and WS_VISIBLE) = WS_VISIBLE) then
        begin
          Form1.ListBox1.Items.Add(GetWindowText(hwnd) + ' - ' + IntToHex(hwnd, 8));
          Break;
        end;
end;

var
  hWnd: DWORD;
  pi: TProcessInformation;
  si: TStartupInfo;
begin
  ZeroMemory(@si, SizeOf(si));
  ZeroMemory(@pi, SizeOf(pi));

  CreateProcess(nil, 'notepad.exe', nil, nil, False, NORMAL_PRIORITY_CLASS, nil,
    nil, si, pi);

  WaitForInputIdle(pi.hProcess, INFINITE);
  Application.MessageBox(PChar('Приступаем к перечислению окон.'+#13#10+
                               'Для продолжения нажмите OK'), nil, MB_ICONWARNING or MB_SYSTEMMODAL);

  EnumThreadWindows(pi.dwThreadId, @EnumThreadWndProc, 0);

  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);
end;


При запуске будет выдано окошко с сообщением, что сейчас будут перечислены окна запущенного процесса notepad.exe. Для большей наглядности можно в запустившемся окне Блокнота сначала вызвать окно замены (Ctrl+H) и плюс к этому вызвать пункт меню Открыть. В этом случае будут перечислены 3 дочерних окна (а точнее их текст, полученый через GetWindowText) и их описатели. У меня это выглядит так:
Цитата
Открыть - 00D10DB4
Замена - 00470A1A
Безымянный - Блокнот - 00740AA2

При проверке учитывается тот факт, что окно что бы быть окном должно иметь хотя бы один флаг среди флагов перечисленных в aTrueWndStyles и иметь флаг WS_VISIBLE. 
Код не универсальный и он умеет определять окна только одного потока, ID которого возвращается в pi.dwThreadId. Конечно для универсальности нужно определять окна всех потоков. Для этого придётся немного усложнить код и получить ID всех потоков и уже для каждого вызвать EnumThreadWindows. Получить список всех потоков процесса можно через функцию CreateToolhelp32Snapshot с флагом TH32CS_SNAPTHREAD и далее перечислить их из получившегося снимка при помощи Thread32First & Thread32Next.

P. S. Извиняюсь, если боян smile
P. S. S. Коментарии не писал. Код довольно прозрачный smile

Автор: Fedia 26.9.2006, 00:37
Цитата(Yanis @  14.9.2006,  10:39 Найти цитируемый пост)
Тема досих пор не тонет

Вот и потонула ветка smile. Извиняюсь, что долго не отвечал. Занят был сильно, а этот вопрос у меня совсем не приоритетный. Хороший пример, хоть и не совсем в тему.
А через ShellExecuteEx тоже самое реализовать сможешь ? Я пробовал так:
Код

function EnumWindowsProc(h: HWND; lp: LPARAM): BOOL; stdcall;
var
  sx, str: string;
  pid,pidreq: DWORD;
begin
  SetLength(sx,300);

  GetWindowThreadProcessId(h, pid);
  GetWindowText(h,PChar(sx),255);
  if (pid=DWORD(lp)) then
  if  IsWindowEnabled(h) then
    Form1.ListBox1.Items.Add(IntToHex(h,8)+' '+inttostr(pid)+' '+strpas(PChar(sx)));

  Result:=True;
end;

procedure GetHWND_from_Histance(PId: Cardinal);
var
  c1:Cardinal;
  pe:TProcessEntry32;
  histan: HMODULE;
  s1:string;
  x:integer;
begin
  c1:=CreateToolHelp32Snapshot(TH32CS_SNAPALL, 0);
  if c1=INVALID_HANDLE_VALUE then
  exit;

  try
    pe.dwSize:=sizeof(pe);
    if Process32First(c1, pe) then
    repeat
      if  pe.th32ParentProcessID = PId then
      begin
        EnumWindows(@EnumWindowsProc,pe.th32ProcessID);
        Break;
      end;
    until not Process32Next(c1,pe);
  finally
    CloseHandle(c1);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
type
  TGetPId = function (Process: HWND): DWORD;
var
  SEInfo: TSHELLEXECUTEINFO;
  Ar: TIntegerDynArray;
  TopW: HWND;
  pi: TProcessInformation;
  si: TStartupInfo;
begin
  FillChar(SEInfo, SizeOf(SEInfo), 0);
  SEInfo.cbSize:=SizeOf(SEInfo);
  SEInfo.Wnd:=Application.Handle;
  SEInfo.fMask:=SEE_MASK_NOCLOSEPROCESS;
  SEInfo.lpFile:='C:\test.exe';
  SEInfo.nShow:=SW_SHOWNORMAL;
  ShellExecuteEx(@SEInfo);

  GetHWND_from_Histance(SEInfo.hProcess);
end;
, но это пример не работает из-за того, что th32ParentProcessID и hProcess не одно и тоже. А как получить из hProcess - th32ProcessID не знаю.

Автор: dumb 26.9.2006, 07:37
Fedia, для нормальной работы с хэндлами таки стоит использовать CreateProcess. почему? - вот цитата из MSDN по SHELLEXECUTEINFO.hProcess:
Цитата(MSDN)

hProcess
Handle to the newly started application. This member is set on return and is always NULL unless fMask is set to SEE_MASK_NOCLOSEPROCESS. Even if fMask is set to SEE_MASK_NOCLOSEPROCESS, hProcess will be NULL if no process was launched. For example, if a document to be launched is a URL and an instance of Microsoft Internet Explorer is already running, it will display the document. No new process is launched, and hProcess will be NULL.

Note ShellExecuteEx does not always return an hProcess, even if a process is launched as the result of the call. For example, an hProcess does not return when you use SEE_MASK_INVOKEIDLIST to invoke IContextMenu.

Автор: Yanis 26.9.2006, 09:32
Цитата(Fedia @  26.9.2006,  01:37 Найти цитируемый пост)
Хороший пример, хоть и не совсем в тему.

Почему? Потому что пример с CreateProcess, а не с ShellExecute(Ex)?
Ну да ладно...

Вобщем тебе выбирать каким способом пользоваться. Проблема
Цитата(Fedia @  26.9.2006,  01:37 Найти цитируемый пост)
А как получить из hProcess - th32ProcessID не знаю.

решается с помощью функции GetProcessId. Присутствует она начиная с XP, поэтому даже в 2000 работать уже не будет.

Автор: Fedia 26.9.2006, 11:40
dumb, 
Ага, читал я справку MSDN по SHELLEXECUTEINFO. И судя по ней в моих задачах hProcess будет не NULL. А в большей эффективности использования CreateProcess я убедился после того, как стало понятно, что ShellExecute(Ex) все равно вызывают CreateProcess. Поэтому полностью с тобой согласен  smile 

Yanis, 
Цитата(Yanis @  26.9.2006,  09:32 Найти цитируемый пост)
Почему? Потому что пример с CreateProcess, а не с ShellExecute(Ex)?
Ну да ладно...

Нет, вопрос в этой ветке изначально звучал даже уже, и касался он только ShellExecute. Единственно, что мне необходимо было узнать в этой ветке, это то, что результат ShellExecute для решения задачи использовать не получиться. А за твой пример отдельное спасибо.

Цитата(Yanis @  26.9.2006,  09:32 Найти цитируемый пост)
решается с помощью функции GetProcessId.

Ах да, мне же эту функцию Romikgy уже приводил, сорри.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)