Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - Общий форум

Страница: 1 |

 

  Вопрос: Работать с окнами класса ToolBarWindow32 Добавлено: 11.12.08 13:20  

Автор вопроса:  GDK
Есть "чужое" приложение. В нём есть окно, класс которого ToolBarWindow32. Это панель инструментов. Нужно узнавать состояние её кнопочек (нажата или отпущена), нажимать и отпускать их, узнавать состояние всего окошка панели (отображается или нет на экране). Ну и неплохо было бы узнавать её место расположения на экране относительно гланого окна "чужой" программы и относительно экрана.
HWnd панели получить могу. Может быть кто-нибудь делал подобное? Если не трудно покажите примеры. Ну хотя бы объясните как/где искать инф. по этому поводу.

Ответить

  Ответы Всего ответов: 15  

Номер ответа: 1
Автор ответа:
 Father



Вопросов: 0
Ответов: 159
 Профиль | | #1 Добавлено: 12.12.08 13:44
Посылаешь SendMessage в окно, возвращаемое значение функции и состояние wParam и lParam - есть реакция окна на сообщение.
Все сообщения для ToolBarWindow32 документированы в msdn и начинаются с префикса TB_.(TB_PRESSBUTTON и т.д.)

Ответить

Номер ответа: 2
Автор ответа:
 GDK



Вопросов: 13
Ответов: 348
 Профиль | | #2 Добавлено: 15.12.08 12:42
TB_PRESSBUTTON как раз и хотел заслать чтобы нажать кнопку.
Не вышло. Почему - не понятно. Пробовал посылать и через SendMessage и через PostMessage. Другие сообщения тоже посылал, Например, получилось удалять кнопки. Но это мне не надо. Вот что нарыл по TB_PRESSBUTTON:

TB_PRESSBUTTON

The TB_PRESSBUTTON message presses or releases the specified button in a toolbar.

TB_PRESSBUTTON
wParam = (WPARAM) idButton;
lParam = (LPARAM) MAKELONG(fPress, 0);

Parameters
idButton
Command identifier of the button to press or release.
fPress
Press flag. If this parameter is TRUE, the button is pressed. If it is FALSE, the button is released.

Return Values
Returns TRUE if successful or FALSE otherwise.


TB_PRESSBUTTON

Сообщение TB_PRESSBUTTON нажимает или выпускает определенную кнопку в toolbar.

TB_PRESSBUTTON wParam = (WPARAM) idButton;
lParam = (LPARAM) MAKELONG(fPress, 0);

Параметры
idButton
Командный идентификатор кнопки, чтобы нажимать или выпускаться.
fPress
Корреспондентский флаг. Если этот параметр является ИСТИНОЙ, кнопка нажата. Если это - ЛОЖЬ, кнопка выпущена.

Обратные Величины
Возвращается ВЕРНО если успешный или ЛОЖНЫЙ в противном случае.

Думал, что дело в MAKELONG(fPress, 0). Пробовал вместо этого выражения просто писать 0. Кнопка при этом всё равно не становится отжатой(не реагирует).
Да, кстати в данном ToolBare есть несколько кнопочек, причём нажатой может быть только одна или ни одной. Может дело в этом(не то сообщение посылаю)?

Ответить

Номер ответа: 3
Автор ответа:
 Father



Вопросов: 0
Ответов: 159
 Профиль | | #3 Добавлено: 15.12.08 22:47
Во-первых не забывай, что idButton - командный идентификатор кнопки, а не порядковый индекс.
Чтобы найти его по индексу пошли TB_GETBUTTON.
Во-вторых, ты имеешь дело с чужим процессом, поэтому пример c проводником:
  1.  
  2. Option Explicit
  3. Private hwntbr As Long
  4.  
  5. Private Sub Command1_Click()
  6.     Dim Tbn As TBBUTTON
  7.     Dim procid As Long
  8.     Dim hProcess As Long
  9.     Dim vptrTbn As Long
  10.     Dim vptrStr As Long
  11.     Dim rwbytes As Long
  12.     
  13.    'TODO: IsWindow(hwntbr)
  14.     Call GetWindowThreadProcessId(hwntbr, procid) ' найти PID окна ToolbarWindow32
  15.     hProcess = OpenProcess(PROCESS_ALL_ACCESS Or PROCESS_DUP_HANDLE, True, procid) ' получить хендл процесса
  16.     vptrTbn = VirtualAllocEx(hProcess, 0, LenB(Tbn), MEM_COMMIT Or MEM_TOP_DOWN, PAGE_READWRITE) 'выделить память для TBBUTTON
  17.     Call SendMessage(hwntbr, TB_GETBUTTON, 4, vptrTbn) 'будем считать что кнопка ПОИСК имеет индекс 4 (0-назад,1-вперед,2-вверх,3-сепаратор,4-поиск )
  18.     Call ReadProcessMemory(hProcess, vptrTbn, Tbn, LenB(Tbn), rwbytes) 'прочитать TBBUTTON из памяти
  19.     Call SendMessage(hwntbr, WM_COMMAND, Tbn.idCommand, hwntbr)
  20.     Call VirtualFreeEx(hProcess, vptrTbn, LenB(Tbn), MEM_RELEASE)
  21.     Call CloseHandle(hProcess)
  22.  
  23. End Sub
  24.  
  25. Private Sub Form_Load()
  26.     'Shell "explorer.exe"
  27.     'Sleep 1000
  28.     Dim hwmain As Long
  29.     ' найти окно проводника и в нем найти ToolbarWindow32
  30.     Call EnumChildWindows(FindWindow("ExploreWClass", vbNullString), AddressOf EnumChildProc, VarPtr(hwntbr))
  31.     If Not CBool(hwntbr) Then Debug.Print "ToolbarWindow32 не найден"
  32. End Sub
  33.  
  34. '-- Module --
  35. Option Explicit
  36.  
  37. Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
  38. Public Declare Sub PutMem4 Lib "msvbvm60" (ByVal dest As Long, ByVal Value As Long)
  39. Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
  40. Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
  41. Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
  42. Public Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
  43. Public Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
  44. Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
  45. Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
  46. Public Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
  47. Public Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
  48. Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
  49.  
  50. Public Const MEM_RELEASE = &H8000
  51. Public Const MEM_COMMIT = &H1000
  52. Public Const MEM_TOP_DOWN = &H100000
  53. Public Const PAGE_READWRITE = &H4
  54.  
  55. Public Const PROCESS_ALL_ACCESS = &H1F0FFF
  56. Public Const PROCESS_DUP_HANDLE = &H40
  57.  
  58. Public Const WM_COMMAND = &H111
  59. Public Const WM_USER = &H400
  60.  
  61. Public Const TB_GETBUTTON = (WM_USER + 23)
  62. Public Const TB_BUTTONCOUNT = (WM_USER + 24)
  63.  
  64. Public Type TBBUTTON
  65.     iBitmap  As Long
  66.     idCommand As Long
  67.     fsState As Byte
  68.     fsStyle As Byte
  69.     dwData As Long
  70.     iString As Long
  71. End Type
  72.  
  73. Public Function EnumChildProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
  74.    Dim st As String * 512
  75.    Dim ls As Long
  76.     ls = GetClassName(hwnd, st, 512)
  77.     If Left(st, ls) = "ToolbarWindow32" Then
  78.         If SendMessage(hwnd, TB_BUTTONCOUNT, 0, 0) > 6 Then 'если кнопок больше шести то будем считать это главным тулбаром
  79.             Call PutMem4(ByVal lParam, ByVal hwnd)          'записать hwnd в lparam
  80.             EnumChildProc = 0                               'и выйти
  81.             Exit Function
  82.         End If
  83.     End If
  84.     EnumChildProc = 1                                       'продолжить поиск
  85. End Function
  86.  
  87. Public Function MAKELONG(ByVal hiword As Integer, ByVal loword As Integer) As Long
  88.     MAKELONG = (hiword * &H10000) Or (loword And &HFFFF&)
  89. End Function


Ответить

Номер ответа: 4
Автор ответа:
 Father



Вопросов: 0
Ответов: 159
 Профиль | | #4 Добавлено: 16.12.08 00:50
P/S/
Не факт, что TB_PRESSBUTTON будет вызывать обработку нажатия, поэтому можно послать мышиные сообщения:
  1.  
  2. Private Sub Command1_Click()
  3.    Dim rwb As Long
  4.    Dim procid As Long
  5.    Dim rc As RECT
  6.    Dim prc As Long ' указатель на выделенную память для RECT в другом процессе
  7.   
  8.    Call GetWindowThreadProcessId(hwntbr, procid) ' найти PID окна
  9.    hProcess = OpenProcess(PROCESS_ALL_ACCESS Or PROCESS_DUP_HANDLE, True, procid) ' получить хендл процесса
  10.    prc = VirtualAllocEx(hProcess, 0, LenB(rc), MEM_COMMIT Or MEM_TOP_DOWN, PAGE_READWRITE) 'выделить память для RECT
  11.    Call SendMessage(hwntbr, TB_GETITEMRECT, 4, prc) ' локальные коорд. кнопки ПОИСК
  12.    Call ReadProcessMemory(hProcess, prc, rc, LenB(rc), rwb) 'прочитать RECT из памяти
  13.    Call VirtualFreeEx(hProcess, prc, LenB(rc), MEM_RELEASE) 'освободить память
  14.    Call SendMessage(hwntbr, WM_LBUTTONDOWN, 0, MAKELONG(rc.Top, rc.Left))
  15.    Call SendMessage(hwntbr, WM_LBUTTONUP, 0, MAKELONG(rc.Top, rc.Left))
  16.    CloseHandle (hProcess)
  17. End Sub
  18.  

Ответить

Номер ответа: 5
Автор ответа:
 GDK



Вопросов: 13
Ответов: 348
 Профиль | | #5 Добавлено: 16.12.08 08:55
Ну спасибо большое - хоть кто то ответил. А то уже вроде бы нашёл рабочий вариант как нажать на кнопку(кстати c помощью посылки WM_LBUTTONUP/WM_LBUTTONDOWN). Но там работа с чужим процессом (т.е. его памятью) была организована в классе и без к-либо комментариев, а я в этом деле NULL.

Ответить

Номер ответа: 6
Автор ответа:
 GDK



Вопросов: 13
Ответов: 348
 Профиль | | #6 Добавлено: 16.12.08 17:45
И ещё. В том варианте кроме класса должен был обязательно присутствовать дополнительный модуль, в котором была фукция, создающая объект этого класса. Причём получалось доставать координаты кнопок только если код находился в форме. Пробовал скопировать его в стандартный модуль и получить координаты - возвращается 0 во всех членах переменной типа RECT. Пробовал в модуле писать Option Explicit, процедуру делать типа Private - результат отрицательный. Короче, полный писец. А я то хотел всю работу с ToolBar-ом чужого приложения оформить в виде класса. Получалось бы для работы этого класса необходимы: дополнительный класс для работы с памятью чужого процесса, модуль для создания объекта этого класса, дополнительная форма для корректной работы. Теперь же благодаря вам попробую разобраться как работать с памятью чужого процесса и организовать всё же работу с ToolBar-ом чужого приложения в виде ОДНОГО класса. Хотя работаю в VBA Word, думаю получится разобраться.
И ещё, к сведению. При поисках по интернету с целью решения этой задачи, наткнулся на следующее: в каком то форуме было выяснено, что поле dwData структуры TBBUTTON содержит в первых четырёх байтах HWnd кнопки, хотя в MSDN об этом ничего не сказано. А выяснилось это при экспериментировании. Да, кстати, EnumChildWindows при поисках дочерних окон чужой проги вызывает ошибку, от которой VBA закрывается вместе с Word-ом. Причём функция обратного вызова (в вашем первом варианте это EnumChildProc), может вызваться один или два или три раза, а потом бац-ошибка. Может быть это особенность VBA, но в любом случае уважение ко всем API типа Enum... после этого поубавилось. Короче пользуюсь GetNextWindow и GetChildWindow.

Ответить

Номер ответа: 7
Автор ответа:
 GDK



Вопросов: 13
Ответов: 348
 Профиль | | #7 Добавлено: 17.12.08 15:10
Ура! Всё получилось! Только лучше писать
  1.  
  2. Call PostMessage(hwntbr, WM_LBUTTONDOWN, 0, MAKELONG(rc.Top, rc.Left))
  3. Call PostMessage(hwntbr, WM_LBUTTONUP, 0, MAKELONG(rc.Top, rc.Left))

Ответить

Номер ответа: 8
Автор ответа:
 Father



Вопросов: 0
Ответов: 159
 Профиль | | #8 Добавлено: 19.12.08 22:47
поле dwData структуры TBBUTTON содержит в первых четырёх байтах HWnd кнопки,

Поле dwData имеет тип DWORD и состоит всего из 4-х байт и если вдруг и содержит hwnd самого окна (для чего бы?), то не сильно ориентируйся на это, т.к. разработчик имет право засунуть туда хоть телефон своей бабушки.

На EnumChildWindows плюнь, делай как удобно.
 

Ответить

Номер ответа: 9
Автор ответа:
 GDK



Вопросов: 13
Ответов: 348
 Профиль | | #9 Добавлено: 26.12.08 17:15
Да я и не ориентируюсь. Так, к сведению написал. Теперь ещё вопросик: Можно ли использовать как шаблон следующий код
  1.  
  2.  Dim rwb As Long
  3.  
  4.    Dim procid As Long
  5.  
  6.    Dim rc As RECT
  7.  
  8.    Dim prc As Long ' указатель на выделенную память для RECT в другом процессе
  9.  
  10.    
  11.  
  12.    Call GetWindowThreadProcessId(hwntbr, procid) ' найти PID окна
  13.  
  14.    hProcess = OpenProcess(PROCESS_ALL_ACCESS Or PROCESS_DUP_HANDLE, True, procid) ' получить хендл процесса
  15.  
  16.    prc = VirtualAllocEx(hProcess, 0, LenB(rc), MEM_COMMIT Or MEM_TOP_DOWN, PAGE_READWRITE) 'выделить память для RECT
  17.  
  18.    Call SendMessage(hwntbr, TB_GETITEMRECT, 4, prc) ' локальные коорд. кнопки ПОИСК
  19.  
  20.    Call ReadProcessMemory(hProcess, prc, rc, LenB(rc), rwb) 'прочитать RECT из памяти
  21.  
  22.    Call VirtualFreeEx(hProcess, prc, LenB(rc), MEM_RELEASE) 'освободить память
  23.  


для извлечения информации других типов (не RECT).
В качестве примера - попытался получить текст из любой строки панели состояния чужой проги(класс окна msctls_statusbar32)

вот как изменил код:
  1.  
  2. Dim BufStr As String
  3. Dim i As Long
  4.  
  5. Dim rwb As Long
  6. Dim procid As Long
  7. Dim rc As String
  8. Dim prc As Long ' указатель на выделенную память для RECT в другом процессе
  9. Dim hwntbr As Long
  10. Dim hProcess As Long
  11.  
  12.  
  13. hwntbr = HWndObjm
  14.  
  15. rc = Space(10)
  16.    Call GetWindowThreadProcessId(hwntbr, procid) ' найти PID окна
  17.  
  18.    hProcess = OpenProcess(PROCESS_ALL_ACCESS Or PROCESS_DUP_HANDLE, True, procid) ' получить хендл процесса
  19.  
  20.    prc = VirtualAllocEx(hProcess, 0, LenB(rc), MEM_COMMIT Or MEM_TOP_DOWN, PAGE_READWRITE) 'выделить память для RECT
  21.  
  22.    Call SendMessage(hwntbr, WM_GETTEXT, 1, prc) ' локальные коорд. кнопки
  23.  
  24.    Call ReadProcessMemory(hProcess, prc, rc, LenB(rc), rwb) 'прочитать RECT из памяти
  25.  
  26.    Call VirtualFreeEx(hProcess, prc, LenB(rc), MEM_RELEASE) 'освободить память
  27.  
  28.    Call CloseHandle(hProcess)



в Call SendMessage(hwntbr, WM_GETTEXT, 1, prc) wParam (=1) - номер панели в статусбаре.
Вместо WM_GETTEXT в Call SendMessage(hwntbr, WM_GETTEXT, 1, prc) пытался также ставить SB_GETTEXTA.

Вот. VBA и весь WORD рушится при выполнении этого кода. Причём на строке
  1.  
  2.    Call ReadProcessMemory(hProcess, prc, rc, LenB(rc), rwb) 'прочитать RECT из памяти
  3.  



И ещё вопрос. Почему prc всегда получается =0. Так и должно быть. Выяснил при отладке. В примере с ToolBar тоже prc=0, но всё работает ведь.

Ответить

Номер ответа: 10
Автор ответа:
 GDK



Вопросов: 13
Ответов: 348
 Профиль | | #10 Добавлено: 26.12.08 17:28
HWnd статусбара правильный - это точно. Проверял с помощью утилиты, показывающей инф. об окне, расположенном под курсором мышки. Кстати, она показывает текст нулевой панели статусбара. В интернете поискал по этому поводу. Нашёл неск. примеров, но все на C написаны. Короче, сам не разобрался.
А сначала думал всё получится просто и быстро.

Ответить

Номер ответа: 11
Автор ответа:
 Father



Вопросов: 0
Ответов: 159
 Профиль | | #11 Добавлено: 26.12.08 19:32
Почему prc всегда получается =0

Нет конечно же, ты ошибся. Скорее всего ты после остановки в отладке нажал reset и Pubic-переменная HWndObjm заново инициализировалась в ноль.
Call SendMessage(hwntbr, WM_GETTEXT, 1, prc) wParam (=1) - номер панели в статусбаре.

Для панелей статусбара WM_GETTEXT не прокатит т.к. wparam хочет видеть ко-во получаемых символов а не zero-index панели.
Надо бы:
Private Const SB_GETTEXTA = (WM_USER + 2)
Private Const SB_GETTEXTLENGTHA = (WM_USER + 3)

В качестве примера - получить текст из строки панели состояния чужой проги(класс окна msctls_statusbar32):
  1.  
  2.    Dim rwb As Long
  3.    Dim procid As Long
  4.    Dim hProcess As Long
  5.    Dim L As Long
  6.    Dim prc As Long ' указатель на выделенную память
  7.    
  8.    Call GetWindowThreadProcessId(hwntbr, procid)  ' найти PID окна msctls_statusbar32
  9.    hProcess = OpenProcess(PROCESS_ALL_ACCESS Or PROCESS_DUP_HANDLE, True, procid) ' получить хендл процесса
  10.    L = SendMessage(hwntbr, SB_GETTEXTLENGTHA, 0, 0) ' длина строки первой панели  // SendMessage(hwntbr, SB_GETTEXTLENGTHA, 1, 0) - вторая панель
  11.    Dim s() As Byte
  12.    ReDim s(L - 1)
  13.    prc = VirtualAllocEx(hProcess, 0, L, MEM_COMMIT Or MEM_TOP_DOWN, PAGE_READWRITE) 'выделить память
  14.    Call SendMessage(hwntbr, SB_GETTEXTA, 0, prc) ' получить текст первой панели //SendMessage(hwntbr, SB_GETTEXTA, 1, prc) - вторая
  15.    Call ReadProcessMemory(hProcess, prc, ByVal VarPtr(s(0)), L, rwb)    'прочитать из памяти
  16.    MsgBox StrConv(s, vbUnicode)
  17.    Call VirtualFreeEx(hProcess, prc, L, MEM_RELEASE) 'освободить память
  18.    Call CloseHandle(hProcess)


У меня сегодня судьба со строками воевать.

Ответить

Номер ответа: 12
Автор ответа:
 GDK



Вопросов: 13
Ответов: 348
 Профиль | | #12 Добавлено: 29.12.08 14:25
Да. Массив символов. Я б ни за что сам не допёр до этого! И в интернете не находил ведь. VarPtr(s(0))-это указатель на часть памяти, содержащей первый элемент массива s()? А почему тогда для ToolBar(a) было Call ReadProcessMemory(hProcess, prc, rc, LenB(rc), rwb) 'прочитать RECT из памяти а не Call ReadProcessMemory(hProcess, prc, VarPtr(rc), LenB(rc), rwb)?
Ну а prc(=0) теперь буду в Debug.Print prc отслеживать.

Ответить

Номер ответа: 13
Автор ответа:
 GDK



Вопросов: 13
Ответов: 348
 Профиль | | #13 Добавлено: 29.12.08 14:32
В смысле для ToolBar'a.

Ответить

Номер ответа: 14
Автор ответа:
 Father



Вопросов: 0
Ответов: 159
 Профиль | | #14 Добавлено: 02.01.09 11:50
Смотря, как декларирована ReadProcessMemory.
  1.  
  2. Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
  3. Call ReadProcessMemory(hProcess, prc, s(0), L, rwb)

или так
  1.  
  2. Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByVal  lpBuffer As Long, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long
  3. Call ReadProcessMemory(hProcess, prc, ByVal VarPtr(s(0)), L, rwb)


Ответить

Номер ответа: 15
Автор ответа:
 GDK



Вопросов: 13
Ответов: 348
 Профиль | | #15 Добавлено: 14.01.09 13:29
Спасибо. Понял. Кстати всё получилось со строкой состояния кроме нулевого сектора. Там жёсткий облом. Но его мне не нужно было считывать поэтому разбираться не стал.
А Debug.Print "prc=" & prc всегда показывает нули.

Ответить

Страница: 1 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам