Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
0 / 0 / 0
Регистрация: 23.04.2023
Сообщений: 3

Сборщик мусора удаляет делегат в неуправляемой памяти

23.04.2023, 19:50. Показов 665. Ответов 11

Студворк — интернет-сервис помощи студентам
Есть следующий код класса, направленный на запрет закрытия окна определенными комбинациями клавиш:

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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
public class LowLevelKeyboardHook
    {
        private const int WH_KEYBOARD_LL = 13;
 
        [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
 
        private struct KBDLLHOOKSTRUCT
        {
            public Keys key;
        }
 
        private LowLevelKeyboardProcDelegate m_callback;
        private LowLevelKeyboardProcDelegate m_callback_1;
        private LowLevelKeyboardProcDelegate m_callback_2;
        private LowLevelKeyboardProcDelegate m_callback_3;
        private LowLevelKeyboardProcDelegate m_callback_4;
        private LowLevelKeyboardProcDelegate m_callback_5;
        private LowLevelKeyboardProcDelegate m_callback_6;
        private LowLevelKeyboardProcDelegate m_callback_7;
        private LowLevelKeyboardProcDelegate m_callback_8;
 
        private IntPtr m_hHook;
        private IntPtr m_hHook_1;
        private IntPtr m_hHook_2;
        private IntPtr m_hHook_3;
        private IntPtr m_hHook_4;
        private IntPtr m_hHook_5;
        private IntPtr m_hHook_6;
        private IntPtr m_hHook_7;
        private IntPtr m_hHook_8;
 
        [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProcDelegate lpfn, IntPtr hMod, int dwThreadId);
 
        [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
 
        [System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true)]
        private static extern IntPtr GetModuleHandle(IntPtr lpModuleName);
 
        [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
 
        public IntPtr LowLevelKeyboardHookProc_win(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                switch (objKeyInfo.key)
                {
                    case Keys.RWin:
                    case Keys.LWin:
                        return (IntPtr)1;
                }
            }
            return CallNextHookEx(m_hHook_1, nCode, wParam, lParam);
        }
 
        public IntPtr LowLevelKeyboardHookProc_del(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
 
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                if (objKeyInfo.key == Keys.Delete)
                {
                    return (IntPtr)1;
                }
            }
            return CallNextHookEx(m_hHook_3, nCode, wParam, lParam);
        }
 
        public IntPtr LowLevelKeyboardHookProc_ctrl(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                switch (objKeyInfo.key)
                {
                    case Keys.RControlKey:
                    case Keys.LControlKey:
                        return (IntPtr)1;
                }
            }
            return CallNextHookEx(m_hHook_2, nCode, wParam, lParam);
        }
 
        public IntPtr LowLevelKeyboardHookProc_alt(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                if (objKeyInfo.key == Keys.Alt)
                {
                    return (IntPtr)1;
                }
            }
            return CallNextHookEx(m_hHook_4, nCode, wParam, lParam);
        }
 
        public IntPtr LowLevelKeyboardHookProc_alt_tab(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                switch (objKeyInfo.key)
                {
                    case Keys.Alt:
                    case Keys.Tab:
                        return (IntPtr)1;
                }
            }
            return CallNextHookEx(m_hHook, nCode, wParam, lParam);
        }
 
        public IntPtr LowLevelKeyboardHookProc_alt_space(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                switch (objKeyInfo.key)
                {
                    case Keys.Alt:
                    case Keys.Space:
                        return (IntPtr)1;
                }
            }
            return CallNextHookEx(m_hHook_5, nCode, wParam, lParam);
        }
 
        public IntPtr LowLevelKeyboardHookProc_control_shift_escape(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                switch (objKeyInfo.key)
                {
                    case Keys.LControlKey:
                    case Keys.RControlKey:
                    case Keys.LShiftKey:
                    case Keys.RShiftKey:
                    case Keys.Escape:
                        return (IntPtr)1;
                }
            }
            return CallNextHookEx(m_hHook_6, nCode, wParam, lParam);
        }
 
        public IntPtr LowLevelKeyboardHookProc_control_alt_del(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                switch (objKeyInfo.key)
                {
                    case Keys.LControlKey:
                    case Keys.Alt:
                    case Keys.Delete:
                        return (IntPtr)1;
                }
            }
            return CallNextHookEx(m_hHook_7, nCode, wParam, lParam);
        }
 
        public IntPtr LowLevelKeyboardHookProc_alt_f4(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                switch (objKeyInfo.key)
                {
                    case Keys.Alt:
                    case Keys.F4:
                        return (IntPtr)1;
                }
            }
            return CallNextHookEx(m_hHook_8, nCode, wParam, lParam);
        }
 
        private delegate IntPtr LowLevelKeyboardProcDelegate(int nCode, IntPtr wParam, IntPtr lParam);
 
        public void SetHook()
        {
            m_callback = LowLevelKeyboardHookProc_win;
            m_callback_1 = LowLevelKeyboardHookProc_alt_tab;
            m_callback_2 = LowLevelKeyboardHookProc_ctrl;
            m_callback_3 = LowLevelKeyboardHookProc_del;
            m_callback_4 = LowLevelKeyboardHookProc_alt;
            m_callback_5 = LowLevelKeyboardHookProc_alt_space;
            m_callback_6 = LowLevelKeyboardHookProc_control_shift_escape;
            m_callback_7 = LowLevelKeyboardHookProc_control_alt_del;
            m_callback_8 = LowLevelKeyboardHookProc_alt_f4;
 
            m_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_1 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_1, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_2 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_2, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_3 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_3, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_4 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_4, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_5 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_5, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_6 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_6, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_7 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_7, GetModuleHandle(IntPtr.Zero), 0);
            m_hHook_8 = SetWindowsHookEx(WH_KEYBOARD_LL, m_callback_8, GetModuleHandle(IntPtr.Zero), 0);
        }
 
        public void Unhook()
        {
            UnhookWindowsHookEx(m_hHook);
            UnhookWindowsHookEx(m_hHook_1);
            UnhookWindowsHookEx(m_hHook_2);
            UnhookWindowsHookEx(m_hHook_3);
            UnhookWindowsHookEx(m_hHook_4);
            UnhookWindowsHookEx(m_hHook_5);
            UnhookWindowsHookEx(m_hHook_6);
            UnhookWindowsHookEx(m_hHook_7);
            UnhookWindowsHookEx(m_hHook_8);
        }
    }
Но во время работы периодически возникает ошибка:

"CallbackOnCollectedDelegate" : "Был произведен обратный вызов делегата типа "ExamTool v0.2!ExamTool_v0._2.LowLevelKeyboardHook +LowLevelKeyboardProcDelegate::Invoke", полученного сборщиком мусора. Это может привести к сбоям приложения, а также к повреждению или утрате данных. При передаче делегатов в неуправляемый код управляемое приложение должно поддерживать их существование, пока не будет гарантировано, что они больше никогда не будут вызваны."

Код не мой, работаю над проектом для колледжа, абсолютно не представляю, как исправить проблему
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
23.04.2023, 19:50
Ответы с готовыми решениями:

Сборщик мусора не удаляет объект
Сборщик мусора не удаляет объект. Мне необходимо чтобы GC его удалил, но этого не происходит. Привожу предельно упрощенный код моей...

Сборщик мусора удаляет нужные объекты
Добрый день. Есть класс, в котором запускается мультимедийный таймер из библиотеки winmm.dll. При попытке сборки мусора приложение...

Рациональное использование памяти, сборщик мусора
Задача определить такую структуру данных: Entity - Мешок для компонентов. Есть массив фиксированных компонентов. Это означает, что эти...

11
sleep
 Аватар для I can
4930 / 4589 / 840
Регистрация: 13.04.2015
Сообщений: 9,739
23.04.2023, 20:04
Цитата Сообщение от JohnMellor Посмотреть сообщение
private delegate IntPtr LowLevelKeyboardProcDelegate(int nCode, IntPtr wParam, IntPtr lParam);
попробуй сделать его public
0
Администратор
Эксперт .NET
 Аватар для OwenGlendower
18273 / 14196 / 5368
Регистрация: 17.03.2014
Сообщений: 28,881
Записей в блоге: 1
23.04.2023, 20:29
JohnMellor, думаю если добавить такой блок в Unhook, то сборщик мусора не будет собирать делегаты.
C#
1
2
3
4
5
6
7
8
9
        m_callback   = null;
        m_callback_1 = null;
        m_callback_2 = null;
        m_callback_3 = null;
        m_callback_4 = null;
        m_callback_5 = null;
        m_callback_6 = null;
        m_callback_7 = null;
        m_callback_8 = null;
Объяснение: сейчас переменные используются только в одном методе и GC похоже считает что они только там и нужны. И поэтому удаляет их как ненужные.

Еще не помешало бы IDisposable с финализатором реализовать.
0
0 / 0 / 0
Регистрация: 23.04.2023
Сообщений: 3
23.04.2023, 21:37  [ТС]
К сожалению, не помогло. На форме, где вызывается метод SetHook(), есть текстовое поле ToolStripTextBox, куда пользователь может ввести пароль, и специальная кнопка, по нажатию на которую (при правильном введенном пароле), форма закрывается.
Ошибка возникает как раз при вводе пароля в поле, причем далеко не сразу, а только после нескольких вводов/удаления неправильных вариантов.

Добавлено через 46 секунд
Опять-таки, увы, не помогло...
0
Администратор
Эксперт .NET
 Аватар для OwenGlendower
18273 / 14196 / 5368
Регистрация: 17.03.2014
Сообщений: 28,881
Записей в блоге: 1
23.04.2023, 21:40
Цитата Сообщение от JohnMellor Посмотреть сообщение
На форме, где вызывается метод SetHook(), есть текстовое поле ToolStripTextBox, куда пользователь может ввести пароль, и специальная кнопка, по нажатию на которую (при правильном введенном пароле), форма закрывается.
А экземпляр LowLevelKeyboardHook где создается и хранится? Внутри этой формы или где-то в другом месте?
0
0 / 0 / 0
Регистрация: 23.04.2023
Сообщений: 3
23.04.2023, 21:53  [ТС]
В следующем методе, который вызывается в событии загрузки формы:

C#
1
2
3
4
5
private void SetHook()
        {
            LowLevelKeyboardHook lowLevelKeyboardHook = new LowLevelKeyboardHook();
            lowLevelKeyboardHook.SetHook();
        }
0
Администратор
Эксперт .NET
 Аватар для OwenGlendower
18273 / 14196 / 5368
Регистрация: 17.03.2014
Сообщений: 28,881
Записей в блоге: 1
23.04.2023, 22:17
JohnMellor, вы помните какое время жизни у локальной переменной и когда сборщик мусора может её удалить? А вместе с ней и все поля.
0
61 / 186 / 31
Регистрация: 14.02.2013
Сообщений: 1,695
23.04.2023, 22:40
интересно так выходит сборщик мусора может любой делегат выгрузить из памяти если к нему нет обращений? Сделать тогда через небольшой промежуток времени какое нибудь обращение у делегату?
0
Эксперт .NET
6691 / 4102 / 1607
Регистрация: 09.05.2015
Сообщений: 9,574
23.04.2023, 23:21
Во первых не понятно зачем столько раз хукать, если можно все комбинации проверить в одном...

Ну и экземпляр вашего класса нужно сохранить в каком нибудь поле, чтобы его GC не собрал вместе с вашими делегатами...

C#
1
2
3
4
5
6
7
8
9
10
class SomeClass
{
    private LowLevelKeyboardHook lowLevelKeyboardHook;
 
    private void SetHook()
    {
        lowLevelKeyboardHook = new LowLevelKeyboardHook();
        lowLevelKeyboardHook.SetHook();
    }
}
0
24.04.2023, 06:27

Не по теме:

Цитата Сообщение от JohnMellor Посмотреть сообщение
LowLevelKeyboardHookProc_control_alt_del ;
занятно... вроде винде пофиг на перехват этой комбинации и всегда уходит в отображение окна выбора действия для системы

0
24.04.2023, 07:42

Не по теме:

Цитата Сообщение от JohnMellor Посмотреть сообщение
работаю над проектом для колледжа
Винлокер?

0
24.04.2023, 08:54

Не по теме:

Цитата Сообщение от I can Посмотреть сообщение
Винлокер?
На winforms? Тогда автор из самых что не на есть трушных хацкеров, прям породистых с родословной. Но вообще соглашусь -- список блокируемых сочетаний наводит на мысль что это какой-то зловред.

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
24.04.2023, 08:54
Помогаю со студенческими работами здесь

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

Сборщик мусора удаляет объекты в порядке их создания, а не в обратном
Python сборщик удаляет объекты классов когда на них не остается ссылок. Но делает это он, к сожалению, в прямом порядке, не в обратном,...

Сборщик мусора
Доброго вам времени суток! У меня вопрос можно ли автоматизировать удаление объектов размещаемых в куче? (Желательно обойтись только STL).

Сборщик мусора
Соберет ли сборщик мусора поля объекта C, такие как "a" и "b", или же нужно самому в явной форме ставить null каждому полю (допустим, в...

Сборщик мусора
Собственно у меня вопрос более теоретический. В AS 3.0 есть сборщик мусора, благодаря которому мы имеем грамотное распределение памяти и...


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

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
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, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru