Страницы: 1
RSS
Проблема с захватом оконной процедуры Экселя.
 
Не получается переопределить оконную процедуру Экселя.  
Public Const GWL_WNDPROC = -4  
 
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc, ByVal hWnd As Long, ByVal Msg As Any, ByVal wParam As Any, ByVal lParam As Long) As Long  
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long  
Public Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long  
 
Sub SetNewWindProc()  
Dim hWnd As Long  
hWnd = Application.hWnd  
OldWindowProc = GetWindowLong(hWnd, GWL_WNDPROC)  
OldWindowProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)  
End Sub  
 
Public Function WindowProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long  
'Пока ничего не делаем  
WindowProc = CallWindowProc(NewWindowProc, hWnd, Msg, wParam, lParam)  
End Function  
 
OldWindowProc  в обоих случаях возвращает отрицательное значение и, как следствие, после вызова SetWindowLong Excel погибает. Для задания/получения других свойств окна, не GWL_WNDPROC, всё работает нормально.
 
Букв много, а смысла - мало...  
 
Что хотите вообще сделать этим кодом?  
Что и зачем переопределить?  
 
Опишите задачу - может, посоветуем более простое решение...
 
Я слежу за мышей, когда она над экселем (поставил hook на WH_MOUSE_LL). Когда стоит такой хук, написанный на ВБА, это требует немалых ресурсов, пусть даже он самый простейший. Следить за мышей мне нужно только над одним листом рабочей книги, поэтому, ресурсы можно сэкономить. По событиям Worksheet_Activate/Worksheet_Deactivate я ставлю/снимаю хук над нужным мне листом.  
 
ЗАДАЧА: Ставить/снимать хук ещё и при активации/деактивации Экселя.  
Я думал делать это путём отлавливания сообщения WM_ACTIVATE для родительского окна приложения Экселя. Вот это у меня и не получается, а именно - получить адрес оконной процедуры Экселя.  
 
Есть альтернативное решение: поставить WH_CBT хук на поток. Тогда можно отлавливать код HCBT_ACTIVATE и по нему ставить/снимать хук на мышь. Но тут выплыл такой момент: когда мышь находится над экселем и он активен, то забираются все ресурсы процессора! Поэтому такой вариант тоже не годится!  
 
Вопрос: как поймать событие активации экселя ? (любым способом)  
Workbook_Activate не подходит, поскольку когда имеется только одна книга, оно не возникает.
 
{quote}{login=@Nik}{date=16.01.2011 05:01}{thema=}Workbook_Activate не подходит, поскольку когда имеется только одна книга, оно не возникает.{/post}{/quote}  
Отслеживать еще и Workbook_Open
 
Выкладываю красочный файл-пример, чтобы всё-таки заинтересовать подумать над тем, как снять хук при деактивации книги экселя.  
Если хук не снимать, то при переходе в редактор ВБА можно увидеть, как неприятно мерцает заголовок ВБА при перемещении мыши и остаётся заметная загрузка процессора (если смотреть диспетчером задач).
 
Пробовал привязаться к таймеру и, скажем, 3 раз в секунду делать:    
 
If GetActiveWindow = Application.hwnd Then  
где GetActiveWindow - функция API, возвращающая хендл текущего активного приложения.  
Всё работает, хук на мышь снимается, когда эксель деактивируется и ставится, когда активируется. Но становится жутко неудобно писать программу на ВБА, поскольку срабатывает процедура, вызываемая по таймеру и тут же исчезают свойства объекта, открываемые символом ".".  
 
У меня просьба к тем, кто общается ещё и на других форумах, в т.ч. и англоязычных, где имеются хорошие специалисты, задать мой вопрос и приложить файл-пример. Может там что подскажут...
 
ну а в процедуру хука:  
 
If GetActiveWindow() <> Application.hWnd Then Application.OnTime Now + TimeSerial(0, 0, 1), "stophooks"  
 
 
но включить  обратно не удастся - только передернув листы..
Живи и дай жить..
 
вот включение по selection_change
Живи и дай жить..
 
Придумал ещё один метод, правда не такой элегантный, как хотелось бы. Принцип такой: при деактивации экселя (проверяется всё так по таймеру, а не в процедуре хука на мышь, поскольку переключиться в другое приложение можно и клавиатурой) останавливается таймер. При этом на всю видимую область окна книги натягивается Label0. У неё прописано событие MouseMove. Как только мышь наедет на эксель, событие срабатывает и можно опять следить за тем, когда же станет активным :))) Тупо, конечно, но рабоает :-))  
Правда, пришлось повозиться... Нужно было учесть варианты, когда открыта не одна книга и когда осущ. переход в режим конструктора. Событие Selection_Change тоже пришлось задействовать. Выкладываю, что у меня получилось.  
 
Хоть и много писанины, но зато можно значительно преукрасить интерфейс, снабдив его функциями, которые до этого казались нереальными для экселя (вспыхивающие метки, появляющиеся под мышкой текстбоксы, всплывающие подсказки и т.п.)  
 
В коде имя Rng1 используется по назначениею только в процедуре хука. В остальных местах оно служит только для того, чтобы получить Лист1.  
 
Вцелом, всё равно вопрос остаётся открытым.
 
упс, обнаружил, что диапазон [Rng1]= Лист1!$D$9, а должен быть равен =Лист1!$D$9:$D$10. Поэтому, если щёлкнуть на D10, то активизировать ячейку получается, а на D9 - нет.
 
Кстати, слэн, в твоём варианте, если включить режим конструктора, а затем перейти в другое приложение, то хук не снимается.    
 
А снимать хук, действительно, лучше всего в самом хуке, типа того, как ты сказал. Только нужно учесть обнуление переменных при переходе в режим конструктора.
 
чесно говоря, сомнительна вообще необходимость всех этих поползновений..  
 
перешел на другой лист, хук снялся - и редактируй себе.. :)  
 
 
но если поизвращаться, то запустить вторую копию иксель(или стороннюю программу) в невидимости и оттуда по таймеру проверять какое окно активно..
Живи и дай жить..
 
А по поводу скрытой копии экселя - это вариант :-))
Страницы: 1
Читают тему
Наверх
Loading...