Как получить дескриптор окна main из идентификатора процесса?
Я хочу перенести это окно на передний план.
Он отлично работает в "Process Explorer".
Как получить дескриптор окна main из идентификатора процесса?
Я хочу перенести это окно на передний план.
Он отлично работает в "Process Explorer".
Я проверил, как .NET определяет главное окно.
Мой вывод показал, что он также использует EnumWindows()
.
Этот код должен делать это аналогично .NET-пути:
struct handle_data {
unsigned long process_id;
HWND window_handle;
};
HWND find_main_window(unsigned long process_id)
{
handle_data data;
data.process_id = process_id;
data.window_handle = 0;
EnumWindows(enum_windows_callback, (LPARAM)&data);
return data.window_handle;
}
BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
handle_data& data = *(handle_data*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (data.process_id != process_id || !is_main_window(handle))
return TRUE;
data.window_handle = handle;
return FALSE;
}
BOOL is_main_window(HWND handle)
{
return GetWindow(handle, GW_OWNER) == (HWND)0 && IsWindowVisible(handle);
}
Я не считаю, что Windows (в отличие от .NET) предоставляет прямой способ получить это.
Единственный способ, которым я знаю, - перечислить все окна верхнего уровня с помощью EnumWindows()
, а затем найти, какой процесс принадлежит каждому из GetWindowThreadProcessID()
. Это звучит косвенно и неэффективно, но это не так плохо, как вы могли ожидать - в типичном случае у вас может быть дюжина окон верхнего уровня, чтобы пройти...
Там есть возможность неправильного понимания здесь. Структура WinForms в .Net автоматически определяет первое созданное окно (например, Application.Run(new SomeForm())
) как MainWindow
. Однако API win32 не распознает идею "главного окна" для каждого процесса. Цикл сообщений полностью способен обрабатывать столько "главных" окон, сколько системные и технологические ресурсы позволят вам создать. Таким образом, ваш процесс не имеет "главного окна". Лучшее, что вы можете сделать в общем случае, это использовать EnumWindows()
, чтобы активировать все не-дочерние окна в данном процессе и попытаться использовать некоторые эвристики, чтобы выяснить, какой из них вам нужен. К счастью, большинство процессов, скорее всего, будут иметь одно "основное" окно, выполняемое большую часть времени, поэтому вы должны получать хорошие результаты в большинстве случаев.
Это моё решение с использованием чистого Win32/C++, основанного на верхнем ответе. Идея состоит в том, чтобы объединить все необходимое в одну функцию без необходимости использования внешних функций или структур обратного вызова:
#include <utility>
HWND FindTopWindow(DWORD pid)
{
std::pair<HWND, DWORD> params = { 0, pid };
// Enumerate the windows using a lambda to process each window
BOOL bResult = EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL
{
auto pParams = (std::pair<HWND, DWORD>*)(lParam);
DWORD processId;
if (GetWindowThreadProcessId(hwnd, &processId) && processId == pParams->second)
{
// Stop enumerating
SetLastError(-1);
pParams->first = hwnd;
return FALSE;
}
// Continue enumerating
return TRUE;
}, (LPARAM)¶ms);
if (!bResult && GetLastError() == -1 && params.first)
{
return params.first;
}
return 0;
}
Хотя это может быть не связано с вашим вопросом, посмотрите функцию GetGUIThreadInfo.
Просто чтобы убедиться, что вы не путаете tid (идентификатор потока) и pid (идентификатор процесса):
DWORD pid;
DWORD tid = GetWindowThreadProcessId( this->m_hWnd, &pid);
В качестве расширения для решения Hiale вы можете предоставить другую или измененную версию, которая поддерживает процессы с несколькими главными окнами.
Сначала измените структуру, чтобы можно было хранить несколько дескрипторов:
struct handle_data {
unsigned long process_id;
std::vector<HWND> handles;
};
Во-вторых, измените функцию обратного вызова:
BOOL CALLBACK enum_windows_callback(HWND handle, LPARAM lParam)
{
handle_data& data = *(handle_data*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (data.process_id != process_id || !is_main_window(handle)) {
return TRUE;
}
// change these 2 lines to allow storing of handle and loop again
data.handles.push_back(handle);
return TRUE;
}
Наконец, внесите изменения в функцию main:
std::vector<HWD> find_main_window(unsigned long process_id)
{
handle_data data;
data.process_id = process_id;
EnumWindows(enum_windows_callback, (LPARAM)&data);
return data.handles;
}
Я ищу функцию в заголовке "winuser.h".
Мой код:
#include <vcl.h>
#include <windows.h>
#include <winuser.h>
#include <stdlib.h>
#include <string.h>
#include <iostream.h>'
#pragma hdrstop
#include "Unit1.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TWinyMouse *WinyMouse;
#define WM_LBUTTONDOWN 0x0201
#define WM_LBUTTONDBLCLK 0x0203
#define WM_RBUTTONDOWN 0x0204
#define MOUSEEVENTF_MOVE 0x0001
#define MOUSEEVENTF_LEFTDOWN 0x0002
#define MOUSEEVENTF_LEFTUP 0x0004
#define MOUSEEVENTF_RIGHTDOWN 0x0008
#define MOUSEEVENTF_RIGHTUP 0x0010
#define MOUSEEVENTF_MIDDLEDOWN 0x0020
#define MOUSEEVENTF_MIDDLEUP 0x0040
#define MOUSEEVENTF_XDOWN 0x0080
#define MOUSEEVENTF_XUP 0x0100
#define MOUSEEVENTF_WHEEL 0x0800
#define MOUSEEVENTF_VIRTUALDESK 0x4000
#define MOUSEEVENTF_ABSOLUTE 0x8000
int SleepTime;
int VectorX[10000];
int VectorY[10000];
int MouseFunction[10000];
int TrackBarPosition;
int IterationEnd;
int VectorIndex=0;
int RecordSwitch=0;
char Key;
POINT Coordinates;
int XCoord, YCoord;
//int X,Y;
//int Button,State;
int XPos,YPos;
//TMessage Mensaje;
HWND hWnd;
//enum TMouseButton { mbLeft, mbRight, mbMiddle };
TMouseButton Button;
TShiftState Estado;
int X,Y;
int XPointer;
int YPointer;
TMouseButton Boton;
POINT RasterCoords;
int Playing;
int TestMode;
int XDrag,YDrag;
int XDragged,YDragged;
int XStore,YStore;
int Timer1Enabled;
int FirstClickDetected;
int cx,cy;
MSG msg;
bool bRet;
int TimerEnabled=0;
TMessage WndProcMessage;
AnsiString DesktopWindowHandle;
LPTSTR StringClass;
DWORD lpdwProcessId;
__fastcall TWinyMouse::TWinyMouse(TComponent* Owner)
: TForm(Owner)
{
/*static HINSTANCE hLib;
hLib = LoadLibrary("user32.dll");
if (hLib == NULL)
{
ShowMessage("LoadLibrary Failed.\n");
}
HWND hwnd;
MSG msg;
WNDCLASSEX wcx;
//Definimos la estructura de clase de ventana (campos):
wcx.cbSize = sizeof( WNDCLASSEX ); // tamaño de la estruct.
wcx.style = CS_HREDRAW | CS_VREDRAW; // valores más usuales
wcx.lpfnWndProc = WndProc; // función de ventana
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0; // informaciones extra
wcx.hInstance = hInstance; // instancia actual
//icono, cursor, fondo e icono pequeño de la clase de ventana:
wcx.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH );
wcx.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
wcx.lpszMenuName = NULL; // nombre del menú
wcx.lpszClassName = WindowName; // nombre de la ventana
//Registramos la clase de ventana ya preparada:
if( !RegisterClassEx( &wcx ) )
return( FALSE ); // si hay error salir
//Creamos la ventana con CreateWindowEx():
hwnd = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW, // estilo extendido
WindowName, // nombre de la ventana
WindowTitle, // título de la ventana
WS_OVERLAPPEDWINDOW, // estilo de ventana
CW_USEDEFAULT, CW_USEDEFAULT, // Posición (x,y) en pantalla
400, 300, // ancho y alto de la ventana
NULL, NULL, // ventana padre e hija+menú
hInstance, // instancia actual
NULL // no hay más información
);
//Comprobamos la creación de la ventana:
if( !hwnd )
return( FALSE ); // si hay error, salir
Hacemos visible la ventana y la actualizamos:
ShowWindow( hwnd, nCmdShow );
UpdateWindow( hwnd );
*/
}
void StoreLeftClick()
{
GetCursorPos(&Coordinates);
XStore=Coordinates.x;
YStore=Coordinates.y;
VectorX[VectorIndex]=XStore;
VectorY[VectorIndex]=YStore;
MouseFunction[VectorIndex]=1;
VectorIndex++;
WinyMouse->LabelActionNumber->Caption=VectorIndex;
}
void StoreDoubleClick()
{
GetCursorPos(&Coordinates);
XStore=Coordinates.x;
YStore=Coordinates.y;
VectorX[VectorIndex]=XStore;
VectorY[VectorIndex]=YStore;
MouseFunction[VectorIndex]=2;
VectorIndex++;
WinyMouse->LabelActionNumber->Caption=VectorIndex;
}
void StoreRightClick()
{
GetCursorPos(&Coordinates);
XStore=Coordinates.x;
YStore=Coordinates.y;
VectorX[VectorIndex]=XStore;
VectorY[VectorIndex]=YStore;
MouseFunction[VectorIndex]=3;
VectorIndex++;
WinyMouse->LabelActionNumber->Caption=VectorIndex;
}
void Play(void)
{
if (RecordSwitch==0)
{
Playing=1;
for(VectorIndex=0;VectorIndex<IterationEnd;VectorIndex++)
{
switch (MouseFunction[VectorIndex])
{
case 1:
XCoord=VectorX[VectorIndex];
YCoord=VectorY[VectorIndex];
SetCursorPos(XCoord,YCoord);
mouse_event(MOUSEEVENTF_LEFTDOWN,XCoord,YCoord,0,0);
mouse_event(MOUSEEVENTF_LEFTUP,XCoord,YCoord,0,0);
break;
case 2:
XCoord=VectorX[VectorIndex];
YCoord=VectorY[VectorIndex];
SetCursorPos(XCoord,YCoord);
mouse_event(MOUSEEVENTF_LEFTDOWN,XCoord,YCoord,0,0);
mouse_event(MOUSEEVENTF_LEFTUP,XCoord,YCoord,0,0);
mouse_event(MOUSEEVENTF_LEFTDOWN,XCoord,YCoord,0,0);
mouse_event(MOUSEEVENTF_LEFTUP,XCoord,YCoord,0,0);
break;
case 3:
XCoord=VectorX[VectorIndex];
YCoord=VectorY[VectorIndex];
SetCursorPos(XCoord,YCoord);
mouse_event(MOUSEEVENTF_RIGHTDOWN,XCoord,YCoord,0,0);
mouse_event(MOUSEEVENTF_RIGHTUP,XCoord,YCoord,0,0);
break;
default:
break;
}
Sleep(SleepTime);
}
}
Playing=0;
}
void StopTimer(void)
{
TimerEnabled=0;
}
void StartTimer(void)
{
TimerEnabled=1;
}
void __fastcall TWinyMouse::ButtonRecordClick(TObject *Sender)
{
RecordSwitch=1;
WinyMouse->AlphaBlend=true;
StartTimer();
}
void __fastcall TWinyMouse::ButtonStopClick(TObject *Sender)
{
RecordSwitch=0;
IterationEnd=VectorIndex;
WinyMouse->AlphaBlend=false;
StopTimer();
}
void __fastcall TWinyMouse::ButtonPlayClick(TObject *Sender)
{
Play();
}
void __fastcall TWinyMouse::ButtonClearClick(TObject *Sender)
{
for (VectorIndex=0;VectorIndex<=IterationEnd;VectorIndex++)
{
VectorX[VectorIndex]=0;
VectorY[VectorIndex]=0;
MouseFunction[VectorIndex]=0;
}
LabelActionNumber->Caption=0;
VectorIndex=0;
}
void __fastcall TWinyMouse::TrackBarSTBAChange(TObject *Sender)
{
TrackBarPosition=(WinyMouse->TrackBarSTBA->Position);
SleepTime=5001-TrackBarPosition;
WinyMouse->LabelSTBAms->Caption=SleepTime;
}
void __fastcall TWinyMouse::TimerTimer(TObject *Sender)
{
if (TimerEnabled==1)
{
//GetClassNameA(hWnd, StringClass, 1024);
//-->Here it'd come the help I'm asking for
while( GetMessage( &msg, hWnd, 0, 0 ) )
{
//Label1->Caption=hWnd.c_str();
TranslateMessage( &msg ); // convertimos el mensaje kbd
DispatchMessage( &msg ); // lanzamos WndProc
switch(msg.message)
{
case WM_LBUTTONDOWN:
StoreLeftClick();
break;
case WM_LBUTTONDBLCLK:
StoreDoubleClick();
break;
case WM_RBUTTONDOWN:
StoreRightClick();
break;
default:
break;
}
}
}
else
{
}
}
Как называется функция, которая будет извлекать переменную HWND любого окна из любого процесса? Примеры: окно Windows, Adobe Reader, Firefox, Chrome, pdfktbuilder и т.д.
Честно говоря, я не хочу, чтобы ты был твоим врагом, так что это мой последний пост.
Я допускаю расхождения, но не хочу входить в бесконечный цикл:
Мы (и я не говорил вам) не можем объявить функцию как CALLBACK... в большинстве случаев, если вы переопределите функцию CALLBACK, мы не сможем получить какую-либо переменную ввода/вывода для этих функций.
С наилучшими пожеланиями.
В любом случае спасибо за ответ