Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.69/13: Рейтинг темы: голосов - 13, средняя оценка - 4.69
213 / 139 / 8
Регистрация: 18.08.2010
Сообщений: 1,018

Создать ссылку на делегат, чтобы Garbage Collector его не уничтожал

09.04.2012, 21:58. Показов 2794. Ответов 8

Студворк — интернет-сервис помощи студентам
Использую неуправляемый и управляемый код. И вот через некоторое время дебаггинга програма прерывается с ошибкой в студии:
CallbackOnCollectedDelegate was detected
Message: A callback was made on a garbage collected delegate of type 'ActiveWindowsHistory!ActiveWindowsHisto ry.Form1+WinEventDelegate::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.
Понимаю, что все дело в том, что нужно как-то сделать, чтобы в управляемом коде ссылка на этот делегат оставалась в продолжении всей жизни программы, а то этот делегат используется только в некправляемом коде, из-за чего сборшик мусора его уничтожает. Помогите так сделать, чтобы делегат не уничтожался сборщиком мусора. А то что-то никак не могу разобраться (в делегатах путаюсь, хоть и пристально читал в книжках о них, из-за этого проблемы с ними...)

Как этот WinEventDelegate присобачить...

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
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
 
namespace ActiveWindowsHistory
{
    public partial class Form1 : Form
    {
        delegate void WinEventDelegate(IntPtr hWinEventHook,
            uint eventType, IntPtr hwnd, int idObject,
            int idChild, uint dwEventThread, uint dwmsEventTime);
 
        const uint WINEVENT_OUTOFCONTEXT = 0;
        const uint EVENT_SYSTEM_FOREGROUND = 3;
 
        [DllImport("user32.dll")]
        static extern bool UnhookWinEvent(IntPtr hWinEventHook);
        [DllImport("user32.dll")]
        static extern IntPtr SetWinEventHook(uint eventMin,
            uint eventMax, IntPtr hmodWinEventProc,
            WinEventDelegate lpfnWinEventProc, uint idProcess,
            uint idThread, uint dwFlags);
        [DllImport("user32.dll")]
        static extern int GetWindowText(IntPtr hWnd,
            StringBuilder lpString, int nMaxCount);
 
        ListBox m_list;
        IntPtr m_hhook;
 
        public Form1()
        {
            InitializeComponent();
            m_list = new ListBox();
            m_list.IntegralHeight = false;
            m_list.Dock = DockStyle.Fill;
            Controls.Add(m_list);
 
            Text = "SetWinEventHook Example";
 
            Load += new EventHandler(Program_Load);
            FormClosing +=
                new FormClosingEventHandler(Program_FormClosing);
        }
 
        void Program_Load(object sender, EventArgs e)
        {
            m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
                EVENT_SYSTEM_FOREGROUND, IntPtr.Zero,
                WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
        }
 
        void WinEventProc(IntPtr hWinEventHook, uint eventType,
            IntPtr hwnd, int idObject, int idChild,
            uint dwEventThread, uint dwmsEventTime)
        {
            if (eventType == EVENT_SYSTEM_FOREGROUND)
            {
                StringBuilder sb = new StringBuilder(500);
                GetWindowText(hwnd, sb, sb.Capacity);
 
                m_list.Items.Insert(0,
                    "Switched to: " + sb.ToString());
            }
        }
 
        void Program_FormClosing(
            object sender, FormClosingEventArgs e)
        {
            UnhookWinEvent(m_hhook);
        }
    }
}
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
09.04.2012, 21:58
Ответы с готовыми решениями:

Как сделать, чтобы garbage collector быстрее проходил?
как сделать, чтобы garbage collector быстрее проходил? Если возможно на примере :)

Garbage collector
как можно просимулировать Garbage collector (написать программу в C#) ?

CLR и Garbage Collector
всем доброго времени суток! Если не вызывать GC.Collect() то среда CLR автоматически убирает мусор! предположим что у нас открыто...

8
Неадекват
 Аватар для freeba
1501 / 1237 / 248
Регистрация: 02.04.2010
Сообщений: 2,807
10.04.2012, 00:45
А объявить делегат в неуправляемом коде религия не позволяет? Все что находиться в блоке unsafe сборщик мусора не трогает.

Ну или можно GC.KeepAlive(объект на который нужна ссылка) юзать.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
10.04.2012, 01:05
Tolias28, создайте ссылку на делегат в теле класса или используйте структуру GCHandle - она специально для этого создана. Правда, ее тоже надо будет в теле класса создать для последующего освобождения.

Цитата Сообщение от freeba Посмотреть сообщение
Все что находиться в блоке unsafe сборщик мусора не трогает.
С чего это вдруг? Блок unsafe всего лишь позволяет выполняться некоторым инструкциям в неуправляемом контексте.

Цитата Сообщение от freeba Посмотреть сообщение
Ну или можно GC.KeepAlive(объект на который нужна ссылка) юзать.
GC.KeepAlive, к сожалению, работает только в контексте текущего метода. После завершения этого метода объект все равно может быть подчищен сборщиком.
0
Неадекват
 Аватар для freeba
1501 / 1237 / 248
Регистрация: 02.04.2010
Сообщений: 2,807
10.04.2012, 13:55
Мда, нехорошо получилось, действительно собирает и в небезопасном коде. В голове кавардак
0
213 / 139 / 8
Регистрация: 18.08.2010
Сообщений: 1,018
10.04.2012, 15:28  [ТС]
Цитата Сообщение от kolorotur Посмотреть сообщение
Tolias28, создайте ссылку на делегат в теле класса или используйте структуру GCHandle
Так дело в том, что я знаю, что нужно создать ссылку в теле класса! Я не знаю как именно ее создать И был бы очень благодарен увидеть код, как именно это делается, если можно...)
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
10.04.2012, 15:31
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
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
 
namespace ActiveWindowsHistory
{
    public partial class Form1 : Form
    {
        delegate void WinEventDelegate(IntPtr hWinEventHook,
            uint eventType, IntPtr hwnd, int idObject,
            int idChild, uint dwEventThread, uint dwmsEventTime);
 
        GCHandle hnd;
        
        ...
 
        public Form1()
        {
            ...
 
            Load += new EventHandler(Program_Load);
            FormClosingEventHandler handler = new FormClosingEventHandler(Program_FormClosing);
            FormClosing += handler;
            hnd = GCHandle.Alloc(handler);
        }
 
        ...
 
        void Program_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnhookWinEvent(m_hhook);
            hnd.Free();
        }
    }
}
1
213 / 139 / 8
Регистрация: 18.08.2010
Сообщений: 1,018
10.04.2012, 17:22  [ТС]
kolorotur, спасибо! Но... я внес указанные вами изменения и по прежнему через некоторое время появляется тоже самое сообщение CallbackOnCollectedDelegate was detected

Вот измененный код
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
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
 
namespace ActiveWindowsHistory
{
    public partial class Form1 : Form
    {
        delegate void WinEventDelegate(IntPtr hWinEventHook,
            uint eventType, IntPtr hwnd, int idObject,
            int idChild, uint dwEventThread, uint dwmsEventTime);
 
        GCHandle hnd;
 
        const uint WINEVENT_OUTOFCONTEXT = 0;
        const uint EVENT_SYSTEM_FOREGROUND = 3;
 
        [DllImport("user32.dll")]
        static extern bool UnhookWinEvent(IntPtr hWinEventHook);
        [DllImport("user32.dll")]
        static extern IntPtr SetWinEventHook(uint eventMin,
            uint eventMax, IntPtr hmodWinEventProc,
            WinEventDelegate lpfnWinEventProc, uint idProcess,
            uint idThread, uint dwFlags);
        [DllImport("user32.dll")]
        static extern int GetWindowText(IntPtr hWnd,
            StringBuilder lpString, int nMaxCount);
 
        ListBox m_list;
        IntPtr m_hhook;
 
        public Form1()
        {
            InitializeComponent();
            m_list = new ListBox();
            m_list.IntegralHeight = false;
            m_list.Dock = DockStyle.Fill;
            Controls.Add(m_list);
 
            Text = "SetWinEventHook Example";
 
            Load += new EventHandler(Program_Load);
            FormClosingEventHandler handler = new FormClosingEventHandler(Program_FormClosing);
            FormClosing += handler;
            hnd = GCHandle.Alloc(handler);
        }
 
        void Program_Load(object sender, EventArgs e)
        {
            m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
                EVENT_SYSTEM_FOREGROUND, IntPtr.Zero,
                WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
        }
 
        void WinEventProc(IntPtr hWinEventHook, uint eventType,
            IntPtr hwnd, int idObject, int idChild,
            uint dwEventThread, uint dwmsEventTime)
        {
            if (eventType == EVENT_SYSTEM_FOREGROUND)
            {
                StringBuilder sb = new StringBuilder(500);
                GetWindowText(hwnd, sb, sb.Capacity);
 
                m_list.Items.Insert(0, sb.ToString());
            }
        }
 
        void Program_FormClosing(
            object sender, FormClosingEventArgs e)
        {
            UnhookWinEvent(m_hhook);
            hnd.Free();
        }
    }
}
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
10.04.2012, 17:29
Тьфу ты елки-палки, это я в примере накосячил - не тот делегат прицепил
Надо было так сделать:

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
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
 
namespace ActiveWindowsHistory
{
    public partial class Form1 : Form
    {
        delegate void WinEventDelegate(IntPtr hWinEventHook,
            uint eventType, IntPtr hwnd, int idObject,
            int idChild, uint dwEventThread, uint dwmsEventTime);
 
        GCHandle hnd;
        ...
        void Program_Load(object sender, EventArgs e)
        {
            WinEventDelegate handler = new WinEventDelegate(WinEventProc);
            m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
                EVENT_SYSTEM_FOREGROUND, IntPtr.Zero,
                handler, 0, 0, WINEVENT_OUTOFCONTEXT);
            hnd = GCHandle.Alloc(handler);
        }
        ...
        void Program_FormClosing(
            object sender, FormClosingEventArgs e)
        {
            UnhookWinEvent(m_hhook);
            hnd.Free();
        }
    }
}
Приношу свои извинения.
1
213 / 139 / 8
Регистрация: 18.08.2010
Сообщений: 1,018
10.04.2012, 17:38  [ТС]
я даже понял, почему проблема не исчезла... Потому что проблемный объект, из-за которого возникает это сообщение, это не FormClosingEventHandler, для которого вы использовали GCHandle... Проблема возникает из-за уничтоженного делегата WinEventDelegate... Я пробовал делать вот так:
C#
1
hndWinEventDelegate = GCHandle.Alloc(WinEventDelegate);
но среда ругается я тип использую как переменную ((

Добавлено через 1 минуту
о, вы уже ответили Спасибо, сейчас попробую

Добавлено через 5 минут
kolorotur, огромное спасибо за помощь! Все работает!)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.04.2012, 17:38
Помогаю со студенческими работами здесь

Режимы Garbage Collector
Добрый день. Че-т не могу найти ответы на эти вопросы :) Какие есть режимы GC и как указать JVM какой режим использовать? Как при...

Посмотреть какой Garbage Collector выбран по умолчанию
Как узнать какой Garbage Collector выбран по умолчанию ? В командную строку пишу: java -XX:+PrintCommandLineFlags -version ...

когда есть смысл вручную вызывать Garbage collector
когда есть смысл вручную вызывать Garbage collector?

Кто может кратко объясните как работает Garbage Collector?
кто может кратко объясните как работает Garbage Collector?

Делегат, как вызвать ссылку на функцию в Мейне
Пробую работу с делегатами. Немного не пойму, как с ними работать. Если пишу все в одном классе(методы static), работает. Создаю отдельный...


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

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru