Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.97/58: Рейтинг темы: голосов - 58, средняя оценка - 4.97
5 / 5 / 1
Регистрация: 26.10.2010
Сообщений: 126

Как узнать дескриптор окна приложения?

11.03.2012, 21:57. Показов 11336. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, в user32.dll есть такая функция:
C#
1
SetForegroundWindow(hWnd)
Понадобилось мне вывести окно наверх экрана. Дескриптор окна я получил следующим образом:
C#
1
Process.GetCurrentProcess().MainWindowHandle
.

Пока приложение было консольное, окно выскакивало наверх. Как только приложение стало WindowsForm, Process.GetCurrentProcess().MainWindowHa ndle возвращает ноль. Handle, правда отличен от нуля, но тоже не совпадает с дескриптором окна, которое выводится.

Как узнать мне дескриптор этого окна или решить проблему другим образом?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
11.03.2012, 21:57
Ответы с готовыми решениями:

Узнать дескриптор окна
Всем привет. В общем у меня такая проблема: запускается приложение => появляется главное окно (1-е) и сразу же появляется окно ввода логина...

Узнать дескриптор окна запускаемой программы
Здравствуйте. Запускаю программу таким образом: ProcessStartInfo startInfo = new ProcessStartInfo(file_directory); //Путь ...

Получить дескриптор окна стороннего приложения и контекстного меню
Здравствуйте. Подскажите пожалуйста. Как можно словить дескриптор выскакивающего окна? в списке Spy++ этого окна нет, т.к. оно...

4
107 / 107 / 9
Регистрация: 19.12.2010
Сообщений: 417
11.03.2012, 22:06
Запросить свойство Handle у формы, нет? Или лучше вызвать метод BringToFront? Form.TopMost?
0
5 / 5 / 1
Регистрация: 26.10.2010
Сообщений: 126
12.03.2012, 13:28  [ТС]
Цитата Сообщение от FutureCome Посмотреть сообщение
Запросить свойство Handle у формы
- я не совсем верно выразился. Когда я обращаюсь к созданной в данном коде форме - можно воспользоваться
Цитата Сообщение от FutureCome Посмотреть сообщение
BringToFront
.
(
Цитата Сообщение от FutureCome Посмотреть сообщение
Form.TopMost
- это скорее нечто вроде свойства AlwaysOnTop)

Речь о том, как бы переключить на передний план главное окно другого приложения (которое я же и запускаю).

ну и интересно, почему MainWindowHandle по разному работает ))

Добавлено через 10 минут
Второе применение:
Я запускаю программу, которая должна быть одна на систему. Если программа уже запущена, то выполняется перевод программы на передний план, а запущенный вторым экземпляр останавливается
0
107 / 107 / 9
Регистрация: 19.12.2010
Сообщений: 417
12.03.2012, 16:02
А так не подойдёт: Работа с дескриптором?
А так: поиск всех окон процесса?
1
5 / 5 / 1
Регистрация: 26.10.2010
Сообщений: 126
13.03.2012, 13:14  [ТС]
FutureCome, Спасибо. Не скажу что код по ссылкам для моего случая подходит, но позволил работать в нужном направлении. Вот что получилось.

Задача:
1. сделать сервер, который запускается один на систему, а при попытке вызвать его ещё раз - выставляет запущенный сервер на передний план, даже если он свёрнут в область уведомлений
2. Сделать несколько клиентов, первый из которых при запуске запустит сервер, а последний - корректно его прибъёт

(Заранее извиняюсь за нерасставленные директивы using - дёргал куски из боевого кода)

Для удобства и читабельности, обращения к WINAPI вынесены в отдельный класс. Вот он:
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
55
56
57
58
59
60
61
    /// <summary>
    /// Обращения к user32.dll и некоторые потребные для этого константы
    /// Windows API - он и есть Windows API
    /// </summary>
    public static class WINAPI
    {
        /// <summary>
        /// Служит для генерации сообщения WM_SYSCOMMAND
        /// </summary>
        public const int WM_SYSCOMMAND = 0x0112;
        /// <summary>
        /// Для использования как wParam при WM_SYSCOMMAND. Отправляет приложению сообщение, что ПОЛЬЗОВТЕЛЬ захотел закрыть окно
        /// </summary>
        public const int SC_CLOSE = 0xF060; // close the window
        /// <summary>
        /// Для использования как wParam при WM_SYSCOMMAND. Отправляет приложению сообщение,
        /// что ПОЛЬЗОВТЕЛЬ захотел восстановить нормальный размер окна
        /// </summary>
        public const int SC_RESTORE = 0xF120; //Restores the window to its normal position and size.
        /// <summary>
        /// Служит для закрытия приложения от имени TaskManager
        /// </summary>
        public const int WM_CLOSE = 0x0010;
 
        /// <summary>
        /// Служит для выставления окошек на передний план
        /// </summary>
        /// <param name="hWnd">указатель на окошко</param>
        /// <returns>ну, что-то вернёт. Видимо удалось/не удалось</returns>
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetForegroundWindow(IntPtr hWnd);
 
        /// <summary>
        /// Найти дескриптор окна
        /// </summary>
        /// <param name="lpClassName">class name</param>
        /// <param name="lpWindowName">window name</param>
        /// <returns>Handle окна</returns>
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(
            string lpClassName, // class name 
            string lpWindowName // window name 
        );
 
        /// <summary>
        /// Отправить сообщение
        /// </summary>
        /// <param name="hWnd"> handle to destination window </param>
        /// <param name="Msg">message</param>
        /// <param name="wParam">first message parameter </param>
        /// <param name="lParam">second message parameter</param>
        /// <returns>что-то вернёт, видимо An application should return zero if it processes this message.</returns>
        [DllImport("user32.dll")]
        public static extern int SendMessage(
            IntPtr hWnd, // handle to destination window 
            uint Msg, // message 
            int wParam, // first message parameter 
            int lParam // second message parameter 
        );
    }

Код сервера
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// TODO: Красивая иконка!!
namespace KPAServer
{
    /// <summary>
    /// Точка входа здеся
    /// </summary>
    static class Program
    {
        /// <summary>
        /// Служит для красивого сообщения об исключении
        /// </summary>
        /// <param name="e">Пойманное исключение</param>
        public static void msgException(Exception e)
        {
/*            String msg;
            msg = //"Возникли проблемы с созданием ссылки на KiaRawServer.\r\n" +
                  "Возникли проблемы в работе программы.\r\n" + 
                  "Программа будет закрыта.\r\n" +
                  "Обратитесь к разработчику, приложив к обращению следующую информацию:\r\n\r\n" +
                  "Тип: " + e.GetType().ToString() + "\r\n" +
                  "Message: " + e.Message + "\r\n" +
                  "Source: " + e.Source + "\r\n" +
                  "StackTrace:\r\n" + e.StackTrace;
            MessageBox.Show(msg,
                System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName,
                MessageBoxButtons.OK, MessageBoxIcon.Error);*/
            msgException(e, "Возникли проблемы в работе программы.\r\n" +
                  "Программа будет закрыта.\r\n" +
                  "Обратитесь к разработчику, приложив к обращению следующую информацию:\r\n");
        }
 
        /// <summary>
        /// Служит для красивого сообщения об исключении
        /// </summary>
        /// <param name="e">Пойманное исключение</param>
        /// <param name="header">Преамбула к ошибке. Предпололжение, с чем связана ошибка и т.п.</param>
        public static void msgException(Exception e, String header)
        {            
            String msg;
            
            msg = header +
                  "\r\n" +
                  "Тип: " + e.GetType().ToString() + "\r\n" +
                  "Message: " + e.Message + "\r\n" +
                  "Source: " + e.Source + "\r\n" +
                  "StackTrace:\r\n" + e.StackTrace;
            MessageBox.Show(msg,
                System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName,
                MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
 
        /// <summary>
        /// Главная точка входа для приложения. Здесь же стартует подключение к серверу
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            if (args.Contains("/?") ||
                args.Contains("/help") ||
                args.Contains("-help") ||
                args.Contains("-?") ||
                args.Contains("--h"))
            {
                Console.WriteLine("/minimized - run in tree");
                Console.WriteLine("/about  - about");
                return;
            }
            else if (args.Contains("/about"))
            {
                Console.WriteLine("Build by Anton Malinovskiy (amalinovskij@micro-project.ru, vk.com/id242889) special for Microproject ltd. (http://www.microproject.ru/)");
                return;
            }
 
            string moduleName = System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name; // как бы извернуться с вписыванием сюда имени, данного при компиляции ??
            bool createdNew = true;
            using (Mutex mutex = new Mutex(true, moduleName, out createdNew)) // если переименуют файл - это работать не будет
            {
                if (createdNew)
                {
                                БЛа-бла бла , оффтоп, полезный код здеся     
                }
                else // Если экземпляр уже запущен - выводим его на передний план
                {
                    MainForm form = new MainForm(); // из пушки по воробъям
                    IntPtr hWnd = WINAPI.FindWindow(null, form.Text);
 
                    if (hWnd != IntPtr.Zero) // перестраховка. Обе функции прекрасно проглотят 0
                    {
                        WINAPI.SendMessage(hWnd, WINAPI.WM_SYSCOMMAND, WINAPI.SC_RESTORE, 0);                        
                        WINAPI.SetForegroundWindow(hWnd);                        
                    }
 
                    /*Process current = Process.GetCurrentProcess(); этот то вариант на окошках и не пашет (
                    foreach (Process process in Process.GetProcessesByName(current.ProcessName))
                    {
 
                        if (process.Id != current.Id)
                        {
                            WINAPI.SetForegroundWindow(process.MainWindowHandle);  // ну-ну. Там 0 (( Почему - непонятно! 
                            break;
                        }
                    }*/
                }
            }
        }
    }
}

код клиента
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
    /// <summary>
    /// собственно, интерфейс к серверу
    /// </summary>
    public class KiaInterface 
    {
        /// <summary>
        /// собственно, контроллер
        /// </summary>
        KiaRawServer server;        
       
        /// <summary>
        /// строка нужна для запуска сервера
        /// </summary>
        const string serverModuleName = @"KPAServer.exe"; //не очень-то надёжно
        /// <summary>
        /// строка нужна для останова сервера 
        /// </summary>
        const string serverWindowTitle = @"Сервер КПА"; //не очень-то надёжно        
 
        /// <summary>
        /// <para>Набор действий, который надо выполнить в каждом конструкторе:</para>
        /// <list type= "number">
        /// <para>
        ///     <item>
        ///         <term>1.</term>
        ///         <description>Убедиться, что сервер запущен, если нет, то запустить его</description>
        ///     </item>
        ///</para>
        ///<para>
        ///     <item>
        ///         <term>2.</term>
        ///         <description>Получить от сервера ссылку на объект доступа к КИА</description>
        ///     </item>
        ///</para>
        ///<para>
        ///     <item>
        ///         <term>3.</term>
        ///         <description>Зарегистрироваться на сервере</description>
        ///     </item>
        ///</para>
        ///<para>
        ///     <item>
        ///         <term>4.</term>
        ///         <description>Войти на сервер</description>
        ///     </item>
        ///</para>
        /// </list>
        /// </summary>
        /// <exception cref="Win32Exception">Нет прав на запуск сервера</exception>
        void universalConstructor()
        {
            #region запуск серевра
            Process serverExe = null;
            Process[] processes = Process.GetProcesses();
            foreach (Process process in processes)
                try // к половине процессов и близко не подпустят
                {
 
                    if (process.MainModule.FileName.Contains(serverModuleName)) // не самое оригинальное имя, нужно быть осторожнее ))
                    {
                        serverExe = process;
                        break;
                    }
                }
                catch (System.ComponentModel.Win32Exception)
                {
                }
 
            if (serverExe == null) // если программы с заданным именем не существует, то запускаем её (свёрнутой)
            {
                serverExe = new System.Diagnostics.Process();// предполагается, что клиент и сервер в одном каталоге - уже нет
                serverExe.StartInfo.FileName = @"D:\\HRD\\soft\\InternalInterface\\bin\\Debug\\" + serverModuleName; // сиё есть бред, но пока пусть так и работает
                serverExe.StartInfo.Arguments = "/minimized";
                serverExe.StartInfo.UseShellExecute = true;
                serverExe.Start();
                System.Threading.Thread.Sleep(2000); // медленно стартует, зараза, надо предусмотреть что-то понадёжнее
            }
            #endregion
 
            #region клиентские заморочки
            #endregion
        }
 
        #region "Традиционный" интерфейс <version>1.0</version>
        /// <summary>
        /// Конструктор, эвва
        /// Запускакт сервер, после чего пытается к нему присоединиться
        /// </summary>
        public KiaInterface()
        {// нужен в <version>1.0</version>
            universalConstructor();
        }
 
        /// <summary>
        /// Уходим с сервера.
        /// Последний клиент убивает сервер, по крайней мере должен ))
        /// </summary>
        ~KiaInterface()
        {
            if (server != null) // могли произойти проблемы ещё при создании объекта, тогда работать с ним не надо
            {
                server.disconnect(); 
                server.clientLogout();
            }
            KiaRawServer.unRegisterClientInfo();
 
           // последний клиент убивает сервер
            Process serverExe = null;
 
            bool isLastClient = true; // наверное, через семафор проще
            Process[] processes = Process.GetProcesses(); // Обновим список процессов
            foreach (Process process in processes)
            {
               try // к половине процессов и близко не подпустят
               {// индийский код!! надо бы у приложения спросить, как его зовут
                    
                   if (Process.GetCurrentProcess().Id != process.Id && process.MainModule.FileName.Contains(System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name)) // теоретически, бывают разные программы с одним именем ))
                       isLastClient = false;
               }
               catch (System.ComponentModel.Win32Exception)
               {
               }
            }
 
            if (isLastClient) // если клиент оказался последним
            {
                IntPtr hWnd = WINAPI.FindWindow(null, serverWindowTitle); // Находим окно сервеа
                WINAPI.SendMessage(hWnd, WINAPI.WM_CLOSE, 0, 0); // закрываем его
                /*foreach (Process process in processes)
                {
                    try // к половине процессов и близко не подпустят
                    {
                        if (process.MainModule.FileName.Contains(serverModuleName)) // не самое оригинальное имя, нужно быть осторожнее ))
                        {
                            serverExe = process;
                            break;
                        }
                    }
                    catch (System.ComponentModel.Win32Exception)
                    {
                    }
                }
 
                serverExe.CloseMainWindow(); // как ни странно, в консоли работает. в MSDN опечатка - а вот тут не работает (
                serverExe.WaitForExit();*/
            }
      
        }
 
        #endregion
    }
Добавлено через 10 минут
думаю, стоит пояснить несколько моментов:
1. в коде есть манипуляции с процессами. Я надеялся получить handle без обращения WINAPI через них. Не получилось. Почему - выяснить не удалось. Но: Process.Kill может завершить процесс АВАРИЙНО, что не подходит для меня, но может кому-то и пригодится.
2. По поводу способа закрывания сервера. Дело в том, что сервер работает из трея. Соответственно, для удобства ALT+F4 и x-кнопка сворачивают в трей, но не закрывают его. Поэтому код:
C#
1
WINAPI.SendMessage(hWnd, WINAPI.WM_SYSCOMMAND, WINAPI.SC_CLOSE, 0);
Приведёт к сворачиванию в трей (Кому надо, расскажу, как я этого добился, сейчас это к делу не относится).
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
13.03.2012, 13:14
Помогаю со студенческими работами здесь

Перерисовка окна другого процесса через дескриптор этого окна
Приветствую всех. Может кто-то знает, как перерисовать окно другого процесса через дескриптор (IntPtr) этого окна. Может апишная функция...

Как получить снимок рабочей области окна программы зная его дескриптор?
Как получить снимок рабочей области окна программы зная его дескриптор?

Узнать название приложения активного окна, хук на переключения окон
Посоветуйте хук, который срабатывал бы при переключении окон. Плюс нужно узнать название того приложения на которое переключились. Например...

Как из DLL узнать дескриптор приложения
Есть программа, она вызывает DLL. Нужно в dll получить заголовок вызвавшего его окна. Кто-нибудь знает как? Много всяких функций пробовал,...

Как из DLL узнать дескриптор приложения
Есть прога(окно). Пишу DLL которая вызывается этой прогой(окном). Нужно получить заголовок окна, которое вызвало эту dll. Перебор всех окон...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru