powered by simpleCommunicator - 2.0.56     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
10 сообщений из 10, страница 1 из 1
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38430556
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Меня учили :
AntonariyСабклассинг нужно снимать всегда.
Дмитрий77Почему?
Если честно, почти никогда этого не делаю.
Какие последствия?C одним из них ты уже столкнулся. Другое — критические ошибки.
Я научился:
Код: vbnet
1.
2.
3.
Private Sub Form_Unload(Cancel As Integer)
  'снятие сабклассинга
  SetWindowLong Me.hwnd, GWL_WNDPROC, OldFormMeWindowProc



В процессе освоения .NET я УДЕЛИЛ ДАННОМУ ВОПРОСУ БОЛЬШОЕ ВНИМАНИЕ и задал вопрос ПО СУЩЕСТВУ.

Дмитрий77 Вопрос 2.
Сабклассинг снимать надо?
И правильно ли я это делаю?

Код: vbnet
1.
2.
3.
4.
  Private Sub Form1_FormClosed(ByVal sender As Object,
   ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
    'снятие сабклассинга ??????????
    s1.ReleaseHandle()


Мне конкретно по этому моменту никто толком ничего не ответил.

У меня возникла проблема с использованием Tooltip1 на Listview1 :
InvalidOperationException
Попытка доступа к элементу управления 'ListView1' не из того потока в кот. он был создан
Сообщение m = WM_CLOSE

Я НАКОНЕЦ ДОКОПАЛСЯ:
Минимальный код примера на котором ПРОБЛЕМА ВОСПРОИЗВОДИТСЯ (см. тест-проект во вложении):
Код: vbnet
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.
Public Class Form1

  Dim s_ListView As SubclassHWND

  Private Sub ListView1_MouseEnter(ByVal sender As Object,
                                   ByVal e As System.EventArgs) Handles ListView1.MouseEnter
    ToolTip1.SetToolTip(ListView1, "My Tooltip is")
  End Sub

  Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    'сабклассим(ListView1 - сам)
    s_ListView = New SubclassHWND()
    s_ListView.AssignHandle(ListView1.Handle)
  End Sub

  Private Sub Form1_FormClosed(ByVal sender As Object,
   ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
    'снятие сабклассинга
    s_ListView.ReleaseHandle()
  End Sub

End Class

Public Class SubclassHWND
  Inherits NativeWindow
End Class



Для воспроизведения проблемы надо:
1) создать проект, кинуть на форму ListView1 и Tooltip1
2) вставить мой код в Form1
3) запустить проект
4) навести мышку на Listview чтобы отобразилось примечание
5) закрыть форму

ВСЕ.
Ошибка очевидно в том КАК и ГДЕ я снимаю сабклассинг:
Код: vbnet
1.
2.
3.
4.
5.
  Private Sub Form1_FormClosed(ByVal sender As Object,
   ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
    'снятие сабклассинга
    s_ListView.ReleaseHandle()
  End Sub



Вопросы:
1) Сабклассинг снимать надо?
2) ГДЕ И КАК это сделать?
...
Рейтинг: 0 / 0
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38430651
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Мне конкретно по этому моменту никто толком ничего не ответил.
неправда Объясните мне как делать сабклассинг нескольких контролов в .Net
...
Рейтинг: 0 / 0
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38431324
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ИзопропилДмитрий77Мне конкретно по этому моменту никто толком ничего не ответил.
неправда Объясните мне как делать сабклассинг нескольких контролов в .Net
Не, я видел. Я не в потолок смотрю.
Я еще в документацию смотрел (пример) -там примерно тоже самое.
А давай на мой код конкретно смотреть.
Вот мой класс (чуть переделанный глядючи на твой код и на пример из документации):
Код: vbnet
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.
Public Class SubclassHWND
  Inherits NativeWindow

  'Event Declaration. This event will be raised when any  
  'Message will be posted to the Control
  Public Event CallBackWndProc(ByRef m As Message, ByRef Cancel As Boolean)

  Private parent As Control

  Public Sub New(ByVal parent As Control)

    AddHandler parent.HandleCreated, AddressOf Me.OnHandleCreated
    AddHandler parent.HandleDestroyed, AddressOf Me.OnHandleDestroyed
    Me.parent = parent
  End Sub

  ' Listen for the control's window creation and hook into it.    
  Private Sub OnHandleCreated(ByVal sender As Object, ByVal e As EventArgs)
    ' Window is now created, assign handle to NativeWindow.
    AssignHandle(CType(sender, Control).Handle)
    Debug.WriteLine("OnHandleCreated")
  End Sub

  Private Sub OnHandleDestroyed(ByVal sender As Object, ByVal e As EventArgs)
    ' Window was destroyed, release hook.
    ReleaseHandle()
    Debug.WriteLine("OnHandleDestroyed")
  End Sub


  <System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
  Protected Overloads Overrides Sub WndProc(ByRef m As Message)
    Dim Cancel As Boolean = False 'по умолчанию обрабатывать сообщение
    RaiseEvent CallBackWndProc(m, Cancel)

    ' если обрабатываем (cancel=False), то forward message to base WndProc
    If Not Cancel Then MyBase.WndProc(m)

  End Sub

End Class



Очень удобно, когда окно (ListView) сабклассится, я получаю все его Msg в s_ListView_CallBackWndProc

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
  Private WithEvents s_ListView As SubclassHWND

  Private Sub s_ListView_CallBackWndProc(ByRef m As System.Windows.Forms.Message,
   ByRef Cancel As Boolean) Handles s_ListView.CallBackWndProc
    Debug.WriteLine(m.ToString)
    Select Case m.Msg
      Case Else
    End Select
  End Sub



А теперь я хочу сделать 2 кнопки:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
  Private Sub ButtonSubclass_Click(ByVal sender As System.Object,
                                   ByVal e As System.EventArgs) Handles ButtonSubclass.Click
    'здесь хочу ВКЛЮЧИТЬ сабклассинг ListView 1 и ПОЛУЧАТЬ Msg в s_ListView_CallBackWndProc
    s_ListView = New SubclassHWND(ListView1) 'ЭТОГО НЕдостаточно!!!
    s_ListView.AssignHandle(ListView1.Handle)
  End Sub

  Private Sub ButtonUnSubclass_Click(ByVal sender As System.Object,
                                     ByVal e As System.EventArgs) Handles ButtonUnSubclass.Click
    'здесь хочу ВЫКЛЮЧИТЬ сабклассинг ListView 1 и НЕ ПОЛУЧАТЬ Msg в s_ListView_CallBackWndProc
    ''снятие сабклассинга
    s_ListView.ReleaseHandle() 'ЭТО ПРИВОДИТ К ПРОБЛЕМАМ!!!
  End Sub



И что ты думаешь, я не понимаю в чем засада?

Идея такого класса понятна:
Класс тупо привязывается к родному Control.

Т.е. когда ListView1 делает parent.HandleCreated, класс вызывает OnHandleCreated и делает AssignHandle(ListView1.Handle)
Но на момент ButtonSubclass_Click мне это бесполезно, т.к. parent.HandleCreated уже давно в прошлом.
Я не хочу лазить в дизайнеры и привязывать
s_ListView = New SubclassHWND(ListView1) на этапе создания ListView
(как это здесь делается )
У меня есть Form_Load и (условно) ButtonSubclass_Click (где я могу и хочу это сделать).

Аналогично, со снятием.
Опять же, я понимаю, что этот класс тупо ловит parent.HandleDestroyed и автоматически снимает сабклассинг в
Sub OnHandleDestroyed делая ReleaseHandle()
Тогда да, ничего не ругается.

Ну я например хочу снять сабклассинг раньше, в ButtonUnSubclass_Click.

Вопросы:
1. что мне переделать в МОЕМ коде чтоб УСТАНАВЛИВАТЬ САБКЛАССИНГ в ButtonSubclass_Click (когда я этого хочу)?
2. что мне переделать в МОЕМ коде чтоб СНИМАТЬ САБКЛАССИНГ в ButtonSubclass_Click (когда я этого хочу)?


В VB6 аналогичный вопрос решаем так:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Public OldListview1WindowProc As Long

Private Sub CommandSubclass_Click()
  OldListview1WindowProc = SetWindowLong( _
   Listview1.hwnd, GWL_WNDPROC, _
   AddressOf NewListview1WindowProc)
End Sub
Private Sub CommandUnSubclass_Click()
  SetWindowLong Listview1.hwnd, GWL_WNDPROC, OldListview1WindowProc
End Sub



Не, ребят, ну объясните что переделать
Я в ваших хитрожопых классах человек новый.
1) Установить сабклассинг (в любой момент)
2) Снять сабклассинг (в любой момент)
И чтоб ничего не глючило при этом.

М.б. тупо забабахать SetWindowLong и CallWindowProc? И не сомневаюсь что это будет работать без глюков.
Но хочется все-таки как здесь принято сделать.
Просто в каждом посте тыкаете на БОЛЬШУЮ КУЛИНАРНУЮ КНИГУ, причем я так понял обязательно читать ее всю (1000 страниц) и прямо сейчас, а это если честно уже достало.
Что мне конкретно надо я объяснил выше.
...
Рейтинг: 0 / 0
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38431575
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Короче этот метод сабклассинга без хитрожопостей умностей внутри класса и влезания в дизайнер формы стандартного проекта правильно готовится так:

Код: vbnet
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.
  Private WithEvents s_ListView As SubclassHWND

  Private Sub ListView1_HandleCreated(ByVal sender As Object,
   ByVal e As System.EventArgs) Handles ListView1.HandleCreated
    s_ListView = New SubclassHWND()
    s_ListView.AssignHandle(ListView1.Handle)
  End Sub

  Private Sub ListView1_HandleDestroyed(ByVal sender As Object,
   ByVal e As System.EventArgs) Handles ListView1.HandleDestroyed
    s_ListView.ReleaseHandle()
  End Sub

  Private Sub s_ListView_CallBackWndProc(ByRef m As System.Windows.Forms.Message,
   ByRef Cancel As Boolean) Handles s_ListView.CallBackWndProc
    'Debug.WriteLine(m.ToString)
    Select Case m.Msg
      Case Else
    End Select
  End Sub


Public Class SubclassHWND
  Inherits NativeWindow

  'Event Declaration. This event will be raised when any  
  'Message will be posted to the Control
  Public Event CallBackWndProc(ByRef m As Message, ByRef Cancel As Boolean)

  Protected Overloads Overrides Sub WndProc(ByRef m As Message)
    Dim Cancel As Boolean = False 'по умолчанию обрабатывать сообщение
    RaiseEvent CallBackWndProc(m, Cancel)

    ' если обрабатываем (cancel=False), то forward message to base WndProc
    If Not Cancel Then MyBase.WndProc(m)

  End Sub

End Class



И в этом виде я могу применять класс как к .Net контролам, так и к API-контролам,
потому как контрол не обязательно создан в чудо-Control-Net-дизайнере, а может быть API-шным.

Но нерешенным остается вопрос с ключевым словом КОГДА Я ЭТОГО ХОЧУ
особенно применительно к вопросу как СНИМАТЬ САБКЛАССИНГ.
Т.е. ВОПРОС ОСТАЕТСЯ


Потому что ВКЛЮЧАТЬ САБКЛАССИНГ очевидно таким образом можно в любой момент.

А вот БЕЗОБИДНО снять сабклассинг по этому методу может не получиться.

В принципе мне этого по идее пока должно хватить, хотя исходя из опыта не уверен.

Ну, и как говорится некая непонятка с сабклассингом API-контролов по этому методу -напр. мой пример с hwndHelp.
(API-контрол не предоставляет событий HandleCreated и HandleDestroyed в которые по хорошему надо втыкать AssignHandle и ReleaseHandle чтоб избежать проблем)
...
Рейтинг: 0 / 0
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38432123
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А кто нибудь может мне внятно ответить?
НА ХРЕНА его вообще снимать В КОНЦЕ?

Хоть по кулинарному?
ИзопропилИзопропил,

вот такой говнокод получше видимо будет
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
    public class SubWindow:NativeWindow
...
        public SubWindow(Control c, SubWindowFunc wf)
...
            control.HandleDestroyed += control_HandleDestroyed;
...       
        void control_HandleDestroyed(object sender, EventArgs e)
        {
            this.ReleaseHandle();
        }
    }


Хоть по простому?
Код: vbnet
1.
2.
3.
4.
  Private Sub ListView1_HandleDestroyed(ByVal sender As Object,
   ByVal e As System.EventArgs) Handles ListView1.HandleDestroyed
    s_ListView.ReleaseHandle()
  End Sub



Тогда как в вашей же кулинарной книге (вернее в документации Майкрософт):
NativeWindow.ReleaseHandle Method
НАПИСАНО:A window automatically calls this method if it receives a native Win32 WM_NCDESTROY message, indicating that Windows has destroyed the handle.
Отсюда вывод, что для API-hwnd сабклассинг в конце можно не снимать (ReleaseHandle не делать).
Да и для Net контролов зачем это делать.
Или имеется ввиду что стрипы не являясь native Win32 Window не получают native Win32 WM_NCDESTROY message?
На хрена ReleaseHandle в конце делать если он автоматически делается?

Но при этом ВОПРОС ОТКРЫТЫЙ:
НАПИСАНОThis method does not destroy the window handle. Instead, it sets the handle's window procedure to the default window procedure . It sets the Handle property to 0 and calls OnHandleChange to reflect the change.
Т.е. для того чтобы снять сабклассинг КОГДА Я ХОЧУ
( sets the handle's window procedure to the default window procedure )
выполнить
Код: vbnet
1.
s_ListView.ReleaseHandle()


законно в любом месте кода (согласно документации) и не должно приводить к проблемам.
Но ПРИВОДИТ как видим из приведенного примера с тултип.
...
Рейтинг: 0 / 0
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38432160
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И...и...и как все плохо
Я понял зачем эти предусмотрительные заглушки,
Код: plaintext
1.
2.
            control.HandleDestroyed += control_HandleDestroyed;
            control.HandleCreated += control_HandleCreated;            

боюсь дядя Рихтер не поможет.
Дело не в кулинарии, а попорченном мясе, здесь марганцовка блин нужна и много.
Дальше веселее.

Мне надо установить API -image лист (потому что Net imagelist слегка глючный), но чтобы он не перерисовывался контролом, надо сделать сабклассинг, но начинать сабклассинг надо только ПОСЛЕ установки API-Image-листа. Т.е. вот так:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
    'привязка ImageList m_LViml к ListView1
    Call SendMessage(ListView1.Handle, LVM_SETIMAGELIST, LVSIL_SMALL, m_LViml)
    
'И ТОЛЬКО ПОСЛЕ ЭТОГО!!!
    'сабклассим
    s_ListView = New SubclassHWND()
    s_ListView.AssignHandle(ListView1.Handle)


  Private Sub s_ListView_CallBackWndProc(ByRef m As System.Windows.Forms.Message, ByRef Cancel As Boolean) _
   Handles s_ListView.CallBackWndProc
    Select Case m.Msg
      Case LVM_SETIMAGELIST
        Cancel = True
      Case Else
    End Select
  End Sub



Естественно,
control.HandleCreated += control_HandleCreated;
я убрал

Ну а вторую часть оставил:

Код: vbnet
1.
2.
3.
4.
  Private Sub ListView1_HandleDestroyed(ByVal sender As Object,
   ByVal e As System.EventArgs) Handles ListView1.HandleDestroyed
    s_ListView.ReleaseHandle()
  End Sub



На XP работает, на 7-ке ругается при старте.
Я понял почему, до установки ImageList у меня стоял код, кот. на 7-ке срабатывает

Работает на Вистах, 7-ках и 8-ках. LVN_GETINFOTIP не генерируется. Если строка не вписывается, то автоматом генерируетя системный Tooltip (работает и для итемов, и для сабитемов). "Самопалка" не нужна. Решение в одну строчку кода:
Код: vbnet
1.
2.
3.
    If sys_WinVista Then ListView1.ShowItemToolTips = True '== Or LVS_EX_INFOTIP
   '!!!но если через ShowItemToolTips,
    ' то это надо делать ДО установки остальных стилей через API либо в конструкторе.



Эти ДЕБИЛЫ для того чтобы установить Or LVS_EX_INFOTIP (а мне надо это сделать НЕ В КОНСТРУКТОРЕ)
ПЕРЕСОЗДАЮТ КОНТРОЛ ЗАНОВО.

В итоге имеем:
1) ListView1_HandleCreated
2) ListView1_HandleDestroyed (здесь краш s_ListView.ReleaseHandle(), я не мог предположить что дебилы НАСТОЛЬКО)
3) ListView1_HandleCreated (но уже с Or LVS_EX_INFOTIP) !!!с другим хэндлом

Я конечно вылечил с перестраховкой:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
  Private Sub ListView1_HandleCreated(ByVal sender As Object,
   ByVal e As System.EventArgs) Handles ListView1.HandleCreated
    s_ListView = New SubclassHWND() 'а вдруг они его еще 10 раз пересоздадут
  End Sub

  Private Sub ListView1_HandleDestroyed(ByVal sender As Object,
   ByVal e As System.EventArgs) Handles ListView1.HandleDestroyed
    s_ListView.ReleaseHandle()
  End Sub

    Dim lStyle As Integer = SendMessage(ListView1.Handle, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0)
    lStyle = lStyle Or LVS_EX_DOUBLEBUFFER Or LVS_EX_SUBITEMIMAGES Or _
     LVS_EX_CHECKBOXES
    If sys_WinVista Then lStyle = lStyle Or LVS_EX_INFOTIP  !!! ТАК ЕСТЕСТВЕННО LISTVIEW НЕ ПЕРЕСОЗДАЕТСЯ
    Call SendMessage(ListView1.Handle, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, lStyle)



Неудивительно что при работе с таким продуктом снятие сабклассинга s_ListView.ReleaseHandle() может приводить к проблемам.
НЕ В КУЛИНАРИИ дело, а в НЕКАЧЕСТВЕННЫХ ПОЛУФАБРИКАТАХ с которыми приходится работать.
...
Рейтинг: 0 / 0
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38432191
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Эти ДЕБИЛЫ для того чтобы установить Or LVS_EX_INFOTIP (а мне надо это сделать НЕ В КОНСТРУКТОРЕ)
ПЕРЕСОЗДАЮТ КОНТРОЛ ЗАНОВО.
в документации это описано,но кто ж её читает
...
Рейтинг: 0 / 0
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38432193
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Изопропил,
ListView.ShowItemToolTips Property

1) Вообще я не принебрегаю чтением MS -документаций, иначе б в API так не разбирался. Где?
М.б. где-то в общих описаниях? М.б. они еще объясняют зачем?
2) А ты считаешь что это нормально? Я так делаю в ОЧЕНЬ РЕДКИХ СЛУЧАЯХ -когда лениво перерисовывать и отслеживать все ньюансы.Но здесь то один единственный стиль и никаких ньюансов.
А вот проблем можно огрести.
...
Рейтинг: 0 / 0
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38432338
Фотография Antonariy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Эти ДЕБИЛЫ для того чтобы установить Or LVS_EX_INFOTIP (а мне надо это сделать НЕ В КОНСТРУКТОРЕ)
ПЕРЕСОЗДАЮТ КОНТРОЛ ЗАНОВО.Этот случай не единичен. Чтобы добавить статус бару SBARS_SIZEGRIP, его тоже нужно пересоздать.
...
Рейтинг: 0 / 0
И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
    #38433746
Дмитрий77
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дмитрий77Вопросы:
1. что мне переделать в МОЕМ коде чтоб УСТАНАВЛИВАТЬ САБКЛАССИНГ в ButtonSubclass_Click (когда я этого хочу)?
2. что мне переделать в МОЕМ коде чтоб СНИМАТЬ САБКЛАССИНГ в ButtonSubclass_Click (когда я этого хочу)?

Я так понимаю, никто не знает как это БЕЗГЛЮЧНО сделать через NativeWindow?
не привязываясь к
Код: vbnet
1.
2.
    AddHandler parent.HandleCreated, AddressOf Me.OnHandleCreated
    AddHandler parent.HandleDestroyed, AddressOf Me.OnHandleDestroyed



А вот так кстати ничего не глючит (тест-проект приложил). И можно жать на кнопки Subclass() и UnSubclass() сколько влезет.
Может ну его и использовать "старый добрый метод"?
Правда конфликт с дворником пришлось улаживать, я там выделил проблемное место.

Код: vbnet
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.
Public Class Form1
  Private WithEvents s_ListView As SubclassMyHWND

  Private Sub ButtonSubclass_Click(ByVal sender As System.Object,
   ByVal e As System.EventArgs) Handles ButtonSubclass.Click
    'сабклассим Listview(когда захотим)
    s_ListView = New SubclassMyHWND()
    s_ListView.Subclass(ListView1.Handle)
  End Sub

  Private Sub ButtonUnSubclass_Click(ByVal sender As System.Object,
   ByVal e As System.EventArgs) Handles ButtonUnSubclass.Click
     'снимаем сабклассинг (когда захотим)
   s_ListView.UnSubclass()
   End Sub

  Private Sub s_ListView_CallBackWndProc(ByRef m As System.Windows.Forms.Message,
   ByRef Cancel As Boolean) Handles s_ListView.CallBackWndProc
    Debug.WriteLine(m.ToString)
    Select Case m.Msg
      Case Else
    End Select
  End Sub

  Private Sub ListView1_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListView1.MouseEnter
    ToolTip1.SetToolTip(ListView1, "")
    ToolTip1.SetToolTip(ListView1, "My Tooltip is")
  End Sub
End Class

Public Class SubclassMyHWND

  'Event Declaration. This event will be raised when any  
  'Message will be posted to the Control
  Public Event CallBackWndProc(ByRef m As Message, ByRef Cancel As Boolean)

  Private OldWindowProc As WindowProcDelegate
  Private Const GWL_WNDPROC = (-4)

  Private Declare Function SetWindowLong_delegate Lib "user32" Alias "SetWindowLongW" _
   (ByVal hwnd As IntPtr, ByVal nIndex As Integer, ByVal dwNewLong As WindowProcDelegate) As WindowProcDelegate
  Private Declare Function CallWindowProc_delegate Lib "user32" Alias "CallWindowProcW" _
   (ByVal lpPrevWndFunc As WindowProcDelegate, ByVal hwnd As IntPtr, ByVal Msg As Integer, _
   ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
  Private Delegate Function WindowProcDelegate _
   (ByVal hwnd As IntPtr, ByVal Msg As Integer, _
    ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer

  Private m_hwnd As IntPtr

  '================================
  'Обратный вызов делегата 
  'http://www.gotdotnet.ru/forums/2/126642/
  Private NewProc As WindowProcDelegate 'специально для полудурка-дворника
  '================================

  Public Sub Subclass(ByVal hwnd As IntPtr)
    m_hwnd = hwnd
    NewProc = New WindowProcDelegate(AddressOf NewWindowProc)
    OldWindowProc = SetWindowLong_delegate( _
     m_hwnd, GWL_WNDPROC, _
     NewProc)
  End Sub

  Public Sub UnSubclass()
    SetWindowLong_delegate(m_hwnd, GWL_WNDPROC, OldWindowProc)
  End Sub

  Private Function NewWindowProc( _
   ByVal hwnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
    Dim m As Message = Message.Create(hwnd, Msg, wParam, lParam)
    Dim cancel As Boolean = False 'по умолчанию обрабатывать сообщение
    RaiseEvent CallBackWndProc(m, cancel)

    If cancel Then
      Return m.Result
    Else ' если обрабатываем (cancel=False), то forward message to base WndProc
      Return CallWindowProc_delegate(OldWindowProc, m.HWnd, m.Msg, m.WParam, m.LParam)
    End If
  End Function

End Class
...
Рейтинг: 0 / 0
10 сообщений из 10, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / И ВСЕ-ТАКИ. Надо ли снимать сабклассинг? Как правильно его снять?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]