Чи можна по ID просесса дізнатися хендл вікна цього просесса?
Власне ІМХО може хто знає які - то апішние функції
зараннее вдячний
можна по Хандлі вікна дізнатися чи належить він процесса
The GetWindowThreadProcessId function retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window.
тобто можна все вікна пребрать.
Може інакше можна, я не знаю.
> Чи можна по ID просесса дізнатися хендл вікна цього просесса?
Як сказано в [1], можна перебрати всі вікна процесу. Але для того, щоб виділити з них потрібне Ви повинні знати про це вікно ще щось, крім того, що воно прінажлежіт данномк процесу.
Величезне спасибі за напрямок але все ж
DWORD GetWindowThreadProcessId (
# XA0; # XA0; HWND hWnd, // handle of window
# XA0; # XA0; LPDWORD lpdwProcessId # XA0; // address of variable for process identifier
# XA0; );
що опередавать в hWnd якщо у мене ніякого вікна немає віддаю 0 нуль і повертає :(
Ну напрагісь, постав питання нормально :)) З знаком питання, з комами і ін.
Я не знущаюся, я питання не зрозумів. Чесно. )
Функція GetWindowThreadProcessId вимагає handle вікна.
Що туди передавати. якщо я не знаю handl десятків вікон мені їх потрібно отримати.
Для тесту передаю туди 0 на виході отримую 0.
Що робити ?
# XA0; Заздалегідь дякую!
1. Ти знаєш id процесу.
2. Для того, щоб знайти всі вікна, що належать даному процесу, потрібно перебрати всі вікна в системі. Тобто отримати послідовно handle всіх вікон.
3. Отримавши handle чергового вікна ти використовуючи зазначену мною функцію перевіряєш чи належить вікно процесу (зауваж, що потрібно передавати покажчик на id процесу, а не брати результат функції - це стандратною помилка).
Тепер про те, як перебрати вікна. Відповідь - не знаю, тому що ніколи не робив цього. Але впевнений, що якщо почати копати, починаючи з функції win api enumwindows, то обов'язково доб'ешься успіху.
Тепер зрозумів. Велике спасибі за наводку
h: = FindWindowEx (0, 0, nil, nil);
while (h <> 0) do
# XA0; begin
# XA0; # XA0; # XA0; GetWindowThreadProcessId (h, @pid);
# XA0; # XA0; # XA0; if (pid = pi.dwProcessId) then
# XA0; # XA0; # XA0; # XA0;
# XA0; # XA0; # XA0; h: = FindWindowEx (0, h, nil, nil); // шукаємо наступне вікно
# XA0; end;
IMHO краще знайти всі потоки процесу і шукати вікно в потоках за допомогою EnumThreadWindows. Тим більше, що не завжди у процесу більше одного потоку і не завжди у вторинних потоках є вікна - завдання може спростити.
procedure SearchHandle (ProcessId: DWORD; CallbackFunction: TFNWndEnumProc;
# XA0; # XA0; UnicID: LPARAM);
var
# XA0; HSnapShot: THandle;
# XA0; te: TThreadEntry32;
begin
# XA0; // нам потрібен знімок потоків
# XA0; HSnapShot: = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
# XA0; try
# XA0; # XA0; // перед використанням TThreadEntry32 потрібно заповнити поле dwSize
# XA0; # XA0; te.dwSize: = sizeof (TThreadEntry32);
# XA0; # XA0; // якщо перший запис про потоках отримана - продовжуємо
# XA0; # XA0; if Thread32First (HSnapShot, te) then
# XA0; # XA0; # XA0; repeat
# XA0; # XA0; # XA0; # XA0; // якщо цей потік відноситься до цікавого для нас процесу, то
# XA0; # XA0; # XA0; # XA0; // перераховуємо всі вікна, створені цим потоком
# XA0; # XA0; # XA0; # XA0; if te.th32OwnerProcessID = ProcessId then
# XA0; # XA0; # XA0; # XA0; # XA0; EnumThreadWindows (te.th32ThreadID, CallbackFunction, UnicID);
// отримуємо запис про наступне потоці, якщо не отримуємо - виходимо з циклу
# XA0; # XA0; # XA0; until (not Thread32Next (HSnapShot, te));
# XA0; finally
# XA0; # XA0; closehandle (HSnapShot); // закриваємо описатель знімка
# XA0; end;
end;
function EnumWnd (Handle: hwnd; UnicID: LPARAM): boolean; stdcall;
begin
# XA0; Result: = True;
# XA0; PostMessage (Handle, WM_CLOSE, 0, 0);
end;
procedure TForm1.Button1Click (Sender: TObject);
begin
# XA0; SearchHandle (GetCurrentProcessId, @EnumWnd, 0);
end;
SearchHandle шукає всі вікна заданого процесу. При знаходженні чергового вікна викликається функція CallbackFunction, якої в даному випадку є # XA0; EnumWnd. Вона посилає WM_CLOSE всіх вікон.
Так як викликається:
SearchHandle (GetCurrentProcessId, @EnumWnd, 0);
то код призводить до отриманих повідомлень WM_CLOSE всіх вікон даного процесу.
> Function EnumWnd (Handle: hwnd; UnicID: LPARAM): boolean;
> Stdcall;
# XA0; BOOL CALLBACK EnumThreadWndProc
# XA0; Хоча, в даному випадку це, можливо, не є принциповим,
# XA0; але, взагалі-то, треба акуратніше з Хідер.
--
З повагою, LVT.
PS # XA0; До речі, Toolhelp32 відсутня в NT4.
а що не так? Я не зрозумів.
> А що не так? Я не зрозумів.
Я б написав замість
> Function EnumWnd (Handle: hwnd; UnicID: LPARAM): boolean;
> Stdcall;
function EnumWnd (Handle: hwnd; UnicID: LPARAM): BOOL; stdcall;
Ах да, для мого прикладу [10] потрібно підключити юніт TLHelp32
не знаю. І взагалі сумніваюся, що в WinApi є поняття "головне вікно".
Краще поясни завдання - навіщо тобі головне вікно? Мабуть, ти щось не так розумієш.
Це само собою. Але, цим ти не відкрутишся;)
Формально, NT4 ще має право на життя, а там такого
поняття, як ToolHelp functions, немає.
Тобто включаєш ремарку "виключаючи NT4".
Незнаю чому але під DELPHI 7 TollHelp32 не працює. а ось на 5 Delphi працює. і навіть невідомо чому
І замість абстрактного "не працює" чому б не сказати де саме затикаючи?
P.S. Так як у мене рівень телепатії вже другого рівня, спробую сказати - ти точно в function EnumWnd поставив директиву stdcall;
Я звичайно извеняюсь але причому тут EnumWnd.
begin
# XA0; H: = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
# XA0; Memo1.Clear;
# XA0; If Process32First (H, P) then
# XA0; # XA0; Memo1.Lines.Add (P.szExeFile)
# XA0; until Process32Next (H, P) = False;
Цей код на D5 працює т.е показує все процеси, а на D7 не працює тобто не вказує жодного запису (WIN XP)
до речі Директива stdcall варто але вона використовується пожже, але все одно все працює (Під D5)
Ну і який сенс в мовчанку грати? Чому інформацію треба витягати, як ніби це мені потрібно. )
ЩО повертає CreateToolhelp32Snapshot? Якщо помилковий Handle - що повертає GetLastError?
begin
H: = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
Memo1.Clear;
If Process32First (H, P) then
# XA0; Memo1.Lines.Add (P.szExeFile)
until Process32Next (H, P) = False;
Нда, я плакаль. Пропоную знайти самому помилку.
P.S. А також непогано було б дізнатися - звідки ти це власне взяв, якщо в [10] я привів робочий код? З мого FAQ "а чи що?
Сорі, це я вже лажанулся. Ти просто переробив приклад для пошуку процесів. Ок, тоді залишаються питання:
ЩО повертає CreateToolhelp32Snapshot? Якщо помилковий Handle - що повертає GetLastError?
Якщо під "головним вікном" розуміти вікно для якого створюється кнопка на панелі завдань, то можна перевірити (з пом GetWindowLong) extended style на наявність ознаки кнопки на панелі завдань (WS_EX_APPWINDOW).
У вікон, що відображаються на Taskbar не обов'язково є стиль # XA0; WS_EX_APPWINDOW. Точніше, більшість відображаються на таскбару вікон цього стилю не має :)
имхо, перше вікно, створене додатком і є "головне", тобто відображається на панелі задач
А як тоді визначити відображається вікно на taskbar?
WS_EX_APPWINDOW
Forces a top-level window onto the taskbar when the window is visible.
> А як тоді визначити відображається вікно на taskbar?
(Тільки зробив апгрейд, файли чортзна-де, перепрошую, що доводиться посилання на сайт давати)
Мій склероз. Я це дивився кілька днів тому.
До речі, Ваш критерій теж неточний :-)
Перевірку з EnumFunctions_60
if (WindowOwner = 0) AND
# XA0; # XA0; ((ExStyle AND WS_EX_TOOLWINDOW) = 0) AND
# XA0; # XA0; ((WinStyle AND WS_VISIBLE) <> 0) then
не проходить таке вікно
# XA0; CreateWindowEx (WS_EX_APPWINDOW or WS_EX_TOOLWINDOW,
# XA0; # XA0; "BUTTON", "I" "m on taskbar", WS_VISIBLE, 0, 0, 0, 0, HWND_DESKTOP, 0, 0, 0);
Дякуємо. На жаль, я практично не обновляю сайт.
Перевірка, очевидно повинна виглядати так (треба перевірити):
if (WindowOwner = 0) and ((WinStyle and WS_VISIBLE) <> 0) and
# XA0; (((ExStyle and WS_EX_TOOLWINDOW) = 0) or ((ExStyle and WS_EX_APPWINDOW) <> 0)) then
а що ти скажеш на:
> Перевірка, очевидно повинна виглядати так (треба перевірити):
>
> If (WindowOwner = 0) and ((WinStyle and WS_VISIBLE) <> 0)
> and
> # XA0; (((ExStyle and WS_EX_TOOLWINDOW) = 0) or ((ExStyle and
> WS_EX_APPWINDOW) <> 0)) then
Перевірка повинна виглядати так (можеш перевірити):
function IsTaskbarBtnExist (h: HWND): Boolean;
var
# XA0; exstyle: Longint;
begin
# XA0; Result: = IsWindowVisible (h);
# XA0; if Result then
# XA0; # XA0; begin
# XA0; # XA0; # XA0; exstyle: = GetWindowLong (h, GWL_EXSTYLE);
# XA0; # XA0; # XA0; Result: = exstyle and WS_EX_APPWINDOW <> 0;
# XA0; # XA0; # XA0; if not Result and
# XA0; # XA0; # XA0; # XA0; (Exstyle and WS_EX_TOOLWINDOW = 0) then
# XA0; # XA0; # XA0; # XA0; Result: = GetWindowLong (h, GWL_HWNDPARENT) = 0;
# XA0; # XA0; end;
end;
У відсутності визначення "головне вікно" будь-яке висловлювання
може бути представлено як справжнє.
--
З повагою, LVT.
PS Собс-но, простіше руководстваться метою: "що потрібно від
цього вікна ".
Те що має значення не порядок, а стилі і владалец.
У VCL додатку зазвичай жодна форма не видно на TaskBar, для цього ісспользуется вікно Application.Handle.
type
# XA0; TForm1 = class (TForm)
# XA0; private
# XA0; # XA0;
# XA0; protected
# XA0; # XA0; procedure CreateParams (var Params: TCreateParams); override;
# XA0; public
# XA0; # XA0;
# XA0; end;
var
# XA0; Form1: TForm1;
procedure TForm1.CreateParams (var Params: TCreateParams);
begin
# XA0; inherited;
# XA0; // кожна з ніжеследуючіх рядків призводить до появи форми на taskbar
# XA0; Params.WndParent: = HWND_DESKTOP;
# XA0; Params.ExStyle: = Params.ExStyle or WS_EX_APPWINDOW;
end;
Трохи поексперементувати прийшов до висновку, що перевірка повинна виглядати так:
if (WindowOwner = 0) and ((WinStyle and WS_VISIBLE) <> 0) and ((WinStyle and WS_CHILD) = 0) and
# XA0; (((ExStyle and WS_EX_TOOLWINDOW) = 0) or ((ExStyle and WS_EX_APPWINDOW) <> 0)) then
You have to do some test on each of the windows returned by EnumWindows () to
decide wheter to show it or not. The test were described by Jeffrey Richter in
the Nov "97 issue of MSJ. Quoting:
"The rules the taskbar uses to decide whether a button should be shown
for a window are really quite simple, but are not well documented.
When you create a window, the taskbar examines the window "s extended
style to see if either the WS_EX_APPWINDOW (defined as 0x00040000) or
WS_EX_TOOLWINDOW (defined as 0x00000080) style is turned on. If
WS_EX_APPWINDOW is turned on, the taskbar shows a button for the
window, and if WS_EX_ TOOLWINDOW is turned on, the taskbar does not
show a button for the window. You should never create a window that
has both of these extended styles.
You can create a window that doesn "t have either of these styles. If a
window has neither style, the taskbar decides to create a button if
the window is unowned and does not create a button if the window is
owned.
One final note: before making any of the above tests, the taskbar
first checks to see if a window has the standard WS_VISIBLE window
style turned on. If this style bit is off, the window is hidden; the
taskbar never shows a button for a hidden window. Only if the
WS_VISIBLE style bit is on will the taskbar check the WS_EX_APPWINDOW,
WS_ EX_TOOLWINDOW, and window ownership information. "
Which, BTW, # XA0; David Lowndes has posted in this group several times in the past
Неточність в тому, що якщо вікно WS_CHILD, то ніякі # XA0; WS_EX_APPWINDOW не допоможуть - можете перевірити.
PS: цікавий спір ні про що.
>> имхо, перше вікно, створене додатком і є
> "Головне",
>> тобто відображається на панелі задач
> Неточність в тому, що якщо вікно WS_CHILD, то ніякі # XA0; WS_EX_APPWINDOW
> Не допоможуть - можете перевірити.
А причому тут WS_CHILD?
Йшлося про EnumWindows top-level windows.
> PS: цікавий спір ні про що.
Це називається обговоренням, IMHO.