Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16

Реализовать UnSubclassing для Excel

21.07.2013, 20:39. Показов 1359. Ответов 4

Студворк — интернет-сервис помощи студентам
Написал прогу для постановки Excel в очередь получателей извещения об изменении содержимого буфера обмена.
Взял за основу субклассинг от Jaafar Tribak.

Возникла проблема с остановкой субклассинга.
Вручную (не закрывая Excel) получается. Но хочется, чтобы этот процесс сам корректно завершался по нажатию крестика.

Из-под события Thisworkbook_BeforeClose() не получается, т.к. Excel "падает" в тот момент, когда это событие еще не начало выполняться.

Возможно ли по-другому успеть перехватить событие закрытия книги, чтобы во время завершить субклассинг (строка 106)?

Visual Basic
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
'CopyRights:
'Ross Donald (VB.NET) code of SetClipboardViewer - [url]http://www.radsoftware.com.au/articles/clipboardmonitor.aspx[/url]
'Jaafar Tribak - Code of Excel Subclassing - [url]http://www.mrexcel.com/forum/general-excel-discussion-other-questions/420673-challenging-problem-how-make-excel-subclassing-safe-stable.html#post2082195[/url]
 
Option Explicit
 
Private Declare Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal MSG As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetDesktopWindow Lib "user32.dll" () As Long
Private Declare Function ShowWindow Lib "user32.dll" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function SetTimer Lib "user32.dll" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32.dll" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
Private Declare Function LockWindowUpdate Lib "user32.dll" (ByVal hwndLock As Long) As Long
Private Declare Function GetProp Lib "user32" Alias "GetPropA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Private Declare Function SetProp Lib "user32" Alias "SetPropA" (ByVal hwnd As Long, ByVal lpString As String, ByVal hData As Long) As Long
Private Declare Function RemoveProp Lib "user32" Alias "RemovePropA" (ByVal hwnd As Long, ByVal lpString As String) As Long
Private Declare Function SetClipboardViewer Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ChangeClipboardChain Lib "user32" (ByVal hwnd As Long, ByVal hWndNext As Long) As Long
 
Private Const GWL_WNDPROC As Long = -4
Private Const WM_USER As Long = &H400
Private Const WM_NCMOUSEMOVE As Long = &HA0
Private Const WM_SETREDRAW As Long = &HB
'Constants for Clipboard API Calls...
Private Const WM_DRAWCLIPBOARD As Integer = &H308
Private Const WM_CHANGECBCHAIN As Integer = &H30D
'UnSubClass
Private Const WM_NCDESTROY As Long = &H82
Private Const WM_DESTROY As Long = &H2
 
Private Const VBE_CLASS_NAME As String = "wndclass_desked_gsk"
Private Const EXCEL_CLASS_NAME As String = "XLMAIN"
 
Private lOldWinProc As Long
Private lVBEhwnd As Long
'Handle for next clipboard viewer...
Private mNextClipBoardViewerHWnd As Long
'flag for sublassing accomplishing
Public flag As Boolean
 
Sub Safe_Subclass(hwnd As Long)
 
    'don't subclass the window twice !
    If GetProp(GetDesktopWindow, "HWND") <> 0 Then
        MsgBox "The Window is already Subclassed.", vbInformation
        Exit Sub
    End If
 
    'store the target window hwnd as a desktop
    'window for later use property.
     SetProp GetDesktopWindow, "HWND", hwnd
 
    'retrieve the VBE hwnd.
     lVBEhwnd = FindWindow(VBE_CLASS_NAME, vbNullString)
 
    'prevent flickering of the screen
    'before posting messages to reset
    'the VBE window.
    LockWindowUpdate lVBEhwnd
 
    'do the same with the desktop in the background.
    SendMessage GetDesktopWindow, ByVal WM_SETREDRAW, ByVal 0&, 0&
 
    'stop and reset the VBE first to safely
    'proceed with our subclassing of xl.
    PostMessage lVBEhwnd, ByVal WM_USER + &HC44, ByVal &H30, ByVal 0&
    PostMessage lVBEhwnd, ByVal WM_USER + &HC44, ByVal &H33, ByVal 0&
    PostMessage lVBEhwnd, ByVal WM_USER + &HC44, ByVal &H83, ByVal 0&
 
    'run a one time timer and subclass xl
    'from the timer callback function.
    'if subclassing is not installed within
    'the timer callback,xl will crash !
    flag = True
    SetTimer GetProp(GetDesktopWindow, "HWND"), 0&, 1, AddressOf TimerProc
End Sub
 
Sub UnSubClassExcel(hwnd As Long)
    'Tear down
    ChangeClipboardChain GetProp(GetDesktopWindow, "HWND"), GetProp(GetDesktopWindow, "NextClipBoardViewerHWnd")
    'remove the subclass and cleanup.
    SetWindowLong hwnd, GWL_WNDPROC, lOldWinProc
    RemoveProp GetDesktopWindow, "HWND"
    RemoveProp GetDesktopWindow, "NextClipBoardViewerHWnd"
    lOldWinProc = 0
End Sub
 
Private Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    On Error Resume Next
    
    Select Case uMsg
        Case WM_DRAWCLIPBOARD 'The clipboard has changed...
            MsgBox "The clipboard has changed..."
            SendMessage GetProp(GetDesktopWindow, "NextClipBoardViewerHWnd"), uMsg, wParam, lParam
 
        Case WM_CHANGECBCHAIN 'Another clipboard viewer has removed itself...
            If wParam = GetProp(GetDesktopWindow, "NextClipBoardViewerHWnd") Then
                SetProp GetDesktopWindow, "NextClipBoardViewerHWnd", lParam
            Else
                SendMessage GetProp(GetDesktopWindow, "NextClipBoardViewerHWnd"), uMsg, wParam, lParam
            End If
            
        'Try UnSubClass
        Case WM_NCDESTROY
            Call UnSubClassExcel(Application.hwnd)
            'Exit Function
            
        Case WM_DESTROY
            Call UnSubClassExcel(Application.hwnd)
            'Exit Function
   End Select
 
   'allow other msgs default processing.
    If flag Then WindowProc = CallWindowProc(lOldWinProc, hwnd, uMsg, wParam, lParam)
End Function
 
 
Sub TimerProc(ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long)
    'we lost the hwnd stored in the lVBEhwnd var
    'after reseting the VBE so let's retrieve it again.
    lVBEhwnd = FindWindow(VBE_CLASS_NAME, vbNullString)
 
    'we no longer need the timer.
    KillTimer GetProp(GetDesktopWindow, "HWND"), 0&
 
    'allow back drawing on the desktop.
    SendMessage GetDesktopWindow, WM_SETREDRAW, ByVal 1, 0&
 
    'hide the VBE.
    ShowWindow lVBEhwnd, 0&
 
    'unlock the window update.
    LockWindowUpdate 0&
 
    'add VBE window hwnd to the Clipboard Chain and save Next ClipBoardViewer handle in the desktop property
    SetProp GetDesktopWindow, "NextClipBoardViewerHWnd", SetClipboardViewer(GetProp(GetDesktopWindow, "HWND"))
    
    'and at last we can now safely
    'subclass our target window.
    lOldWinProc = SetWindowLong(GetProp(GetDesktopWindow, "HWND"), GWL_WNDPROC, AddressOf WindowProc)
End Sub
Вложения
Тип файла: xls ClipBoardChange2.xls (52.0 Кб, 19 просмотров)
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
21.07.2013, 20:39
Ответы с готовыми решениями:

Реализовать перекрестный запрос в delphi для вывода в excel
Доброго времени суток) нуждаюсь в помощи по построению перекрестного запроса в delphi и отображению данных в excel есть запросы...

Как лучше реализовать классы для экспорта в Excel?
Всем привет! Приложение должно иметь возможность экспортировать отчеты в эксель. Я в затруднении, как это лучше сделать... 1 вариант:...

Реализовать класс для матриц. В этом классе реализовать интерфейс, содержащий методы для выполнения операций
Реализовать класс для матриц. В этом классе реализовать интерфейс, содержащий методы для выполнения следующих операций: - сложение -...

4
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
26.01.2014, 19:48
Лучший ответ Сообщение было отмечено The trick как решение

Решение

Попробуй так
Visual Basic
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
'UnSubClass
Private Const WM_SYSCOMMAND As Long = &H112&
Private Const SC_CLOSE As Long = &HF060&
....
Private Function WindowProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    Select Case uMsg
        Case WM_DRAWCLIPBOARD 'The clipboard has changed...
            MsgBox "The clipboard has changed..."
            SendMessage GetProp(GetDesktopWindow, "NextClipBoardViewerHWnd"), uMsg, wParam, lParam
 
        Case WM_CHANGECBCHAIN 'Another clipboard viewer has removed itself...
            If wParam = GetProp(GetDesktopWindow, "NextClipBoardViewerHWnd") Then
                SetProp GetDesktopWindow, "NextClipBoardViewerHWnd", lParam
            Else
                SendMessage GetProp(GetDesktopWindow, "NextClipBoardViewerHWnd"), uMsg, wParam, lParam
            End If
        Case WM_SYSCOMMAND
            If wParam = SC_CLOSE Then
                Call UnSubClassExcel(Application.hwnd)
                WindowProc = 0
                PostMessage hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam
            End If
   End Select
   If flag Then WindowProc = CallWindowProc(lOldWinProc, hwnd, uMsg, wParam, lParam)
End Function
Честно сказать не особо разбирался, но код помоему ужасный, можно сделать проще (хотя может и ошибаюсь)
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
26.01.2014, 20:07  [ТС]

Спасибо за честную критику.

Проверил. Теперь все в порядке. Excel не валится.
Наличие объекта в буфере определяет также хорошо.
0
Модератор
10057 / 3902 / 884
Регистрация: 22.02.2013
Сообщений: 5,853
Записей в блоге: 79
26.01.2014, 20:10
Цитата Сообщение от Dragokas Посмотреть сообщение
Спасибо за честную критику.
Так это твой код? Зачем десктопу передавать свойства? Это нехорошо, если будет вылет, то свойство не уберется у десктопа и сабклассинг не запустится при следующих запусках, только если его отключить опять.
0
Эксперт WindowsАвтор FAQ
 Аватар для Dragokas
18033 / 7736 / 892
Регистрация: 25.12.2011
Сообщений: 11,502
Записей в блоге: 16
26.01.2014, 20:13  [ТС]
Нет. Это код тов. Jaafar Tribak. Там выше и ссылка на обсуждение.
Я уже не помню, что там правил.
Цитата Сообщение от The trick Посмотреть сообщение
если будет вылет, то свойство не уберется у десктопа и сабклассинг не запустится при следующих запусках, только если его отключить опять.
Да, это понятно.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
26.01.2014, 20:13
Помогаю со студенческими работами здесь

Реализовать поиск по листу Excel
Всем привет! Подскажите пожалуйста как сделать поиск определенного текста в Visaul studio 2013 типа Find ? этот код установки значения...

Реализовать вывод данных из Java в Excel
я пытаюсь использовать библиотеку http://poi.apache.org/ но не могу создать документ , проблема с библиотеками , не у кого не осталось...

Как в Excel реализовать задачи на множествах
Как сделать объединение,пересечение,разность в Excel

Как реализовать константы Excel из-под VB?
Я поднимаю Excel из-под VB, причем приходится использовать позднее связывание (т.е. не указывая явно olb-файл в Project - Referencies). При...

Реализовать печать листа EXCEL программно
Подскажите пожалуйста. У меня в коде для печати документов Word используется метод PrintOutOd, я меняю Word на Excel не могли бы вы...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru