1 – найти окно, получить хендл (дубль ответа коллеги, тем не менее)
[DllImport("USER32.DLL", CharSet = CharSet.Auto)]
internal static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
2 – послать “энтрер”… а тут все может быть просто, или не совсем
просто SendKeys мне не подошел (долгая история, но можете с него и начать ))
3 – как вышло у меня, для типовых виндовых диалогов “открыть файл”/”сохранить файл” – надо “класс” приемник сообщения, и всю его иерархиею, начиная с хендла (диалога, в моем случае) (понадобится тула https://social.msdn.microsoft.com/Forums/vstudio/e… пример для сохранения
"Save Table".hWndByTitle().setTitle(csvDlg).waitForIdle().sendString(
new string[] {
"DUIViewWndClassName",
"DirectUIHWND",
"FloatNotifySink",
"ComboBox",
"Edit" },
csv);
реализация sendString
internal static IntPtr sendString(this IntPtr hWnd, string[] classNames, string msg, bool verb = false)
{
var hCtrl = hWnd;
if (classNames != null && classNames.Count() > 0)
{
Thread.Sleep(to[toFileStdDlg]);
foreach (var c in classNames)
{
Thread.Sleep(to[toFileStdDlg]);
hCtrl = user32.FindWindowEx(hCtrl, IntPtr.Zero, c, null);
if (hCtrl.Equals(IntPtr.Zero))
{
$"tERROR :: sendString not found class {c}".log();
return hWnd;
}
else
hCtrl.waitForIdle();
}
}
for (int i = 0; i < msg.Length; i++)
user32.PostMessage(hCtrl, WM_CHAR, msg[i], 0);
Thread.Sleep(to[toFileStdDlg]);
user32.PostMessage(hWnd, WM_KEYDOWN, user32.VkKeyScan('r'), 0);
user32.PostMessage(hWnd, WM_KEYUP, user32.VkKeyScan('r'), 0);
return hWnd;
}
Если окно одно, то я его успешно нахожу и нормально обращаюсь через FindWindow
// Get a handle to an application window.
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
// Activate an application window.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
private void button1_Click(object sender, EventArgs e)
{
// Get a handle to the Calculator application. The window class
// and window name were obtained using the Spy++ tool.
IntPtr calculatorHandle = FindWindow("CalcFrame", "Калькулятор");
// Verify that Calculator is a running process.
if (calculatorHandle == IntPtr.Zero)
{
MessageBox.Show("Calculator is not running.");
return;
}
// Make Calculator the foreground application and send it
// a set of calculations.
SetForegroundWindow(calculatorHandle);
SendKeys.SendWait("111");
SendKeys.SendWait("*");
SendKeys.SendWait("11");
SendKeys.SendWait("=");
}
но если запустить вторую копию программы то у этих окон одинаковые классы и заголовки и через FindWindow
не находит. Какие еще есть способы? Помогите пожалуйста.
задан 23 мар 2012 в 16:38
MerlinMerlin
5,4815 золотых знаков46 серебряных знаков90 бронзовых знаков
Решилось через EnumWindows
, готовая реализация:
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
// Get a handle to an application window.
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
// Activate an application window.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible ( IntPtr hWnd );
[DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowTextLength(IntPtr hWnd);
List<IntPtr> ListHandles = new List<IntPtr>();
//перед нажатием кнопки запускаем несколько калькуляторов
private void btnSearchHwnd_Click(object sender, EventArgs e)
{
EnumWindows((hWnd, lParam) =>
{
if ((IsWindowVisible(hWnd) && GetWindowTextLength(hWnd) != 0) && GetWindowText(hWnd).StartsWith("Калькулятор"))
{
ListHandles.Add(hWnd);
listBox1.Items.Add(hWnd.ToString());
}
return true;
}, IntPtr.Zero);
}
string GetWindowText(IntPtr hWnd)
{
int len = GetWindowTextLength(hWnd) + 1;
StringBuilder sb = new StringBuilder(len);
len = GetWindowText(hWnd, sb, len);
return sb.ToString(0, len);
}
private void listBox1_MouseClick(object sender, MouseEventArgs e)
{
// Get a handle to the Calculator application. The window class
// and window name were obtained using the Spy++ tool.
IntPtr calculatorHandle = ListHandles[listBox1.SelectedIndex];
if (calculatorHandle == IntPtr.Zero)
{
MessageBox.Show("Calculator is not running.");
return;
}
//выводим на передний фон окно именно того калькулятора,
//дескриптор которого выбрали в listBox1, что и требовалось
SetForegroundWindow(calculatorHandle);
//Делаем с нужным окном что хотим
SendKeys.SendWait("111");
SendKeys.SendWait("*");
SendKeys.SendWait("11");
SendKeys.SendWait("=");
}
}
}
ответ дан 23 мар 2012 в 21:47
MerlinMerlin
5,4815 золотых знаков46 серебряных знаков90 бронзовых знаков
Основным способом по-любому будет FindWindow()
, если вам нужно, чтобы программа не запускалась, если копия уже запущена, то используйте мютексы. В Delphi на чистом WinApi это выглядит так:
var
HM:Thandle;
begin
HM := OpenMutex(MUTEX_ALL_ACCESS, false, 'MyProg'); // ищем мютекс "MyProg"
if HM = 0 then
// резервируем мютекс "MyProg", если такового не найдено.
HM := CreateMutex(nil, false, 'MyProg') else application.Terminate;
ответ дан 23 мар 2012 в 16:50
AseNAseN
13.6k13 золотых знаков60 серебряных знаков122 бронзовых знака
Найти handle окна можно стандартными средствами .NET‘а. Обратите внимание на класс System.Diagnostics.Process
(В частности на его свойства MainWindowHandle
, MainWindowTitle
и ProcessName
. А также статические методы GetProcesses
и GetProcessesByName
)
Ипользуя вышеперечисленное, несложно найти все интересующие окна:
IntPtr[] handles = Process.GetProcessesByName("requiredProcess")
.Where(process => process.MainWindowHandle != IntPtr.Zero)
.Select(process => process.MainWindowHandle)
.ToArray();
После этого можно “общаться” со всеми найденными окнами.
Второй вариант в Вашей ситуации – закрыть все “лишние” окна, оставив одно. Закрыть главное окно процесса можно с помощью метода CloseMainWindow
.
ответ дан 23 мар 2012 в 21:14
ShadShad
3,44319 серебряных знаков23 бронзовых знака
I have to track the running time of a program.
That program exposes the following window
At the same time I launch my program which in a timer does:
private void TimerCheckGroups_Tick(object sender, EventArgs e)
{
IntPtr windowPtr = FindWindowByCaption(IntPtr.Zero, "Execution");
if (windowPtr != IntPtr.Zero)
Console.Beep();<--------
}
But the beep line never gets hit.
Have I misunderstood the meaning of a window caption?
–ADD–
I’ll try to make the execution phases clearer.
Startup—-> launch my logger.
User——-> launches program A that launches program B (not visible) that launches window C. C has caption Execution.
When I launch the solution proposed by dontbyteme the only the B program appears so only 1 window.
In short
-
logger: not visible since it’s a tray program
-
program A: visible since it’s the main program
-
program B: not visible since it’s set to Notvisible
-
program C: not visible why?!?!?!?
–SOLUTION THANX TO JARRETT–
-
logger stays idle with a timer monitoring processes
-
program A starts but nobody cares about it. Then program A launches program B
-
when program B is awake i find the window and start logging
Пособие-самоучитель |
||
§ 2. Окна. Поиск окна по заголовку. Координаты курсора мыши. Определение хендла окна по точке и заголовку. Структура POINTAPI. |
||
Скачать |
Дата создания 11.04.2005 {Автор 4us} |
|
Новые |
|
Функция CloseWindow |
|
Назначение | Сворачивает заданное хендлом окно. |
Объявление | Declare Function
|
Аргументы | hwnd (Long) – хендл сворачиваемого окна |
Функция CloseWindow возвращает ненулевое значение в случае успеха операции и ноль при неудаче. |
|
Функция DestroyWindow |
|
Назначение | Уничтожает заданное хендлом окно и все его дочерние окна. Не работает под Windows XP. Да и под Win98 тоже. И вообще, на фиг она нужна? |
Объявление | Declare Function
|
Аргументы | hwnd (Long) – хендл уничтожаемого окна |
Функция DestroyWindow возвращает ненулевое значение в случае успеха операции и ноль при неудаче. |
|
Функция FindWindow |
|
Назначение | Находит хендл первого окно верхнего уровня по имени класса или по заголовку (тексту) окна. |
Объявление | Declare Function
|
Аргументы | lpClassName (String) – строка с именем класса или ноль, если поиск происходит по заголовку (тексту) окна. В качестве нуля лучше всего использовать константу vbNullString. lpWindowName (String) – строка с заголовком или текстом окна или ноль, если поиск окна происходит по имени класса. В качестве нуля лучше всего использовать константу vbNullString |
Функция FindWindow возвращает хендл найденного окна. |
|
Функция GetCursorPos |
|
Назначение | Передает в структуру POINTAPI текущую позицию курсора мыши в экранной системе координат. |
Объявление | Declare GetCursorPos Lib |
Аргументы | lpPoint (структура) – содержит координаты X и Y в экранной системе координет в пикселях. Объявление структуры POINTAPI: Type POINTAPI Далее любая переменная объявляется с типом POINTAPT, например MouseCoordinat : Public MouseCoordinat As |
Функция GetCursorPos возвращает ненулевое значение в случае успеха операции и ноль при неудаче. |
|
Функция GetWindowText |
|
Назначение | Читает заголовок окна или текстовое содержимое элемента формы. (Свойства .Caption и .Text) |
Объявление | Declare GetWindowText Lib |
Аргументы | hwnd (Long) – хендл окна, из котого читается текст lpString (String) – заранее выделенная строка символов длиной не менее cch+1 символов, в которой после выполнения функции будет содержаться заголовок или текст окна. cch (Long) – длина строки lpString |
Функция GetWindowText возвращает длину строки, скопированной в lpString. С помощью этой функции НЕЛЬЗЯ читать текст из окон других приложений! |
|
Функция OpenIcon |
|
Назначение | Восстанавливает заданное хендлом свернутое окно и делает его активным. |
Объявление | Declare OpenIcon Lib "user32" |
Аргументы | hwnd (Long) – хендл свернутого окна |
Функция OpenIcon возвращает ненулевое значение в случае успеха операции и ноль при неудаче. |
|
Функция WindowFromPoint |
|
Назначение | Возвращает хендл окна, содержащую точку с заданными координатами. |
Объявление | Declare WindowFromPoint Lib |
Аргументы | xPoint (Long) – горизонтальная координата точки yPoint (Long) – вертикальная координата точки |
Функция WindowFromPoint возвращает хендл окна, содержащего точку. |
|
|
В прошлом параграфе мы добрались до окна нашего проекта – формы,
просто использовав свойство .hWnd, которое выложило нам на тарелечке
хендл окна. Но что делать, если нам надо добраться до чужого окна? Давайте продолжим
исследование окон.
А сейчас по пытаемся найти окно и сбить, т.е. я хотел сказать, произведем с
ним какие-то действия. Для этого сделаем себе учебную цель. Создадим новый exe-проект,
изменим свойство формы Form1.Caption=”F-16 Fighter” и откомпилируем
(то бишь создадим исполняемый файл exe). Запустим наш проект и пусть полученное
окно болтается на Десктопе до поры.
Теперь создадим новый exe-проект. Для наших экспериментов нам
потребуются четыре кнопки Command, один CheckBox, один таймер
Timer1 и пять текстбоксов, причем для Text1 желательно включить
свойства Multiline=True и ScrollBars=2 (Вертикаль).
В форме объявим две переменные, которые будут у нас использоваться
для: HandleWin – хранения хендла (чего делать нельзя, я имею ввиду хранить
нельзя, это мы отметим ниже особо) и KillWin – куда будут возвращать
свои значения функции (хотел ее назвать KillBill, потом KillGates, но перепутал
и стало лень менять. Но тоже по существу).
Option Explicit
Dim HandleWin As Long
Dim KillWin As Long
Примечание: При работе с API использование Option Explicit
уже не просто рекомендовано, а крайне необходимо и сугубо обязательно! Во
всех модулях и формах.
Далее, в процедуре загрузки формы очистим текстбоксы, в для Text2 присвоим значение
нашего учебного окна “F-16 Fighter”. Кроме того установим интервал
таймера и выключим его (он пока не нужен).
Еще примечание: Да, ты уж извини, но я не буду писать свойство
.Text для текстбоксов. Пора уже отвыкать есть руками, раз уж полезли в API.
Свойста, являющиеся главными для объектов понимаются по умолчанию и их явно
писать не обязательно(.Text для текстбоксов, .Capture для лейблов и т. д.)
Private
Sub Form_Load()
Text1 = ""
Text2 = "F-16 Fighter"
Text3 = ""
Text4 = ""
Text5 = ""
Timer1.Interval = 100
Timer1 = False
End Sub
Попробуем получить хендл окна по его (окна естественно) заголовку.
Заголовок – это все то, что выводится в синенькой верхней полосочке почти в
каждом окне. Для нашего окна-мишени это – Form1.Caption = “F-16 Fighter”.
Используем функцию FindWindow. Давай добавим в проект стандартный модуль
и объявим ее (все что пишется в модуле я буду выделять коричневым цветом):
Public
Declare Function FindWindow Lib "user32" Alias "FindWindowA"
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Как мы видим, в этой функции есть два аргумента, по которым можно найти окно:
по имени класса (
lpClassName)
и по имени заголовка (lpWindowName).
Как правило окно ищется по одному какому-нибудь аргументу. Поскольку мы не знаем
имя класса искомого окна (да и вообще не знаем, что это такое), а знаем заголовок,
то его и надо подставить в функцию вместо. Но и второе значение (lpClassName)
нельзя пускать на самотек. Ему надо передать ноль (в API всегда надо чего-то
передавать). Но аргумент этот имеет строковый тип, поэтому нужно использовать
константу vbNullString. Так как заголовок окна мы храним в Text2, то
использование функции будет выглядеть очень просто:
HandleWin
= FindWindow(vbNullString, Text2)
В переменную HandleWin мы получим искомый хендл искомого окна. Напишем теперь
процедуру:
Private
Sub Command1_Click()
HandleWin = FindWindow(vbNullString, Text2)
Text1 = Text1 & "Хендл окна с именем " & Text2 & "
" & HandleWin & vbCrLf
Text3 = HandleWin
End Sub
Нажимая на кнопку Command1, мы получаем хендл того окна, чей заголовок прописан
в Text2. При этом в Text1 будет выводится общая информация о найденом окне.
Теперь попробуем произвести кое-какие манипуляции с окном по его хендлу: уничтожить,
свернуть и развернуть. Для этого используются следующие функции
DestroyWindow – убивает окно. В Windows XP эта функция не работает. Она
в общем-то и в Win98 тоже не хочет убивать окно. Ну я решил, что и черт с ней.
Но пусть остается для примера.
CloseWindow – сворачивает окно
OpenIcon – восстанавливает свернутое окно
Их объявление совершенно идентично и смысл их использования сводится лишь к
подстановке вместо аргумента переменной, содержащей хендл. Объявим их в модуле:
Public
Declare Function DestroyWindow& Lib "user32" (ByVal hwnd As Long)
Public Declare Function CloseWindow Lib "user32" (ByVal hwnd As Long)
As Long
Public Declare Function OpenIcon Lib "user32" (ByVal hwnd As Long)
As Long
Обрати внимание, что первая функия объявлена с применением значка типа &
вместо As Long в конце. Такое объявление ничем не отличается по смыслу
и работе от двух других. Теперь пропишем каждую в свои процедуры соответствующих
кнопок Command2, Command3 и Command4. Кроме того, мы еще и проанализируем результат
действия каждой функции по возвращаемому значению (если ноль, то действие не
удалось) и выведем соответствующее сообщения в Text1:
Private
Sub Command2_Click()
KillWin = DestroyWindow&(HandleWin)
If KillWin = 0 Then
Text1 = Text1 & " Убийство окна " & HandleWin & "
не удалось!" & vbCrLf
Else
Text1 = Text1 & " Мы убили окно " & HandleWin & vbCrLf
End If
End SubPrivate Sub Command3_Click()
KillWin = CloseWindow(HandleWin)
If KillWin = 0 Then
Text1 = Text1 & " Свернуть окно " & HandleWin & "
не удалось!" & vbCrLf
Else
Text1 = Text1 & " Мы свернули окно " & HandleWin & vbCrLf
End If
End SubPrivate Sub Command4_Click()
KillWin = OpenIcon(HandleWin)
If KillWin = 0 Then
Text1 = Text1 & " Восстановить окно " & HandleWin & "
не удалось!" & vbCrLf
Else
Text1 = Text1 & " Мы восстановили окно " & HandleWin &
vbCrLf
End If
End Sub
Теперь я еще раз объясню, почему так делать нельзя. В процедуре
Command1 мы нашли и сохранили в переменной HandleWin хендл окна. А используем
его совершенно в другой процедуре по другому событию Command_Click. Между двумя
нажатиями пользователем на кнопки может произойти черт знает что. Если ты определишь
хендл , а затем закроешь и снова откроешь программку “F-16 Fighter”,
то ее окно будет иметь уже совершенно иной хендл и сделать с ним ничего будет
нельзя, до тех пор, пока не определишь его новый хендл. Поэтому действия с окнами
должны производится сразу же после определения хендла. Но я нарочно так сделал,
чтобы для простоты разделить функции по процедурам и иметь показательный отрицательный
пример под рукой.
Далее мы сделаем так, чтобы указав на окно курсором мыши мы могли посмотреть
(не получить для использования, а именно посмотреть), какой у окна хендл и какой
у него заголовок. Реализуется это с помощью функции WindowFromPoint,
которая возвращает хендл окна по точке на этом окне. Точкой этой будут координаты
курсора мыши. Получить их можно с помощью функции GetCursorPos. Вот с
нее и начнем. Точнее начнем с процедуры, которая будет включать весь этот наш
механизм. И процедура эта будет для Check1. Он лучше кнопки, так как имеет два
положения включено и выключено. Именно здесь мы будем включать и выключать таймер.
Зачем он нам нужен? А нужен он для того, чтобы не пытаться найти событие, которое
происходит при наведении мыши на окно. Так как в нашем проекте его и не происходит.
А таймер исправно , через каждые 100 миллисекунд будет нам включать наш механизм
определения хендла окна, на котором находится курсор мыши.
Итак начнем. Короткая процедура для включения-выключения таймера:
Private
Sub Check1_Click()
If Check1 = 0 Then
Timer1 = False
If Check1 = 1 Then
Timer1 = True
End Sub
И теперь самое интересное – процедура самого таймера.
Private Sub
Timer1_Timer()
'объявим тройку нужных нам переменных
Dim PosCur As Long
Dim DlinaTexta As Long
Dim WindowCaption As String
В модуле объявим функцию для определения координат мыши:
Public
Declare Function GetCursorPos Lib “user32” (lpPoint As POINTAPI) As
Long
И опааа, видим всего один аргумент, в то время координат должно быть две. А
дело в том, что lpPoint представляет структуру POINTAPI, которая содержит как
раз эти две координаты. Структура – это по-сути тот же пользовательский тип
данных, который мы разбирали в Главе 17 первой
части самоучителя, только задан жестко и никаких здесь вольностей быть не должно.
Поэтому в модуле объявляем тип POINTAPI так как это требуется для API-функций:
Type
POINTAPI
X As Long
Y As Long
End Type
и затем объявляем какую-нибудь переменную с типом POINTAPI, например MouseCoordinat:
Public
MouseCoordinat As POINTAPI
Вот теперь, возвращаемся к нашей процедуре таймера в форме и получаем, наконец,
координаты мыши:
PosCur = GetCursorPos(MouseCoordinat)
'записываем координаты в текстбоксы для большей
наглядности
Text4 = MouseCoordinat.X
Text5 = MouseCoordinat.Y
Теперь нам надо по этим координатам получить хендл окна. Объявим в модуле функцию:
Public
Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long,
ByVal yPoint As Long) As Long
Ну здесь все просто, как апельсин. Два аргумента – две координаты, что еще нужно
джигиту, чтобы встретить старость. Пишем в нашей процедуре:
HandleWin = WindowFromPoint(MouseCoordinat.X,
MouseCoordinat.Y)
Text3 = HandleWin
Теперь у нас в переменной HandleWin есть хендл и еще по нему мы можем узнать
заголовок экрана с помощью функции GetWindowText. Объявим ее в модуле:
Public
Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA"
(ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Ну с первым аргументом (hwnd)
– хендлом понятно, мы его имеем. Второй аргумент (lpString),
это как раз то, что мы хотим получить, т.е. заголовок , а третий (cch)-
длина этого самого заголовка. Поскольку мы этой длины не знаем, то ставим по-максимуму
-255 (вряд ли заголовок будет более 256 символов). А вот что касается второго
аргумента, тут дело несколько сложнее. Если мы подставим просто нашу переменную
WindowCaption, которую мы и объявили для заголовка окна
DlinaTexta = GetWindowText(HandleWin, WindowCaption, 255)
то это результатов не даст. Дело в том, что строковые аргументы API-функций
требуют, чтобы для них был в памяти зарезервирован буфер размером не меньше
строки, которую мы хотим получить. А для этого надо передать в функцию строку
пробелов, соответствующую размеру буфера. Короче, смысл в том , что мы присваиваем
переменной строку пробелов, а вместо нее получаем строку данных. И если строка
пробелов длинее , например “____________”, чем строка данных “123”,
то мы получим “123_____________”, т.е. данные плюс лишние пробелы,
а если строка пробелов короче, то данные усекутся по длине строки пробелов.
Исходя из этих мудреных рассуждений возвращаемся опять к нашей процедуре и резервируем
буфер (на самом деле просто присваиваем переменной WindowCaption строку пробелов
по-длинее
WindowCaption =
Space(256)
и теперь используем функцию по-правильному
DlinaTexta = GetWindowText(HandleWin,
WindowCaption, 255)
Теперь, раз у нас есть длина заголовка (это как раз то, что возвратила функция),
мы можем отсечь ненужные нам пробелы и вывести даныые в текстбокс
Text2 = Left(WindowCaption,
DlinaTexta)
End Sub
На этом пока все. В это параграфе мы разобрали технику использования API. Теперь
ты можещь, двигая мышью узнавать хендл любых окон и их заголовки (если есть).
Причем на собственной форме ты увидишь содержимое текстов, названия кнопок и
т.п. Исходник примера можно скачать вверху страницы.
Сайт создан в системе uCoz
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Diagnostics; using System.Threading; using System.Runtime.InteropServices; using System.Windows.Forms; namespace FindWindowByTitle { public partial class Form1 : Form { [DllImport("USER32.DLL")] private static extern int GetWindowText(IntPtr IntPtr, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowProc lpEnumFunc, string winName); public delegate bool EnumWindowProc(IntPtr hWnd, string winName); public Form1() { InitializeComponent(); } bool FindWindowByTitle(IntPtr hwnd, string winName) { StringBuilder str = new StringBuilder(200); GetWindowText(hwnd, str, 200); if (!str.ToString().Contains(winName)) return true; return false; } private void Form1_Click(object sender, EventArgs e) { Process p= Process.GetProcessesByName("impacthost")[0]; IntPtr hwin = new IntPtr(); hwin = p.MainWindowHandle; EnumChildWindows(hwin, new EnumWindowProc(FindWindowByTitle), "Gq_MvWorkspace"); } } }
правильно находит искомое окно, возвращает false. Но как теперь по выходе из
, но она осталась неизменной. Как тут быть?