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

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

11.03.2012, 21:57. Показов 11381. Ответов 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
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru