Как найти дескриптор окна

Как получить дескриптор окна

Концепция пользовательского интерфейса в ОС Windows построена на понятии окна. Диалоги, кнопки, панели управления, списки – все это окна. Поэтому для того чтобы произвести какие-либо действия с каким либо элементом интерфейса своего или чужого приложения, нужно получить дескриптор окна.

Как получить дескриптор окна

Вам понадобится

  • – пакет Platform SDK;
  • – компилятор.

Инструкция

Получите дескриптор окна, создав его. Произведите вызовы API-функций CreateWindow или CreateWindowEx, либо вызовите соответствующие методы-обертки (на необходимых объектах) классов используемого фреймворка или библиотеки, инкапсулирующих функционал работы с окнами или элементами управления.Функции CreateWindow и CreateWindowEx непосредственно возвращают дескриптор окна при успешном его создании. При неудачном вызове они возвращают значение NULL. Код причины ошибки может быть запрошен при помощи API-функции GetLastError. Прототипы и подробное описание параметров функций CreateWindow и CreateWindowEx можно получить по ссылкам http://msdn.microsoft.com/en-us/library/windows/desktop/ms632679%28v=vs.85%29.aspx и http://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx .При использовании классов различных фреймворков создание объектов окон операционной системы может происходить как явно (посредством вызова метода), так и неявно (реализация стратегии RAII). Поэтому дескриптор окна лучше получать на готовом инициализированном объекте. О методах классов, возвращающих дескриптор окна, инкапсулируемый объектом, можно узнать в документации соответствующего фреймворка. Например, в MFC подобным методом является GetSafeHwnd класса CWnd.

Получите дескриптор окна путем его поиска. Используйте API-функции FindWindow и FindWindowEx или соответствующие методы-обертки объектов классов применяемого фреймворка.Функция FindWindow возвращает дескриптор окна верхнего уровня, если оно найдено или NULL при неудаче. Поиск производится по имени класса и заголовку окна. Описание параметров и аспектов работы функции находится по ссылке http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499%28v=vs.85%29.aspx .Семантика работы функции FindWindowEx аналогична FindWindow с той лишь разницей, что она производит поиск дочерних окон. Документация для FindWindowEx приведена по ссылке http://msdn.microsoft.com/en-us/library/windows/desktop/ms633500%28v=vs.85%29.aspx .

Найдите дескриптор окна в процессе перечисления их множеств. Воспользуйтесь API-функциями EnumWindows, EnumChildWindows, EnumThreadWindows либо методами объектов классов используемого фреймворка.Функции EnumWindows и EnumChildWindows перечисляют окна верхнего уровня и дочерние окна соответственно. Функция EnumThreadWindows перечисляет все не дочерние окна указанного потока. Каждой из этих функций должен быть передан указатель на процедуру обратного вызова, которой в процессе работы будут передаваться дескрипторы найденных окон в качестве параметров.Комбинируя функции перечисления, получая и анализируя свойства окон в процедуре обратного вызова, можно найти дескриптор требуемого окна. Документация для описанных функций приведена по ссылкам:- EnumWindows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx ;- EnumChildWindows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633494%28v=vs.85%29.aspx ;- EnumThreadWindows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633495%28v=vs.85%29.aspx .

Получите дескриптор окна по известным координатам. Функции WindowFromPoint, ChildWindowFromPoint, ChildWindowFromPointEx возвращают дескрипторы окон, к областям расположения которых принадлежит заданная точка.Функция WindowFromPoint наиболее проста в использовании, но не возвращает дескрипторы скрытых и отключенных окон. Документация по ее применению находится по ссылке http://msdn.microsoft.com/en-us/library/windows/desktop/ms633558%28v=vs.85%29.aspx .Функции ChildWindowFromPoint и ChildWindowFromPointEx находят дескрипторы дочерних окон заданного родительского окна, принадлежащих заданной точке. При этом поведением ChildWindowFromPointEx можно гибко управлять с помощью дополнительного параметра. Документация для данных функций приводится по ссылкам:- ChildWindowFromPoint: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632676%28v=vs.85%29.aspx ;- ChildWindowFromPointEx: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632677%28v=vs.85%29.aspx .

Видео по теме

Войти на сайт

или

Забыли пароль?
Еще не зарегистрированы?

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Чтобы найти дескриптор окна можно воспользоваться функцией GetNextWindow API Windows. Определение этой функции:

HWND GetNextWindow(hWnd hWnd, unsigned int wCmd);

Она определяет дескриптор следующего или предыдущего окна в Z-последовательности. Параметр hWnd – дескриптор окна, от которого начинается отсчет. Параметр wCmd определяет направление поиска. Если wCmd = GW_HWNDNEXT, то ищется следующее окно, находящееся ниже. Если wCmd = GW_HWNDPREV, то ищется предыдущее окно, находящееся выше.

Следующее окно в Z-последовательности – это то, которое вызывалось из указанного или к которому пользователь обращался после создания указанного окна. Если указано дочернее окно, то поиск ведется среди дочерних окон.

Если искомое окно найдено, то возвращается его дескриптор. Если следующего или предыдущего окна нет (в зависимости от значения wCmd), то возвращается 0.

Можно использовать функцию GetNextWindow для поиска окна с известным текстом. Но при этом нам потребуется еще одна функция API WindowsGetWindowText. Эта функция копирует текст, связанный с указанным окном, в указанный буфер. Ее объявление имеет вид:

int GetWindowText(HWND hWnd, char *lpString, int nMaxCount);

Параметр hWnd – дескриптор окна. Параметр IpString указывает на буфер, в который копируется текст. Параметр nMaxCount определяет максимальное число копируемых символов. Если число символов в тексте превышает эту величину, текст усекается.

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

Теперь мы можем решить задачу, поставленную нами в качестве примера: определить дескриптор окна выполняемого приложения «Калькулятор». Это можно сделать с помощью следующего кода:

HWND H = Handle;
char Pch[128];
do
{
H = GetNextWindow (H, GW__HWNDNEXT);
GetWindowText(H,Pch,128);
if(CompareText(Pch, "Калькулятор") == 0)
break;
}
while(H != NULL);
if(H != NULL)
//...свой код программы

Первый выполняемый оператор присваивает переменной H значение свойства Handle формы вашего приложения. Далее в цикле просматриваются окна, лежащие ниже в Z-последовательности, и среди них ищется окно с текстом «Калькулятор». Для этого используется функция CompareText, сравнивающая без учета регистра строку, на которую указывает Pch, со строкой «Калькулятор». Если строки совпадают, функция CompareText возвращает нуль. Пользуясь тем, что С++ позволяет оперировать с целыми значениями как с булевыми, строку оператора if можно было бы записать и в таком виде:

if(!CompareText(Pch, "Калькулятор"))
{
...
}

Окно калькулятора будет найдено, если око получало фокус после запуска вашего приложения. Таким образом, если пользователь запустил «Калькулятор» из вашего приложения или даже если «Калькулятор» был запущен ранее или независимо от вашего приложения, дескриптор его окна будет найден. Если цикл завершается со значением H = NULL, значит приложение «Калькулятор» в данный момент не открыто.

Табаков Юрий

Табаков Юрий

Программист

Автор и редактор проекта CuBook.PRO. Главная задача, которую я ставлю перед собой – донести до начинающих программистов удобочитаемый материал. Буду рад выслушать замечания и предложения. Не забываем ставить оценки и делать репосты =)

http://www.cnblogs.com/zjutlitao/p/3889900.html

1. Используйте функцию FindWindow, чтобы получить дескриптор окна.

Пример:Используйте функцию FindWindow, чтобы получить дескриптор окна, затем получить размер окна и переместить окно в указанное положение.

Мы хотим взять оконную ручку крутой музыкальной шкатулки и переместить ее, что нам делать?


[WinAPI] Несколько методов получения дескриптора окна

Сначала откройте SPY ++ в инструменте в VC или VS и щелкните окно поиска следующим образом:

PS:Переместите похожую на яблочко вещь в окно, которое вы хотите найти. Это Kuwo Music Box. Информация об окне появится ниже, включая дескриптор, имя, класс, тип, размер и расположение окна. Нажмите ОК, и появится дополнительная информация ~

PS:Поскольку FindWindowA (LPCSTR lpClassName, LPCSTR lpWindowName); может найти дескриптор окна по имени класса окна и имени окна, если вы знаете только одно, напишите другое как null. Здесь мы обнаружим, что его имя окна будет следовать за воспроизводимой песней Поэтому неразумно находить дескриптор окна по имени окна (но мы можем получить имя воспроизводимой в данный момент музыки по имени окна!), Поэтому мы используем имя класса окна, чтобы получить дескриптор окна.

Ха-ха, остальные две функции очень просты, и я должен это понять.

#include <Windows.h>  
#include <stdio.h>  
#include <string.h>  
#include <iostream>
using namespace std;


int main(int argc, char* argv[])
{
	// Получение дескриптора окна Kuwo Music в соответствии с именем класса окна  
	//HWND hq = FindWindow("kwmusicmaindlg", NULL);
	 // WeChat
	HWND hq = FindWindow("WeChatMainWndForPC", NULL);
	//qq
	//HWND hq = FindWindow("TXGuiFoundation", NULL);
	 // Получаем размер крутого музыкального окна  
	RECT rect;
	GetWindowRect(hq, &rect);
	int w = rect.right - rect.left, h = rect.bottom - rect.top;
	 cout << "wide:" << w << "" << "high:" << h << endl;


	 // Горизонтальные и вертикальные координаты положения мобильного окна - 100 позиций  
	MoveWindow(hq, 100, 100, w, h, false);


	 // Получаем окно рабочего стола  
	HWND hd = GetDesktopWindow();
	GetWindowRect(hd, &rect);
	w = rect.right - rect.left;
	h = rect.bottom - rect.top;
	 cout << "Ширина:" << w << "" << "Высокая:" << h << endl;


	return 0;
}

>_<:Здесь функция GetWindowRect может получить прямоугольник окна, и размер окна может быть рассчитан в соответствии с прямоугольником окна; MoveWindow может перемещать окно в указанную позицию, а 4-й и 5-й параметры также могут изменять размер окна!

>_<:Ниже я добавил дополнительную операцию, чтобы получить размер рабочего стола ~

2、Получить все окна верхнего уровня и их дочерние окна

Пример:Используйте функции EnumWindows и EnumChildWindows и относительные функции обратного вызова EnumWindowsProc и EnumChildWindowsProc, чтобы получить все окна верхнего уровня и их дочерние окна.

нота:Некоторые окна были специально обработаны, например, QQ нельзя получить этим методом!

>_<:Как показано выше, у некоторых окон нет имен, поэтому они пусты ~

  1. #include <Windows.h>  
  2. #include <stdio.h>  
  3. #include <tchar.h>  
  4. #include <string.h>  
  5. #include <iostream.h>  
  6.   
  7. int Pnum=0,Cnum;// Количество родительских окон, количество дочерних окон каждого родительского окна  
  8.   
  9. //———————————————————  
  10. // Функция обратного вызова EnumChildWindows, hwnd – это указанное родительское окно  
  11. //———————————————————  
  12. BOOL CALLBACK EnumChildWindowsProc(HWND hWnd,LPARAM lParam)  
  13. {  
  14.     char WindowTitle[100]={0};    
  15.     Cnum++;  
  16.     ::GetWindowText(hWnd,WindowTitle,100);  
  17.     printf(“–|%d :%sn”,Cnum,WindowTitle);  
  18.     return true;     
  19. }  
  20. //———————————————————  
  21. // Функция обратного вызова EnumWindows, hwnd – найденное окно верхнего уровня  
  22. //———————————————————  
  23. BOOL CALLBACK EnumWindowsProc(HWND hWnd,LPARAM lParam)  
  24. {  
  25.     if(GetParent(hWnd)==NULL && IsWindowVisible(hWnd))  // Определяем, видно ли окно верхнего уровня и  
  26.     {  
  27.         Pnum++;  
  28.         Cnum=0;  
  29.         char WindowTitle[100]={0};  
  30.         ::GetWindowText(hWnd,WindowTitle,100);  
  31.         printf(“——————————————-n”);  
  32.         printf(“%d: %sn”,Pnum,WindowTitle);  
  33.         EnumChildWindows(hWnd,EnumChildWindowsProc,NULL); // Получаем все дочерние окна родительского окна  
  34.     }  
  35.     return true;     
  36. }  
  37. //———————————————————  
  38. //основная функция  
  39. //———————————————————  
  40. int main()  
  41. {  
  42.     // Получить все окна верхнего уровня на экране и вызвать функцию обратного вызова каждый раз, когда будет найдено окно  
  43.     EnumWindows(EnumWindowsProc ,NULL );  
  44.     getchar();  
  45.     return 0;  
  46. }  

3. Используйте функции GetDesktopWindow и GetNextWindow, чтобы получить все дочерние окна.

PS:Пройдя таким образом, вы можете найти нужный дескриптор окна (не делайте плохих вещей! Ха-ха ~)

  1. #include <Windows.h>  
  2. #include <stdio.h>  
  3. #include <tchar.h>  
  4. #include <string.h>  
  5. #include <iostream.h>  
  6.   
  7. int main()  
  8. {      
  9.     HWND hd=GetDesktopWindow();        // Получаем окно рабочего стола  
  10.     hd=GetWindow(hd,GW_CHILD);        // Получаем первое дочернее окно на экране  
  11.     char s[200]={0};  
  12.     int num=1;  
  13.     while(hd!=NULL)                    // Цикл для получения всех дочерних окон  
  14.     {  
  15.         memset(s,0,200);  
  16.         GetWindowText(hd,s,200);  
  17.         cout<<num++<<“: “<<s<<endl;  
  18.         hd=GetNextWindow(hd,GW_HWNDNEXT);  
  19.     }  
  20.     getchar();  
  21.     return 0;  
  22. }  

In light of a recent discussion on Meta complaining that questions like this one have “not been properly answered”, I’m going to try and give answering this one a whirl. Not to imply that I think meklarian’s answer is bad—in fact, far from it. But it’s clearly been deemed unsatisfactory, so perhaps I can fill in some of the additional details.

Your problem results from a fairly widespread confusion over what the desktop window actually is. The GetDesktopWindow function does precisely what it’s documented to do: it returns a handle to the desktop window. This, however, is not the same window that contains the desktop icons. That’s a completely different window that appeared for the first time in Windows 95. It’s actually a ListView control set to the “Large Icons” view, with the actual desktop window as its parent.

Raymond Chen, a developer on the Windows Shell team provides some additional detail in the following Windows Confidential article: Leftovers from Windows 3.0

[ . . . ]  While in Windows 3.0, icons on the desktop represented minimized windows, in Windows 95, the desktop acted as an icon container.

The Windows 95 desktop was actually a window created by Explorer that covered your screen (but sat beneath all the other windows on your desktop). That was the window that displayed your icons. There was still a window manager desktop window beneath that (the window you get if you call Get­Desktop­Window), but you never saw it because it was covered by the Windows 95 desktop—the same way that the wood paneling in the basement of my colleague’s house covered the original wall and the time capsule behind the wall.

[ . . . ]

This desktop design has remained largely unchanged since its introduction in Windows 95. On a typical machine, the original desktop is still there, but it’s completely covered by the Explorer desktop.

In summary, then, the window returned by the GetDesktopWindow function is the actual desktop window, the only one we had way back in Windows 3.0. The Explorer desktop (the one that contains all your icons) is merely another window sitting on top of the desktop window (although one that completely covers the original) that wasn’t added until Windows 95.

If you want to get a handle to the Explorer desktop window, you need to do some additional work beyond simply calling the GetDesktopWindow function. In particular, you need to traverse the child windows of the actual desktop window to find the one that Explorer uses to display icons. Do this by calling the FindWindowEx function to get each window in the hierarchy until you get to the one that you want. It has a class name of SysListView32. You’ll also probably want to use the GetShellWindow function, which returns a handle to the Shell’s desktop window, to help get you started.

The code might look like this (warning: this code is untested, and I don’t recommend using it anyway!):

HWND hShellWnd = GetShellWindow();
HWND hDefView = FindWindowEx(hShellWnd, NULL, _T("SHELLDLL_DefView"), NULL);
HWND folderView = FindWindowEx(hDefView, NULL, _T("SysListView32"), NULL);
return folderView;

I noted there that I don’t actually recommend using that code. Why not? Because in almost every case that you want to get a handle to the desktop window (either the actual desktop window, or the Explorer desktop), you’re doing something wrong.

This isn’t how you’re supposed to interact with the desktop window. In fact, you’re not really supposed to interact with it at all! Remember how you learned when you were a child that you’re not supposed to play with things that belong to other people without their permission? Well, the desktop belongs to Windows (more specifically, to the Shell), and it hasn’t given you permission to play with its toys! And like any good child, the Shell is subject to throwing a fit when you try to play with its toys without asking.

The same Raymond Chen has published another article on his blog that details a very specific case, entitled What’s so special about the desktop window?

Beyond the example he gives, this is fundamentally not the way to do UI automation. It’s simply too fragile, too problematic, and too subject to breaking on future versions of Windows. Instead, define what it is that you’re actually trying to accomplish, and then search for the function that enables you to do that.

If such a function does not exist, the lesson to be learned is not that Microsoft simply wants to make life harder for developers. But rather that you aren’t supposed to be doing that in the first place.

Psilon

Master of Orion

Эксперт .NET

6094 / 4950 / 905

Регистрация: 10.07.2011

Сообщений: 14,522

Записей в блоге: 5

30.09.2015, 13:19

6

Nalik, выше верно сказали. Я в своё время тоже намучился, но получил рабочее решение.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class ExeLockFounder
{
    const uint WM_SETTEXT = 0x000C;
    delegate bool EnumDelegate(IntPtr hWnd, IntPtr lParam);
 
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
 
    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string lpszWindow);
 
    [DllImport("user32.dll")]
    static extern bool EnumThreadWindows(int dwThreadId, EnumDelegate lpfn, IntPtr lParam);
 
    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
 
    private static IntPtr GetWindowByClassName(IEnumerable<IntPtr> windows, string className)
    {
        foreach (var window in windows)
        {
            var sb = new StringBuilder(256);
            GetClassName(window, sb, sb.Capacity);
            if (sb.ToString() == className)
                return window;
        }
        return IntPtr.Zero;
    }
 
    static IEnumerable<IntPtr> EnumerateProcessWindowHandles(Process process)
    {
        var handles = new List<IntPtr>();
        foreach (ProcessThread thread in process.Threads)
            EnumThreadWindows(thread.Id, (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
        return handles;
    }
 
    private readonly IntPtr _editHandle;
 
    public ExeLockFounder()
    {
        var processes = Process.GetProcessesByName("Setup");
        var proc = Array.Find(processes, x => string.Equals(x.MainWindowTitle, "ExeLock", StringComparison.OrdinalIgnoreCase));
 
        var windows = EnumerateProcessWindowHandles(proc);
        var hWnd = GetWindowByClassName(windows, "TFormPassDialog");
        _editHandle = FindWindowEx(hWnd, IntPtr.Zero, "TEdit", null);
    }
 
    public void SendText(string message)
    {
        SendMessage(_editHandle, WM_SETTEXT, IntPtr.Zero, message);
    }
}

Тут я находил окно типа “TFormPassDialog” (нужная мне форма, когда как главное окно имело тип ExeLock), принадлежащее процессу “Setup”. После чего находил там нужный мне TEdit и вбивал в него некоторый текст. Немного расширив, можно написать такой хелпер:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public static class WinApi
{
    delegate bool EnumDelegate(IntPtr hWnd, IntPtr lParam);
 
    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
 
    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string lpszWindow);
 
    [DllImport("user32.dll")]
    static extern bool EnumThreadWindows(int dwThreadId, EnumDelegate lpfn, IntPtr lParam);
 
    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);
 
    private static IntPtr GetWindowByClassName(IEnumerable<IntPtr> windows, string className)
    {
        foreach (var window in windows)
        {
            var sb = new StringBuilder(256);
            GetClassName(window, sb, sb.Capacity);
            if (sb.ToString() == className)
                return window;
        }
        return IntPtr.Zero;
    }
 
    public static IEnumerable<IntPtr> EnumerateProcessWindowHandles(Process process)
    {
        var handles = new List<IntPtr>();
        foreach (ProcessThread thread in process.Threads)
            EnumThreadWindows(thread.Id, (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
        return handles;
    }
 
    public static IntPtr GetWindowByClassName(Process proc, string className)
    {
        var windows = EnumerateProcessWindowHandles(proc);
        var hWnd = GetWindowByClassName(windows, className);
        return hWnd;
    }
 
    public static IntPtr GetObjectByClassName(Process proc, string windowClassName, string className)
    {
        var window = GetWindowByClassName(proc, windowClassName);
        return FindWindowEx(window, IntPtr.Zero, className, null);
    }
}



1



Добавить комментарий