Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.85/26: Рейтинг темы: голосов - 26, средняя оценка - 4.85
3 / 3 / 2
Регистрация: 27.06.2013
Сообщений: 94
1

WM_DESTROY закрывает не все окна

04.10.2014, 15:26. Показов 4851. Ответов 12
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Пишу на C#, на раздел по WinAPI есть только в разделе C++. Если будет ответ с кодом на C++, переведу на C#. Программа (не вирус) должна закрывать все окна, кроме разрешенных. Сами процессы приложения надо закрывать не всегда (это знаю, как делать). По таймеру нахожу все видимые окна с помощью EnumWindows, записываю их в массив структур, где хранятся Handle, заголовок окна, ID процесса, имя исполняемого файла процесса, класс окна.
C#
1
PostMessage(WindowsAll[i].Hwnd, (int)WM.CLOSE, IntPtr.Zero, IntPtr.Zero);
всегда пытается закрыть окно, но некоторые окна требуют подтверждения на закрытие и в результате не закрываются.
C#
1
PostMessage(WindowsAll[i].Hwnd, (int)WM.DESTROY, IntPtr.Zero, IntPtr.Zero);
закрывает не все окна, но закрывает окна, требующие подтверждения на закрытие, без выдачи запроса.
Наилучший результат получается, если использовать две строчки в таком порядке:
C#
1
2
PostMessage(WindowsAll[i].Hwnd, (int)WM.DESTROY, IntPtr.Zero, IntPtr.Zero); 
PostMessage(WindowsAll[i].Hwnd, (int)WM.CLOSE, IntPtr.Zero, IntPtr.Zero);
Все известные окна закрываются, но, например, окно Paint, если в нем есть несохраненный файл, закрывается довольно долго - несколько секунд мигает окно, которое требует подтверждения на закрытие.
Окна, создаваемые Window Explorer, закрываются только через CLOSE и не реагируют на DESTROY. Поэтому могут быть окна, которые не будут реагировать на DESTROY и требовать подтверждения на CLOSE.
Видел советы, что, когда посылается сообщение WM_DESTROY, необходимо использовать
C#
1
PostQuitMessage(0);
Знаю, как это делается, если окно создается с помощью WinAPI. Но не знаю, где должен быть
этот вызов, если окно находится среди уже открытых окон с использованием таймера. Поможет ли это, не знаю, но хотел бы это попробовать. Желателен полный текст программы или ссылка на него, которая посылает сообщение WM_DESTROY уже существующему окну и вызывает
C#
1
PostQuitMessage(0);
В Интернете примеры не нашел.
Нужно узнать любой способ быстрого принудительного закрытия всех ненужных окон без выдачи предупреждения.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.10.2014, 15:26
Ответы с готовыми решениями:

Проводник закрывает окна
По иконке "Мой компьютер" не открывается окно. Если попробовать другим способом добраться до дисков...

Компьютер начал перекидывать на другие окна в браузере, открывает закрывает проги сам
Компьютер начал перекидывать на другие окна в браузере, открывает закрывает проги и окна сам. Не...

Ищу программу, которая закрывает дополнительные окна браузеров после щелчка на некоторые ссылки.
Помимо рекламы и разнообразных всплывающих окон в сети очень напрягают дополнительные окна...

Windows закрывает все программы
Здавствуйте! После постановления на первоначальное состояние диска H, то есть основного, все...

12
567 / 198 / 70
Регистрация: 25.05.2012
Сообщений: 816
04.10.2014, 16:52 2
Может в вашем случае проще завершать процессы, а не закрывать окна? Они и не обязаны в обязательном порядке закрываться при получении WM_CLOSE.
0
3 / 3 / 2
Регистрация: 27.06.2013
Сообщений: 94
04.10.2014, 17:18  [ТС] 3
Нужно закрывать в том числе окна процесса Explorer, а сам Explorer по понятным причинам закрывать нельзя. И желательно иметь возможность закрыть любое окно, не закрывая процесса.
0
Заблокирован
Автор FAQ
04.10.2014, 17:43 4
Max_t, куда проще прятать окно а не закрывать, как можно думать что убив диалог главного потока приложение продолжить корректно работать. ShowWindow с парметром SW_HIDE используй
Цитата Сообщение от Max_t Посмотреть сообщение
PostMessage
- вот кто кто тебе сказал что пост помещает сообщение в очередь сообщений кроме потока в котором Post вызван???
http://msdn.microsoft.com/en-u... s.85).aspx хотябы гуглите перед тем как писать.

Добавлено через 1 минуту

Не по теме:

ЗЫ: Вместо поста юзай SendMessage SendNotify/SendCallbackMessage но не Post который в добавок ко всему имеет таймаут жизни окло 4 сек. Но в твоём случае селдует использовать ShowWindow

0
3 / 3 / 2
Регистрация: 27.06.2013
Сообщений: 94
04.10.2014, 19:43  [ТС] 5
Если скрыть окно, оно продолжает занимать ресурсы. А программа рассчитана на долгую работу без перезагрузки. PostMessage единственная функция, которая прибивает окно Paint, хотя и не сразу. Как прочитал, она помещает сообщение в очередь и завершает работу, а SendMessage продолжает работу, пока сообщение не будет получено. Может ли кто подсказать, почему PostMessage лучше закрывает окна, и в каком направлении смотреть, чтобы окна закрывались сразу и закрывались вновь создаваемые окна Windows Explorer с помощью WM_DESTROY, а не только WM_CLOSE? Есть ли смысл смотреть в направлении PostQuitMessage(0) ?
0
Заблокирован
Автор FAQ
04.10.2014, 21:15 6
Цитата Сообщение от Max_t Посмотреть сообщение
Если скрыть окно, оно продолжает занимать ресурсы. А программа рассчитана на долгую работу без перезагрузки. PostMessage единственная функция, которая прибивает окно Paint, хотя и не сразу. Как прочитал, она помещает сообщение в очередь и завершает работу, а SendMessage продолжает работу, пока сообщение не будет получено.
- Post никогда не доставит сообщение в окно другого процесса точка это делают Send
Цитата Сообщение от Max_t Посмотреть сообщение
SendMessage продолжает работу, пока сообщение не будет получено.
- я наверное зачем-то написал
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
SendNotify/SendCallbackMessage
Max_t, попробуй убить окно офиса а потом посмотри долго ли проживёт процесс.
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
как можно думать что убив диалог главного потока приложение продолжить корректно работать.

Не по теме:

ЗЫ:
Большинство АПИ приложений построено по схеме

C++
1
2
3
4
5
6
7
8
9
10
WinMain(){
CreateWindow(...)
MessageLoop[]
}
 
WindowProc(){
WM_DESTROY:
PostQuitMessage(0);//после него MessageLoop умирает а вслед за ним умирает и главный поток приложения, т.е погибает весь процесс
break;
}
Покурить
http://msdn.microsoft.com/en-u... s.85).aspx
http://msdn.microsoft.com/en-u... ating_loop

0
3 / 3 / 2
Регистрация: 27.06.2013
Сообщений: 94
05.10.2014, 00:55  [ТС] 7
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
- Post никогда не доставит сообщение в окно другого процесса точка это делают Send
У меня Post закрывает окна других приложений. Совершенно точно закрывает, но не все окна. Эффективнее Send, но эффективность недостаточная. Заметил также, что не закрывается окно Internet Explorer, а запрашивает подтверждения. Остается вопрос, почему на WM_CLOSE реагируют все окна (и запрашивают подтверждения), а на WM_DESTROY, при котором подтверждения не запрашивается, - не все. И как гарантировано прибить окно без запроса подтверждения по WM_DESTROY или другим способом.

Пока там не нашел по своей задаче.
0
Заблокирован
Автор FAQ
05.10.2014, 10:53 8
Max_t, показываю в деталях
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
#include <iostream>
#include <windows.h>
using namespace std;
 
int main(){
    setlocale(LC_CTYPE, ".866");
    system("pause");
    HWND hWnd = FindWindow(NULL, "Îêîøêî");
    if(!hWnd)
        wcout<<L"îêíî íå íàéäåíî "<<endl;
    else
    {
        wcout<<L"äåñêðèïòîð îêíà "<<(int)(hWnd)<<endl;
        if( !PostMessage(hWnd, WM_DESTROY, 0, 0) )
            wcout<<L"îøèáêà PostMessage"<<endl;
        else
            wcout<<L"PostMessage óñïåøíà"<<endl;
 
        system("pause");
        if( !SendMessage(hWnd, WM_DESTROY, 0, 0) )
            wcout<<L"îøèáêà SendMessage"<<endl;
        else
            wcout<<L"SendMessage óñïåøíà"<<endl;
 
        system("pause");
        if( !SendMessageCallback(hWnd, WM_QUIT, 0, 0, 0, 0) )
            wcout<<L"îøèáêà SendMessage"<<endl;
        else
            wcout<<L"SendMessage óñïåøíà"<<endl;
 
    }
    system("pause");
    return 0;
}
Загрузи проект отсюда Нужно компилировать программу подмени в WndProc ветку WM_DESTROY верней сначала отсавь и посомтри отработку а затем замени выход с WM_DESTROY на WM_QUIT

C++
1
2
3
4
5
6
7
8
9
10
11
12
UINT nCmd = HIWORD(wParam);
        UINT idCtrl = LOWORD(wParam);
        HWND hChild = (HWND)lParam;
        switch (msg)
        {       
        case /*WM_DESTROY*/WM_QUIT:
                PostQuitMessage(0); //Çàêðûâàåì ïðèëîæåíèå
                break;
        default: 
                return DefWindowProc(hWnd, msg, wParam, lParam); //âîçâðàùàåì äåôîëòíûå çíà÷åíèÿ                
        }
        return 0l;
Показываю лог работы уже для случая завершения работы диалогового приложения по WM_QUIT
Миниатюры
WM_DESTROY закрывает не все окна   WM_DESTROY закрывает не все окна   WM_DESTROY закрывает не все окна  

0
Заблокирован
Автор FAQ
05.10.2014, 10:58 9
Цитата Сообщение от Max_t Посмотреть сообщение
на WM_DESTROY, при котором подтверждения не запрашивается, - не все.
- не все приложения запрограммированы закрывать окно по данному сообщению в принципе можешь покрутить ещё EndDialog http://www.vsokovikov.narod.ru... dialog.htm т.е в любом случае тебе нужно ждать подтверждения того что окно закрылось Post в этом случае не подходит

Добавлено через 1 минуту

Не по теме:

Max_t, я тут хочу для себя расставить все точки над и для PostMessage, напиши приложение которое закрывает окна консольное или диалоговое?

0
3 / 3 / 2
Регистрация: 27.06.2013
Сообщений: 94
05.10.2014, 18:59  [ТС] 10
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Max_t, я тут хочу для себя расставить все точки над и для PostMessage, напиши приложение которое закрывает окна консольное или диалоговое?
Пример консольного кода на C#, который ищет и закрывает окна при запуске с помощью PostMessage. enum WM не привожу из-за большого размера. В С++ сообщения, посылаемые окнам, должны быть в Windows.h В моем приложении функция, похожая на CloseWindows(), вызывается по таймеру, остальное примерно то же самое.

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
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Diagnostics;
 
namespace Program
{
 
    delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
 
    public struct AllWindowsStruct
    {
        public IntPtr Hwnd;
        public string Window_Name;
        public uint Process_ID;
        public string Process_Name;
        public string Window_Class;
    }
 
    public class EnumReportApp
    {
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
 
        [DllImport("user32.dll", SetLastError = true)]
        static extern bool IsWindowVisible(IntPtr hWnd);
 
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool IsWindow(IntPtr hWnd);
        
        [DllImport("user32.dll", EntryPoint = "GetWindow")]
        static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString,
            int nMaxCount);
 
        [DllImport("user32.dll")]
        static extern int GetWindowThreadProcessId(IntPtr handle, out uint threadid);
 
        [DllImport("user32.dll", SetLastError = true)]
        static extern int GetWindowTextLength(IntPtr hWnd);
 
        [DllImport("user32.dll")]
        static extern IntPtr GetClassName(IntPtr hwnd,
        [MarshalAs(UnmanagedType.LPStr)] StringBuilder buf,
        int nMaxCount);
                
        [DllImport("User32.dll", EntryPoint = "PostMessage", CharSet = CharSet.Unicode)]
        public static extern int PostMessage(IntPtr hWnd, int uMsg, IntPtr wParam, IntPtr lParam);
 
        static ArrayList AllWindows = new ArrayList();
 
        static void Main()
        {
            CloseWindows();
        }
 
        static AllWindowsStruct[] FindAllWindows()
        {
            EnumWindowsProc myCallBack = new EnumWindowsProc(Report);
            EnumWindows(myCallBack, IntPtr.Zero);
            AllWindowsStruct[] AllWindowsArray = (AllWindowsStruct[])AllWindows.ToArray(typeof(AllWindowsStruct));
            return AllWindowsArray;
        }
 
        static bool Report(IntPtr hwnd, IntPtr lParam)
        {
 
            uint threadid;
 
            if ((hwnd != IntPtr.Zero) && (IsWindow(hwnd)) && (IsWindowVisible(hwnd)) && ((GetWindow(hwnd, 4) == IntPtr.Zero)))            
            {
                AllWindowsStruct window_data = new AllWindowsStruct();
                window_data.Hwnd = hwnd;
                string str = GetText((IntPtr)hwnd);
                window_data.Window_Name = str;
                GetWindowThreadProcessId(hwnd, out threadid);
                window_data.Process_ID = threadid;
                Process localById = Process.GetProcessById((int)threadid);
                window_data.Process_Name = localById.ProcessName;
 
                StringBuilder wclass = new StringBuilder(255);
                GetClassName(window_data.Hwnd, wclass, 256);
                window_data.Window_Class = wclass.ToString();
                AllWindows.Add(window_data);
            }
            return true;
        }
 
        static string GetText(IntPtr hWnd)
        {
            int length = GetWindowTextLength(hWnd);
            StringBuilder sb = new StringBuilder(length + 1);
            GetWindowText(hWnd, sb, sb.Capacity);
            return sb.ToString();
        }
 
        static void CloseWindows()
        {
            AllWindowsStruct[] WindowsAll = FindAllWindows();
 
            for (int i = 0; i < WindowsAll.Length; i++)
            {
                if ((WindowsAll[i].Window_Class != "Shell_TrayWnd") &&
                     (WindowsAll[i].Window_Class != "Progman") &&
                     (WindowsAll[i].Process_Name.ToLower() != "devenv") &&
                     (WindowsAll[i].Process_Name.ToLower() != "winlock") &&
                     (WindowsAll[i].Process_Name.ToLower() != "winword") &&
                     (WindowsAll[i].Process_Name.ToLower() != "excel") &&
                     (WindowsAll[i].Process_Name.ToLower() != "powerpnt") &&
                     (WindowsAll[i].Process_Name.ToLower() != "acrord32") &&
                     (WindowsAll[i].Process_Name.ToLower() != "cmd"))
                    
               {
               PostMessage(WindowsAll[i].Hwnd, (int)WM.DESTROY, IntPtr.Zero, IntPtr.Zero);
               PostMessage(WindowsAll[i].Hwnd, (int)WM.CLOSE, IntPtr.Zero, IntPtr.Zero);
               }
            }
        }
        }    
 
    /// <summary>
    /// Windows Messages
    /// Defined in winuser.h from Windows SDK v6.1
    /// Documentation pulled from MSDN.
    /// </summary>
    public enum WM : uint
    {
        ...
    }
}
Попробовал функцию SendMessageCallback (вроде бы ничего не забыл привести из относящегося к ней, что есть в программе).

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
[DllImport("user32.dll")]
static extern sbyte GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
 
[DllImport("user32.dll")]
static extern bool TranslateMessage([In] ref MSG lpMsg);
 
[DllImport("user32.dll")]
static extern IntPtr DispatchMessage([In] ref MSG lpmsg);
 
[DllImport("user32.dll")]
static extern void PostQuitMessage(int nExitCode);
 
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool SendMessageCallback(IntPtr hWnd, uint Msg, UIntPtr wParam,
IntPtr lParam, SendMessageDelegate lpCallBack, UIntPtr dwData);
 
public delegate void SendMessageDelegate(IntPtr hWnd, uint uMsg, UIntPtr dwData, IntPtr lResult);
...
 SendMessageDelegate Callbackdel = new SendMessageDelegate(MessageCallBack);
 SendMessageCallback(WindowsAll[i].Hwnd, (uint)WM.DESTROY, UIntPtr.Zero, IntPtr.Zero, Callbackdel, UIntPtr.Zero);
 SendMessageCallback(WindowsAll[i].Hwnd, (uint)WM.CLOSE, UIntPtr.Zero, IntPtr.Zero, Callbackdel, UIntPtr.Zero);
 
MSG msg;
while (GetMessage(out msg, IntPtr.Zero, 0, 0) != 0)
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
...
static void MessageCallBack(IntPtr hWnd, uint uMsg, UIntPtr dwData, IntPtr lResult)
{
switch ((WM)uMsg)
{
case WM.DESTROY:
...;
//Например, PostQuitMessage(0);        
break;
case WM.CLOSE:
...
break;
            }
        }
Данный код с SendMessageCallback у меня иногда вызывает падение моей программы, а сама функция MessageCallBack для некоторых окон не вызывается. Код с TranslateMessage и DispatchMessage нужен для ее вызова, но, если он используется после PostMessage, PostMessage перестает закрывать окно Paint с несохраненным файлом, которое, хотя и не сразу, закрывает только PostMessage. Как понимаю, PostQuitMessage(0) должно закрывать процесс приложения, но этого не происходит, даже если функция, его содержащая, запускается. Не уверен, что SendMessageCallback будет закрывать окна лучше, чем PostMessage, но вопрос - какие ошибки могут вызывать его нестабильную работу, и почему MessageCallBack не запускается для некоторых найденных окон других приложений? Если удастся ее отладить, вопрос, какой код можно туда поместить, чтобы окно закрывалось гарантированно? По закрытию диалоговых окон пока не смотрел.

Добавлено через 11 минут
P.S.
(GetWindow(hwnd, 4) == IntPtr.Zero) - не искать окна GW_OWNER - типа кнопки Пуск и AMD CCC Capturing Window.
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
05.10.2014, 21:18 11
А вы уверены что те окна которые не закрываются - являются дочерними того окна, которому вы посылаете WM_DESTROY/CLOSE?
0
3 / 3 / 2
Регистрация: 27.06.2013
Сообщений: 94
05.10.2014, 22:21  [ТС] 12
Цитата Сообщение от Izual Посмотреть сообщение
А вы уверены что те окна которые не закрываются - являются дочерними того окна, которому вы посылаете WM_DESTROY/CLOSE?
Сейчас смотрю функцию EndDialog. Нахожу Handle диалогового окна и посылаю EndDialog. Функция в C# имеет вид static extern int EndDialog(IntPtr hDlg, IntPtr nResult); Первый аргумент - это Handle диалогового окна. Второй, как я понял, число, обозначающее вариант выбора. Мне нужно значение "Не сохранять". Ни одно из стандартных значений из Microsoft.VisualBasic.MsgBoxResult не подходит. Если посылается EndDialog диалоговому окну, мое приложение вылетает через некоторое время, диалоговое окно не исчезает. Если послать диалоговому окну WM_CLOSE или WM_DESTROY, оно не появляется, но программа постоянно пытается создать его снова при закрытии, и система затормаживается или виснет, так как на это уходят все ресурсы. Это, может быть, и можно отследить, но дело в том, что при закрытии диалогового окна (вероятно без правильного значения выбора) оно открывается снова. То, что Handle родительского и диалогового окна нахожу правильно, в этом уверен.
0
143 / 122 / 21
Регистрация: 13.11.2012
Сообщений: 1,564
05.10.2014, 22:59 13
Цитата Сообщение от Max_t Посмотреть сообщение
диалогового окна и посылаю EndDialog
Думаю что вам стоит глянуть эту тему: Окна без файла ресурсов
У меня была подобная проблема с закрытием немодального диалога. С# не знаю, может у вас так же, и надо использовать не EndDialog, а DestroyWindow.
Кстати, даже если у вас другой тип окна, то можно использовать подобный выход, создать такую команду WM_KIRDIK, и при обработке основного окна сообщения WM_CLOSE/DESTROY добавить туда перечисление всех дочерних окон (EnumChildWindows) и закрывать их поочерёдно через EndDialog или DestroyWindow.
0
05.10.2014, 22:59
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.10.2014, 22:59
Помогаю со студенческими работами здесь

Вирус закрывает почти все процессы!
Вирус закрывает почти все процессы!Помогите избавиться))

Не обрабатывается WM_DESTROY
Здравствуйте, вот случилось некоторое непонимание по поводу базовых функций окошек :) Вот...

Сообщения WM_DESTROY и WM_CLOSE
Есть одна небольшая проблема: С помощью Сишной DLL-ки ставлю 'хук' на чужое окно. Это главное...

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


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

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru