<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=399615&amp;view=findpost&amp;p=3574987</guid>
        <pubDate>Wed, 18 Feb 2015 17:55:43 +0000</pubDate>
        <title>Многопоточность в VB6 часть 3</title>
        <link>https://forum.sources.ru/index.php?showtopic=399615&amp;view=findpost&amp;p=3574987</link>
        <description><![CDATA[TheTrik: Эта часть скорее больше о внедрении DLL чем о многопоточности как таковой, но т.к. DLL может работать в программах с различным числом потоков то я сделал эту часть как продолжение темы о многопоточности в VB6. В прошлой части я написал о возможности создания потока в DLL, и о методе создания нативной DLL на VB6. Также я написал о том, что такая DLL будет работать в любом приложении, но примера не привел. В этой части мы напишем DLL которая будет выполняться в чужом 32-разрядном процессе и выполнять там наш код. В качестве примера сделаем приложение которое будет осуществлять сабклассинг окна в другом потоке и передавать в наше приложение сообщения, которые мы сможем обработать. Напишу сразу - DLL только для примера и не предназначена для работы в приложениях, т.к. имеются недостатки которые в качестве экономии кода я не устранял.<br>
Я решил сделать 3 случая использования:<ul class="tag-list"><li>Ограничение минимального размера перекрывающегося окна.</li><li>Отслеживания нажатий/отпусканий кнопок мыши в окне.</li><li>Лог сообщений.</li></ul>Итак, сначала нужно придумать механизм взаимодействия между процессами. Я решил пойти следующим путем:<ol class="tag-list" type="1"><li>Для обмена данными между приложениями будем использовать проецированный в память файл.</li><li>Для передачи сообщения от процесса-&quot;жертвы&quot; нашему приложению, будем использовать новое зарегистрированное сообщение.</li><li>Для уведомления о завершении сабклассинга передавать сообщение будем в другую сторону.</li></ol>Теперь нужно продумать как осуществлять запуск. Ставим хук <strong class='tag-b'>WH_GETMESSAGE</strong> на поток в котором содержится окно. Теперь наша DLL загрузится в АП процесса жертвы. В callback функции <strong class='tag-b'>GetMsgProc</strong> при первом вызове будем инициализировать данные и устанавливать сабклассинг на нужное окно, для обмена как было сказано выше используем файл-маппинг. Итак код:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&#39; modSubclassDLL.bas &nbsp;- процедуры хука и сабклассинга</div><div class="code_line">&#39; © Кривоус Анатолий Анатольевич (The trick), 2014</div><div class="code_line">&nbsp;</div><div class="code_line">Option Explicit</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; Эту структуру мы будем прередавать между процессами через файловое представление</div><div class="code_line">Public Type MsgData</div><div class="code_line">&nbsp;&nbsp; &nbsp;hWnd &nbsp; &nbsp;As Long &nbsp; &nbsp; &#39; Хендл сабклассируемого окна</div><div class="code_line">&nbsp;&nbsp; &nbsp;uMsg &nbsp; &nbsp;As Long &nbsp; &nbsp; &#39; Сообщение</div><div class="code_line">&nbsp;&nbsp; &nbsp;wParam &nbsp;As Long &nbsp; &nbsp; &#39; Параметры</div><div class="code_line">&nbsp;&nbsp; &nbsp;lParam &nbsp;As Long &nbsp; &nbsp; &#39; -</div><div class="code_line">&nbsp;&nbsp; &nbsp;return &nbsp;As Long &nbsp; &nbsp; &#39; Возвращаемое значение</div><div class="code_line">&nbsp;&nbsp; &nbsp;defCall As Long &nbsp; &nbsp; &#39; Вызывать ли изначальную процедуру</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">Private Declare Function OpenFileMapping Lib &quot;kernel32&quot; Alias &quot;OpenFileMappingW&quot; (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal lpName As Long) As Long</div><div class="code_line">Private Declare Function OpenMutex Lib &quot;kernel32&quot; Alias &quot;OpenMutexW&quot; (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal lpName As Long) As Long</div><div class="code_line">Private Declare Function MapViewOfFile Lib &quot;kernel32&quot; (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long</div><div class="code_line">Private Declare Function UnmapViewOfFile Lib &quot;kernel32&quot; (ByVal lpBaseAddress As Long) As Long</div><div class="code_line">Private Declare Function CloseHandle Lib &quot;kernel32&quot; (ByVal hObject As Long) As Long</div><div class="code_line">Private Declare Function GetMem4 Lib &quot;msvbvm60&quot; (Src As Any, Dst As Any) As Long</div><div class="code_line">Private Declare Function WaitForSingleObject Lib &quot;kernel32&quot; (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long</div><div class="code_line">Private Declare Function ReleaseMutex Lib &quot;kernel32&quot; (ByVal hMutex As Long) As Long</div><div class="code_line">Private Declare Function CallNextHookEx Lib &quot;user32&quot; (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Integer, lParam As Any) As Long</div><div class="code_line">Private Declare Function SendMessage Lib &quot;user32&quot; Alias &quot;SendMessageW&quot; (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long</div><div class="code_line">Private Declare Function SetWindowLong Lib &quot;user32&quot; Alias &quot;SetWindowLongW&quot; (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long</div><div class="code_line">Private Declare Function SetProp Lib &quot;user32&quot; Alias &quot;SetPropW&quot; (ByVal hWnd As Long, ByVal lpString As Long, ByVal hData As Long) As Long</div><div class="code_line">Private Declare Function RemoveProp Lib &quot;user32&quot; Alias &quot;RemovePropW&quot; (ByVal hWnd As Long, ByVal lpString As Long) As Long</div><div class="code_line">Private Declare Function GetProp Lib &quot;user32&quot; Alias &quot;GetPropW&quot; (ByVal hWnd As Long, ByVal lpString As Long) As Long</div><div class="code_line">Private Declare Function GlobalAddAtom Lib &quot;kernel32&quot; Alias &quot;GlobalAddAtomW&quot; (ByVal lpString As Long) As Integer</div><div class="code_line">Private Declare Function GlobalDeleteAtom Lib &quot;kernel32&quot; (ByVal nAtom As Integer) As Integer</div><div class="code_line">Private Declare Function RegisterWindowMessage Lib &quot;user32&quot; Alias &quot;RegisterWindowMessageW&quot; (ByVal lpString As Long) As Long</div><div class="code_line">Private Declare Function CallWindowProc Lib &quot;user32&quot; Alias &quot;CallWindowProcW&quot; (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long</div><div class="code_line">Private Declare Sub CopyMemory Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (Destination As Any, Source As Any, ByVal Length As Long)</div><div class="code_line">&nbsp;</div><div class="code_line">Private Const GWL_WNDPROC &nbsp; &nbsp; &nbsp; &nbsp;As Long = (-4)</div><div class="code_line">Private Const INFINITE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long = -1&amp;</div><div class="code_line">Private Const MUTEX_ALL_ACCESS &nbsp; As Long = &amp;H1F0001</div><div class="code_line">Private Const FILE_MAP_READ &nbsp; &nbsp; &nbsp;As Long = &amp;H4</div><div class="code_line">Private Const FILE_MAP_WRITE &nbsp; &nbsp; As Long = &amp;H2</div><div class="code_line">Private Const WAIT_FAILED &nbsp; &nbsp; &nbsp; &nbsp;As Long = -1&amp;</div><div class="code_line">&nbsp;</div><div class="code_line">Private WM_SENDMESSAGE &nbsp; As Long &nbsp; &nbsp;&#39; Наше сообщение для обмена с основной программой. Отсылая из текущего потока это сообщение</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; в наше приложение (TestSubclassDLL), мы уведомляем приложение через SendMessage о том, что</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; пришло новое сообщение, параметры которого записаны в файловое представление. Передавая из</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; главного (TestSubclassDLL) приложения сюда это сообщение, мы уведомляем о том, что нужно</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; снять сабклассинг и выполнить деинициализацию.</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">Dim hMutex &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &#39; Описатель мьютекса для синхронизации чтения/записи общих данных</div><div class="code_line">Dim hMap &nbsp; &nbsp; &nbsp; &nbsp;As Long &nbsp; &nbsp; &#39; Хендл файлового отображения</div><div class="code_line">Dim lpShrdData &nbsp;As Long &nbsp; &nbsp; &#39; Адрес общих данных</div><div class="code_line">Dim hWndServer &nbsp;As Long &nbsp; &nbsp; &#39; Хендл окна для приема и обработки сообщений</div><div class="code_line">Dim hWndHook &nbsp; &nbsp;As Long &nbsp; &nbsp; &#39; Хендл сабклассируемого окна в этом процессе</div><div class="code_line">Dim hHook &nbsp; &nbsp; &nbsp; As Long &nbsp; &nbsp; &#39; Хендл хука, для передачи в CallNextHookEx</div><div class="code_line">Dim aPrevProc &nbsp; As Integer &nbsp;&#39; Атом имени свойства изначальной оконной процедуры</div><div class="code_line">Dim init &nbsp; &nbsp; &nbsp; &nbsp;As Boolean &nbsp;&#39; Инициализирован ли сабклассинг</div><div class="code_line">Dim disabled &nbsp; &nbsp;As Boolean &nbsp;&#39; Сабклассинг окончен.</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Процедура хука</div><div class="code_line">Public Function GetMsgProc(ByVal code As Long, ByVal wParam As Long, ByVal lParam As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim prevProc &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если не инициализирован сабклассинг - инициализируем</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not (init Or disabled) Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Открываем проекцию</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;hMap = OpenFileMapping(FILE_MAP_WRITE, False, StrPtr(&quot;TrickSubclassFileMap&quot;))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If hMap = 0 Then MsgBox &quot;Невозможно открыть проекцию&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Проецируем</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lpShrdData = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CloseHandle hMap: hMap = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If lpShrdData = 0 Then MsgBox &quot;Невозможно отобразить представление&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Открываем синхронизирующий мьютекс</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;hMutex = OpenMutex(MUTEX_ALL_ACCESS, False, StrPtr(&quot;TrickSubclassMutex&quot;))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If hMutex = 0 Then MsgBox &quot;Невозможно отрыть мьютекс&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Регистрация сообщения</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;WM_SENDMESSAGE = RegisterWindowMessage(StrPtr(WM_SENDMESSAGE))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If WM_SENDMESSAGE = 0 Then MsgBox &quot;Невозможно Зарегистрировать сообщение&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Добавляем/получаем атом для сохранения предыдущей оконной процедуры</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;aPrevProc = GlobalAddAtom(StrPtr(&quot;prevProc&quot;))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If aPrevProc = 0 Then MsgBox &quot;Невозможно добавить атом&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Захватываем мьютекс. Если например в главном приложении еще не произошел выход из SetWindowsHookEx, то</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; еще неизвестен хендл хука, а т.к. у нас там уже захвачен этот мьютекс, то этот поток будет ждать пока</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; мьютекс не освободится, что произойдет только после записи хендля хука в общую память и остальных данных</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If WaitForSingleObject(hMutex, INFINITE) = WAIT_FAILED Then MsgBox &quot;Ошибка ожидания&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем хендл окна, которое будет принимать сообщения</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal lpShrdData, hWndServer</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем хендл сабклассируемого окна</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal lpShrdData + 4, hWndHook</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем хендл хука</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal lpShrdData + 8, hHook</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Освобождаем мьютекс</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ReleaseMutex hMutex</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем адрес оконной процедуры и задаем новый</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;prevProc = SetWindowLong(hWndHook, GWL_WNDPROC, AddressOf WndProc)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If prevProc = 0 Then MsgBox &quot;Невозможно заменить оконную процедуру&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Установка свойства окна</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;SetProp hWndHook, CLng(aPrevProc) And &amp;HFFFF&amp;, prevProc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Успех</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;init = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Передаем на обработку другим процедурам</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMsgProc = CallNextHookEx(hHook, code, wParam, lParam)</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Деинициализация</div><div class="code_line">Public Sub Clear()</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hMutex Then CloseHandle (hMutex): hMutex = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpShrdData Then UnmapViewOfFile (lpShrdData): lpShrdData = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hWndHook Then RemoveProp hWndHook, CLng(aPrevProc) And &amp;HFFFF&amp;: hWndHook = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;If aPrevProc Then GlobalDeleteAtom (aPrevProc): aPrevProc = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;init = False</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Оконная процедура</div><div class="code_line">Private Function WndProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim sendData &nbsp; &nbsp;As MsgData</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim prevProc &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Проверяем не снятие ли сабклассинга</div><div class="code_line">&nbsp;&nbsp; &nbsp;If uMsg = WM_SENDMESSAGE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем предыдущий адрес процедуры</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;prevProc = GetProp(hWnd, CLng(aPrevProc) And &amp;HFFFF&amp;)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Устанавливаем его оконной процедуре</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;SetWindowLong hWnd, GWL_WNDPROC, prevProc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Очистка</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Clear</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Отключаем сабклассинг</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Возможна ситуация когда будет вызвана GetMsgProc, до того, как будет снят хук в главно приложении</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; этот флаг предотвращает повторную инициализацию данных.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;disabled = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Теперь из главного приложения будет вызвана UnhookWindowsHookEx и наша DLL будет выгружена из памяти.</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Формируем запрос</div><div class="code_line">&nbsp;&nbsp; &nbsp;sendData.hWnd = hWnd</div><div class="code_line">&nbsp;&nbsp; &nbsp;sendData.uMsg = uMsg</div><div class="code_line">&nbsp;&nbsp; &nbsp;sendData.wParam = wParam</div><div class="code_line">&nbsp;&nbsp; &nbsp;sendData.lParam = lParam</div><div class="code_line">&nbsp;&nbsp; &nbsp;sendData.defCall = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Захватываем мьютекс</div><div class="code_line">&nbsp;&nbsp; &nbsp;If WaitForSingleObject(hMutex, INFINITE) = WAIT_FAILED Then MsgBox &quot;Ошибка ожидания&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal lpShrdData + 12, sendData, Len(sendData)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Освобождаем мьютекс</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReleaseMutex hMutex</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Отправляем сообщение главному окну</div><div class="code_line">&nbsp;&nbsp; &nbsp;SendMessage hWndServer, WM_SENDMESSAGE, 0, ByVal 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем результат обработки</div><div class="code_line">&nbsp;&nbsp; &nbsp;If WaitForSingleObject(hMutex, INFINITE) = WAIT_FAILED Then MsgBox &quot;Ошибка ожидания&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory sendData, ByVal lpShrdData + 12, Len(sendData)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Освобождаем мьютекс</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReleaseMutex hMutex</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Следует ли обрабатывать его дальше</div><div class="code_line">&nbsp;&nbsp; &nbsp;If sendData.defCall Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;prevProc = GetProp(hWnd, CLng(aPrevProc) And &amp;HFFFF&amp;)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;WndProc = CallWindowProc(prevProc, sendData.hWnd, sendData.uMsg, sendData.wParam, sendData.lParam)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;WndProc = sendData.return</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">End Function</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
Разберем подробно код. В процедуре инициализации проверяем флаги инициализации и отключения сабклассинга.  Если какой-либо <strong class='tag-b'>True</strong>, то значит либо сабклассинг установлен, либо закончен. Иначе начинаем инициализацию. Первым делом открываем файл-маппинг и проецируем представление на АП процесса. Для избежания состояния гонки используем синхронизирующий объект мьютекс. Потом регистрируем сообщение <strong class='tag-b'>WM_SENDMESSAGE</strong> для обмена в системе и получаем его номер. Для хранения адреса предыдущей оконной процедуры я решил использовать свойство окна, хотя можно было бы использовать и переменную модуля, т.к. за раз можно только перехватить только одно окно в этой реализации. Для ускоренного доступа к свойству я использую атом, поэтому регистрируем его с именем <strong class='tag-b'>prevProc</strong>. Потом пытаемся захватить мьютекс. Когда это удается, то общие данные доступны только для этого потока, никакой другой поток не сможет что-то записать туда и мы избежим состояния гонки. Из файл-маппинга достаем нужные нам данные (хендл главного окна нашего приложения, хендл сабклассируемого окна и хендл хука, его нужно передать в <strong class='tag-b'>CallNextHookEx</strong>). Позже освобождаем мьютекс, и устанавливаем адрес оконной процедуры на наш (сабклассируем окно). Теперь все сообщения предназначенные для окна пойдут в процедуру <strong class='tag-b'>WndProc</strong>.<br>
Разберем процедуру <strong class='tag-b'>WndProc</strong>. Для начала разберем структуру файл-маппинга:<br>
<div class='tag-align-center'><img class='tag-img' src='http://s7.hostingkartinok.com/uploads/images/2014/11/18d231d22c7a250d0ef6ed4a8d933573.png' alt='user posted image'></div><br>
 Проверяем сообщение, если это наше зарегистрированное, то его может отправить только наше приложение при снятии сабклассинга, поэтому выполняем деинициализацию. Иначе формируем данные сообщения и, захватив мьютекс, пишем их в файл маппинг со смещения 0x0Ch (12<sub class='tag-sub'>10</sub>) и передаем их в главное окно нашего приложения для обработки. Т.к. мы используем <strong class='tag-b'>SendMessage</strong> для передачи, выход из нее не произойдет пока мы в своем приложении не завершим обработку этого сообщения. При возврате проверяем флаг <strong class='tag-b'>defCall</strong>, который отвечает пускать ли сообщение дальше в старую оконную процедуру или нет.<br>
Теперь разберем главное приложение:<br>
Модуль:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&#39; modMain.bas - демонстрация работы многопоточности в NativeDLL на примере внедрения DLL и выполнению сабклассинга</div><div class="code_line">&#39; © Кривоус Анатолий Анатольевич (The trick), 2014</div><div class="code_line">&nbsp;</div><div class="code_line">Option Explicit</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; Соответствует из SubclassDLL</div><div class="code_line">Public Type MsgData</div><div class="code_line">&nbsp;&nbsp; &nbsp;hwnd &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;uMsg &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;wParam &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lParam &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;return &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;defCall As Long</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">Public Type POINTAPI</div><div class="code_line">&nbsp;&nbsp; &nbsp;x &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;y &nbsp; As Long</div><div class="code_line">End Type</div><div class="code_line">Public Type MINMAXINFO</div><div class="code_line">&nbsp;&nbsp; &nbsp;ptReserved &nbsp; &nbsp; &nbsp;As POINTAPI</div><div class="code_line">&nbsp;&nbsp; &nbsp;ptMaxSize &nbsp; &nbsp; &nbsp; As POINTAPI</div><div class="code_line">&nbsp;&nbsp; &nbsp;ptMaxPosition &nbsp; As POINTAPI</div><div class="code_line">&nbsp;&nbsp; &nbsp;ptMinTrackSize &nbsp;As POINTAPI</div><div class="code_line">&nbsp;&nbsp; &nbsp;ptMaxTrackSize &nbsp;As POINTAPI</div><div class="code_line">End Type</div><div class="code_line">Public Type RECT</div><div class="code_line">&nbsp;&nbsp; &nbsp;Left &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Top &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Right &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Bottom &nbsp;As Long</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">Public Declare Function OffsetRect Lib &quot;user32&quot; (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long</div><div class="code_line">Public Declare Function GetWindowRect Lib &quot;user32&quot; (ByVal hwnd As Long, lpRect As RECT) As Long</div><div class="code_line">Public Declare Function ReleaseDC Lib &quot;user32&quot; (ByVal hwnd As Long, ByVal hdc As Long) As Long</div><div class="code_line">Public Declare Function GetWindowRgn Lib &quot;user32&quot; (ByVal hwnd As Long, ByVal hRgn As Long) As Long</div><div class="code_line">Public Declare Function CreateRectRgn Lib &quot;gdi32&quot; (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long</div><div class="code_line">Public Declare Function DeleteObject Lib &quot;gdi32&quot; (ByVal hObject As Long) As Long</div><div class="code_line">Public Declare Function FrameRgn Lib &quot;gdi32&quot; (ByVal hdc As Long, ByVal hRgn As Long, ByVal hBrush As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long</div><div class="code_line">Public Declare Function FrameRect Lib &quot;user32&quot; (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long</div><div class="code_line">Public Declare Function GetWindowDC Lib &quot;user32&quot; (ByVal hwnd As Long) As Long</div><div class="code_line">Public Declare Function GetStockObject Lib &quot;gdi32&quot; (ByVal nIndex As Long) As Long</div><div class="code_line">Public Declare Function SetROP2 Lib &quot;gdi32&quot; (ByVal hdc As Long, ByVal nDrawMode As Long) As Long</div><div class="code_line">Public Declare Function GetROP2 Lib &quot;gdi32&quot; (ByVal hdc As Long) As Long</div><div class="code_line">Public Declare Function WriteProcessMemory Lib &quot;kernel32&quot; (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long</div><div class="code_line">Public Declare Function ReadProcessMemory Lib &quot;kernel32&quot; (ByVal hProcess As Long, lpBaseAddress As Any, lpBuffer As Any, ByVal nSize As Long, lpNumberOfBytesWritten As Long) As Long</div><div class="code_line">Public Declare Function WindowFromPoint Lib &quot;user32&quot; (ByVal xPoint As Long, ByVal yPoint As Long) As Long</div><div class="code_line">Public Declare Function GetCursorPos Lib &quot;user32&quot; (lpPoint As POINTAPI) As Long</div><div class="code_line">Public Declare Function OpenProcess Lib &quot;kernel32&quot; (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long</div><div class="code_line">Public Declare Function CreateFileMapping Lib &quot;kernel32&quot; Alias &quot;CreateFileMappingW&quot; (ByVal hFile As Long, lpFileMappigAttributes As Any, ByVal flProtect As Long, ByVal dwMaximumSizeHigh As Long, ByVal dwMaximumSizeLow As Long, ByVal lpName As Long) As Long</div><div class="code_line">Public Declare Function MapViewOfFile Lib &quot;kernel32&quot; (ByVal hFileMappingObject As Long, ByVal dwDesiredAccess As Long, ByVal dwFileOffsetHigh As Long, ByVal dwFileOffsetLow As Long, ByVal dwNumberOfBytesToMap As Long) As Long</div><div class="code_line">Public Declare Function UnmapViewOfFile Lib &quot;kernel32&quot; (ByVal lpBaseAddress As Long) As Long</div><div class="code_line">Public Declare Function CloseHandle Lib &quot;kernel32&quot; (ByVal hObject As Long) As Long</div><div class="code_line">Public Declare Function CreateMutex Lib &quot;kernel32&quot; Alias &quot;CreateMutexW&quot; (lpMutexAttributes As Any, ByVal bInitialOwner As Long, ByVal lpName As Long) As Long</div><div class="code_line">Public Declare Function SetWindowsHookEx Lib &quot;user32&quot; Alias &quot;SetWindowsHookExW&quot; (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long</div><div class="code_line">Public Declare Function UnhookWindowsHookEx Lib &quot;user32&quot; (ByVal hHook As Long) As Long</div><div class="code_line">Public Declare Function LoadLibrary Lib &quot;kernel32&quot; Alias &quot;LoadLibraryW&quot; (ByVal lpLibFileName As Long) As Long</div><div class="code_line">Public Declare Function GetProcAddress Lib &quot;kernel32&quot; (ByVal hModule As Long, ByVal lpProcName As String) As Long</div><div class="code_line">Public Declare Function FreeLibrary Lib &quot;kernel32&quot; (ByVal hLibModule As Long) As Long</div><div class="code_line">Public Declare Function GetMem4 Lib &quot;msvbvm60&quot; (Src As Any, Dst As Any) As Long</div><div class="code_line">Public Declare Function WaitForSingleObject Lib &quot;kernel32&quot; (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long</div><div class="code_line">Public Declare Function ReleaseMutex Lib &quot;kernel32&quot; (ByVal hMutex As Long) As Long</div><div class="code_line">Public Declare Function GetWindowThreadProcessId Lib &quot;user32&quot; (ByVal hwnd As Long, lpdwProcessId As Long) As Long</div><div class="code_line">Public Declare Function SendMessage Lib &quot;user32&quot; Alias &quot;SendMessageW&quot; (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long</div><div class="code_line">Public Declare Function RegisterWindowMessage Lib &quot;user32&quot; Alias &quot;RegisterWindowMessageW&quot; (ByVal lpString As Long) As Long</div><div class="code_line">Public Declare Function SetWindowLong Lib &quot;user32&quot; Alias &quot;SetWindowLongW&quot; (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long</div><div class="code_line">Public Declare Function CallWindowProc Lib &quot;user32&quot; Alias &quot;CallWindowProcW&quot; (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long</div><div class="code_line">Public Declare Sub CopyMemory Lib &quot;kernel32&quot; Alias &quot;RtlMoveMemory&quot; (Destination As Any, Source As Any, ByVal Length As Long)</div><div class="code_line">&nbsp;</div><div class="code_line">Public Const GWL_WNDPROC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long = (-4)</div><div class="code_line">Public Const ERROR_ALREADY_EXISTS &nbsp; As Long = 183&amp;</div><div class="code_line">Public Const INVALID_HANDLE_VALUE &nbsp; As Long = -1</div><div class="code_line">Public Const PAGE_READWRITE &nbsp; &nbsp; &nbsp; &nbsp; As Long = &amp;H4&amp;</div><div class="code_line">Public Const FILE_MAP_WRITE &nbsp; &nbsp; &nbsp; &nbsp; As Long = &amp;H2</div><div class="code_line">Public Const INFINITE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long = -1&amp;</div><div class="code_line">Public Const WAIT_FAILED &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long = -1&amp;</div><div class="code_line">Public Const WH_GETMESSAGE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long = 3</div><div class="code_line">Public Const PROCESS_VM_OPERATION &nbsp; As Long = &amp;H8&amp;</div><div class="code_line">Public Const PROCESS_VM_READ &nbsp; &nbsp; &nbsp; &nbsp;As Long = &amp;H10&amp;</div><div class="code_line">Public Const PROCESS_VM_WRITE &nbsp; &nbsp; &nbsp; As Long = &amp;H20&amp;</div><div class="code_line">Public Const WM_GETMINMAXINFO &nbsp; &nbsp; &nbsp; As Long = &amp;H24</div><div class="code_line">Public Const WHITE_BRUSH &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long = 0</div><div class="code_line">Public Const R2_XORPEN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long = 7</div><div class="code_line">Public Const NULLREGION &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long = 1</div><div class="code_line">Public Const WM_LBUTTONDOWN &nbsp; &nbsp; &nbsp; &nbsp; As Long = &amp;H201&amp;</div><div class="code_line">Public Const WM_LBUTTONUP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long = &amp;H202&amp;</div><div class="code_line">&nbsp;</div><div class="code_line">Public WM_SENDMESSAGE &nbsp; As Long &#39; Наше сообщение</div><div class="code_line">Public hProcess &nbsp; &nbsp; &nbsp; &nbsp; As Long &#39; Хендл процесса, в котором стоит хук</div><div class="code_line">&nbsp;</div><div class="code_line">Dim hMutex &nbsp; &nbsp; &nbsp;As Long &#39; Мьютекс, для синхронизации записи и чтения</div><div class="code_line">Dim lpShrdData &nbsp;As Long &#39; Адрес общей памяти (доступной обоим процессам)</div><div class="code_line">Dim hLib &nbsp; &nbsp; &nbsp; &nbsp;As Long &#39; Хендл SubclassDLL</div><div class="code_line">Dim lpProc &nbsp; &nbsp; &nbsp;As Long &#39; Адрес GetMsgProc</div><div class="code_line">Dim hHook &nbsp; &nbsp; &nbsp; As Long &#39; Хендл хука</div><div class="code_line">Dim TID &nbsp; &nbsp; &nbsp; &nbsp; As Long &#39; ИД потока</div><div class="code_line">Dim PID &nbsp; &nbsp; &nbsp; &nbsp; As Long &#39; ИД процесса</div><div class="code_line">Dim hMap &nbsp; &nbsp; &nbsp; &nbsp;As Long &#39; Хендл проекции</div><div class="code_line">Dim lpPrevProc &nbsp;As Long &#39; Адрес изначальной оконной процедуры frmMain</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Инициализация</div><div class="code_line">Public Function Initialize() As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Создаем мьютекс для синхронизации</div><div class="code_line">&nbsp;&nbsp; &nbsp;hMutex = CreateMutex(ByVal 0&amp;, 0, StrPtr(&quot;TrickSubclassMutex&quot;))</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hMutex = 0 Then MsgBox &quot;Невозможно создать мьютекс&quot;: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Err.LastDllError = ERROR_ALREADY_EXISTS Then MsgBox &quot;Один экземпляр уже запущен&quot;: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Создаем проекцию</div><div class="code_line">&nbsp;&nbsp; &nbsp;hMap = CreateFileMapping(INVALID_HANDLE_VALUE, ByVal 0&amp;, PAGE_READWRITE, 0, 100, StrPtr(&quot;TrickSubclassFileMap&quot;))</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hMap = 0 Then MsgBox &quot;Невозможно создать проекцию&quot;: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Проецируем</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpShrdData = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpShrdData = 0 Then MsgBox &quot;Невозможно отобразить представление&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Регистрация сообщения</div><div class="code_line">&nbsp;&nbsp; &nbsp;WM_SENDMESSAGE = RegisterWindowMessage(StrPtr(WM_SENDMESSAGE))</div><div class="code_line">&nbsp;&nbsp; &nbsp;If WM_SENDMESSAGE = 0 Then MsgBox &quot;Невозможно Зарегистрировать сообщение&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Сабклассинг нашего окна для приема сообщений</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpPrevProc = SetWindowLong(frmMain.hwnd, GWL_WNDPROC, AddressOf WndProc)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Загружаем DLL</div><div class="code_line">&nbsp;&nbsp; &nbsp;hLib = LoadLibrary(StrPtr(&quot;..\SubclassDLL\SubclassDLL&quot;))</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hLib = 0 Then MsgBox &quot;Невозможно загрузить модуль&quot;: ReleaseMutex hMutex: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpProc = GetProcAddress(hLib, &quot;GetMsgProc&quot;)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpProc = 0 Then MsgBox &quot;Невозможно найти функцию GetMsgProc&quot;: ReleaseMutex hMutex: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;Initialize = True</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Деинициализация</div><div class="code_line">Public Sub Clear()</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hMap Then CloseHandle (hMap)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hMutex Then CloseHandle (hMutex)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpShrdData Then UnmapViewOfFile (lpShrdData)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hLib Then FreeLibrary (hLib)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpPrevProc Then SetWindowLong frmMain.hwnd, GWL_WNDPROC, lpPrevProc</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hProcess Then CloseHandle (hProcess)</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Установить сабклассинг</div><div class="code_line">Public Function StartSubclass(ByVal hwnd As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем идентификатор потока</div><div class="code_line">&nbsp;&nbsp; &nbsp;TID = GetWindowThreadProcessId(hwnd, PID)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If TID = 0 Then MsgBox &quot;Невозможно получить ИД потока&quot;: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Нельзя сабклассить свои окна, иначе может произойти рекурсия</div><div class="code_line">&nbsp;&nbsp; &nbsp;If TID = App.ThreadID Then MsgBox &quot;Нельзя сабклассить свои окна&quot;: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если был сабклассинг, то убираем</div><div class="code_line">&nbsp;&nbsp; &nbsp;StopSubclass hwnd</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Открываем процесс</div><div class="code_line">&nbsp;&nbsp; &nbsp;hProcess = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_WRITE Or PROCESS_VM_READ, 0, PID)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hProcess = 0 Then MsgBox &quot;Невозможно открыть процесс&quot;: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Захватываем мьютекс</div><div class="code_line">&nbsp;&nbsp; &nbsp;If WaitForSingleObject(hMutex, INFINITE) = WAIT_FAILED Then MsgBox &quot;Ошибка ожидания&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Ставим хук на прием сообщений в нужном потоке</div><div class="code_line">&nbsp;&nbsp; &nbsp;hHook = SetWindowsHookEx(WH_GETMESSAGE, lpProc, hLib, TID)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hHook = 0 Then MsgBox &quot;Невозможно поставить хук&quot;: ReleaseMutex hMutex: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Записываем хендл окна приемника сообщений</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 CLng(frmMain.hwnd), ByVal lpShrdData</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Записываем хендл сабклассируемого окна</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 hwnd, ByVal lpShrdData + 4</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Записываем хендл хука</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 hHook, ByVal lpShrdData + 8</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Освобождаем мьютекс, код в другом процессе теперь сможет читать эти данные</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReleaseMutex hMutex</div><div class="code_line">&nbsp;&nbsp; &nbsp;StartSubclass = True</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Снять сабклассинг</div><div class="code_line">Public Function StopSubclass(ByVal hwnd As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hHook Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Отправляем окну наше сообщение, в другом процессе наш обработчик обработает его и снимет сабклассинг</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;SendMessage hwnd, WM_SENDMESSAGE, 0, ByVal 0&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Снимаем хук, в другом процессе библиотека выгружается</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;UnhookWindowsHookEx (hHook): hHook = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Закрываем описатель процесса</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CloseHandle hProcess: hProcess = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;StopSubclass = True</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Оконная процедура</div><div class="code_line">Private Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Select Case uMsg</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case WM_SENDMESSAGE</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Dim msg As MsgData</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Захватываем мьютекс, хотя можно и не ожидать, потому что поток все равно спит, т.к. был вызов SendMessage</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; но если сабклассить несколько окон, то вызов обязателен</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If WaitForSingleObject(hMutex, INFINITE) = WAIT_FAILED Then MsgBox &quot;Ошибка ожидания&quot;, vbCritical: Clear: Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Копируем данные сообщения в переменную</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CopyMemory msg, ByVal lpShrdData + 12, Len(msg)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Вызываем наш обработчик</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;msg.return = frmMain.WndProc(msg.hwnd, msg.uMsg, msg.wParam, msg.lParam, msg.defCall)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Копируем обратно</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;CopyMemory ByVal lpShrdData + 12, msg, Len(msg)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Освобождаем мьютекс</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ReleaseMutex hMutex</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;WndProc = CallWindowProc(lpPrevProc, hwnd, uMsg, wParam, lParam)</div><div class="code_line">&nbsp;&nbsp; &nbsp;End Select</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Список сообщений</div><div class="code_line">Public Sub SetWMList(msgList() As String)</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim msgList(&amp;H38F)</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H0) = &quot;WM_NULL&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H1) = &quot;WM_CREATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2) = &quot;WM_DESTROY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H3) = &quot;WM_MOVE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H5) = &quot;WM_SIZE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H6) = &quot;WM_ACTIVATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H7) = &quot;WM_SETFOCUS&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H8) = &quot;WM_KILLFOCUS&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA) = &quot;WM_ENABLE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HB) = &quot;WM_SETREDRAW&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HC) = &quot;WM_SETTEXT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HD) = &quot;WM_GETTEXT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HE) = &quot;WM_GETTEXTLENGTH&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HF) = &quot;WM_PAINT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H10) = &quot;WM_CLOSE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H11) = &quot;WM_QUERYENDSESSION&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H12) = &quot;WM_QUIT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H13) = &quot;WM_QUERYOPEN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H14) = &quot;WM_ERASEBKGND&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H15) = &quot;WM_SYSCOLORCHANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H16) = &quot;WM_ENDSESSION&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H18) = &quot;WM_SHOWWINDOW&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H19) = &quot;WM_CTLCOLOR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H1A) = &quot;WM_WININICHANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H1B) = &quot;WM_DEVMODECHANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H1C) = &quot;WM_ACTIVATEAPP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H1D) = &quot;WM_FONTCHANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H1E) = &quot;WM_TIMECHANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H1F) = &quot;WM_CANCELMODE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H20) = &quot;WM_SETCURSOR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H21) = &quot;WM_MOUSEACTIVATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H22) = &quot;WM_CHILDACTIVATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H23) = &quot;WM_QUEUESYNC&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H24) = &quot;WM_GETMINMAXINFO&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H26) = &quot;WM_PAINTICON&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H27) = &quot;WM_ICONERASEBKGND&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H28) = &quot;WM_NEXTDLGCTL&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2A) = &quot;WM_SPOOLERSTATUS&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2B) = &quot;WM_DRAWITEM&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2C) = &quot;WM_MEASUREITEM&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2D) = &quot;WM_DELETEITEM&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2E) = &quot;WM_VKEYTOITEM&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2F) = &quot;WM_CHARTOITEM&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H30) = &quot;WM_SETFONT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H31) = &quot;WM_GETFONT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H32) = &quot;WM_SETHOTKEY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H33) = &quot;WM_GETHOTKEY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H37) = &quot;WM_QUERYDRAGICON&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H39) = &quot;WM_COMPAREITEM&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H3D) = &quot;WM_GETOBJECT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H41) = &quot;WM_COMPACTING&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H44) = &quot;WM_COMMNOTIFY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H46) = &quot;WM_WINDOWPOSCHANGING&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H47) = &quot;WM_WINDOWPOSCHANGED&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H48) = &quot;WM_POWER&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H49) = &quot;WM_COPYGLOBALDATA&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H4A) = &quot;WM_COPYDATA&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H4B) = &quot;WM_CANCELJOURNAL&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H4E) = &quot;WM_NOTIFY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H50) = &quot;WM_INPUTLANGCHANGEREQUEST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H51) = &quot;WM_INPUTLANGCHANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H52) = &quot;WM_TCARD&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H53) = &quot;WM_HELP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H54) = &quot;WM_USERCHANGED&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H55) = &quot;WM_NOTIFYFORMAT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H7B) = &quot;WM_CONTEXTMENU&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H7C) = &quot;WM_STYLECHANGING&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H7D) = &quot;WM_STYLECHANGED&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H7E) = &quot;WM_DISPLAYCHANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H7F) = &quot;WM_GETICON&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H80) = &quot;WM_SETICON&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H81) = &quot;WM_NCCREATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H82) = &quot;WM_NCDESTROY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H83) = &quot;WM_NCCALCSIZE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H84) = &quot;WM_NCHITTEST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H85) = &quot;WM_NCPAINT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H86) = &quot;WM_NCACTIVATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H87) = &quot;WM_GETDLGCODE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H88) = &quot;WM_SYNCPAINT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA0) = &quot;WM_NCMOUSEMOVE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA1) = &quot;WM_NCLBUTTONDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA2) = &quot;WM_NCLBUTTONUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA3) = &quot;WM_NCLBUTTONDBLCLK&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA4) = &quot;WM_NCRBUTTONDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA5) = &quot;WM_NCRBUTTONUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA6) = &quot;WM_NCRBUTTONDBLCLK&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA7) = &quot;WM_NCMBUTTONDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA8) = &quot;WM_NCMBUTTONUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HA9) = &quot;WM_NCMBUTTONDBLCLK&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HAB) = &quot;WM_NCXBUTTONDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HAC) = &quot;WM_NCXBUTTONUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HAD) = &quot;WM_NCXBUTTONDBLCLK&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HE0) = &quot;SBM_SETPOS&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HE1) = &quot;SBM_GETPOS&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HE2) = &quot;SBM_SETRANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HE3) = &quot;SBM_GETRANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HE4) = &quot;SBM_ENABLE_ARROWS&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HE6) = &quot;SBM_SETRANGEREDRAW&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HE9) = &quot;SBM_SETSCROLLINFO&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HEA) = &quot;SBM_GETSCROLLINFO&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HEB) = &quot;SBM_GETSCROLLBARINFO&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;HFF) = &quot;WM_INPUT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H100) = &quot;WM_KEYDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H101) = &quot;WM_KEYUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H102) = &quot;WM_CHAR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H103) = &quot;WM_DEADCHAR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H104) = &quot;WM_SYSKEYDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H105) = &quot;WM_SYSKEYUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H106) = &quot;WM_SYSCHAR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H107) = &quot;WM_SYSDEADCHAR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H108) = &quot;WM_KEYLAST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H109) = &quot;WM_WNT_CONVERTREQUESTEX&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H10A) = &quot;WM_CONVERTREQUEST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H10B) = &quot;WM_CONVERTRESULT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H10C) = &quot;WM_INTERIM&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H10D) = &quot;WM_IME_STARTCOMPOSITION&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H10E) = &quot;WM_IME_ENDCOMPOSITION&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H10F) = &quot;WM_IME_COMPOSITION&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H110) = &quot;WM_INITDIALOG&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H111) = &quot;WM_COMMAND&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H112) = &quot;WM_SYSCOMMAND&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H113) = &quot;WM_TIMER&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H114) = &quot;WM_HSCROLL&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H115) = &quot;WM_VSCROLL&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H116) = &quot;WM_INITMENU&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H117) = &quot;WM_INITMENUPOPUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H118) = &quot;WM_SYSTIMER&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H11F) = &quot;WM_MENUSELECT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H120) = &quot;WM_MENUCHAR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H121) = &quot;WM_ENTERIDLE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H122) = &quot;WM_MENURBUTTONUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H123) = &quot;WM_MENUDRAG&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H124) = &quot;WM_MENUGETOBJECT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H125) = &quot;WM_UNINITMENUPOPUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H126) = &quot;WM_MENUCOMMAND&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H127) = &quot;WM_CHANGEUISTATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H128) = &quot;WM_UPDATEUISTATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H129) = &quot;WM_QUERYUISTATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H132) = &quot;WM_CTLCOLORMSGBOX&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H133) = &quot;WM_CTLCOLOREDIT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H134) = &quot;WM_CTLCOLORLISTBOX&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H135) = &quot;WM_CTLCOLORBTN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H136) = &quot;WM_CTLCOLORDLG&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H137) = &quot;WM_CTLCOLORSCROLLBAR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H138) = &quot;WM_CTLCOLORSTATIC&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H200) = &quot;WM_MOUSEMOVE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H201) = &quot;WM_LBUTTONDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H202) = &quot;WM_LBUTTONUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H203) = &quot;WM_LBUTTONDBLCLK&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H204) = &quot;WM_RBUTTONDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H205) = &quot;WM_RBUTTONUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H206) = &quot;WM_RBUTTONDBLCLK&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H207) = &quot;WM_MBUTTONDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H208) = &quot;WM_MBUTTONUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H209) = &quot;WM_MBUTTONDBLCLK&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H20A) = &quot;WM_MOUSEWHEEL&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H20B) = &quot;WM_XBUTTONDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H20C) = &quot;WM_XBUTTONUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H20D) = &quot;WM_XBUTTONDBLCLK&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H210) = &quot;WM_PARENTNOTIFY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H211) = &quot;WM_ENTERMENULOOP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H212) = &quot;WM_EXITMENULOOP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H213) = &quot;WM_NEXTMENU&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H214) = &quot;WM_SIZING&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H215) = &quot;WM_CAPTURECHANGED&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H216) = &quot;WM_MOVING&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H218) = &quot;WM_POWERBROADCAST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H219) = &quot;WM_DEVICECHANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H220) = &quot;WM_MDICREATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H221) = &quot;WM_MDIDESTROY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H222) = &quot;WM_MDIACTIVATE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H223) = &quot;WM_MDIRESTORE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H224) = &quot;WM_MDINEXT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H225) = &quot;WM_MDIMAXIMIZE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H226) = &quot;WM_MDITILE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H227) = &quot;WM_MDICASCADE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H228) = &quot;WM_MDIICONARRANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H229) = &quot;WM_MDIGETACTIVE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H230) = &quot;WM_MDISETMENU&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H231) = &quot;WM_ENTERSIZEMOVE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H232) = &quot;WM_EXITSIZEMOVE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H233) = &quot;WM_DROPFILES&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H234) = &quot;WM_MDIREFRESHMENU&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H280) = &quot;WM_IME_REPORT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H281) = &quot;WM_IME_SETCONTEXT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H282) = &quot;WM_IME_NOTIFY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H283) = &quot;WM_IME_CONTROL&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H284) = &quot;WM_IME_COMPOSITIONFULL&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H285) = &quot;WM_IME_SELECT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H286) = &quot;WM_IME_CHAR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H288) = &quot;WM_IME_REQUEST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H290) = &quot;WM_IME_KEYDOWN&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H291) = &quot;WM_IME_KEYUP&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2A0) = &quot;WM_NCMOUSEHOVER&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2A1) = &quot;WM_MOUSEHOVER&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2A2) = &quot;WM_NCMOUSELEAVE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H2A3) = &quot;WM_MOUSELEAVE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H300) = &quot;WM_CUT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H301) = &quot;WM_COPY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H302) = &quot;WM_PASTE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H303) = &quot;WM_CLEAR&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H304) = &quot;WM_UNDO&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H305) = &quot;WM_RENDERFORMAT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H306) = &quot;WM_RENDERALLFORMATS&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H307) = &quot;WM_DESTROYCLIPBOARD&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H308) = &quot;WM_DRAWCLIPBOARD&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H309) = &quot;WM_PAINTCLIPBOARD&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H30A) = &quot;WM_VSCROLLCLIPBOARD&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H30B) = &quot;WM_SIZECLIPBOARD&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H30C) = &quot;WM_ASKCBFORMATNAME&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H30D) = &quot;WM_CHANGECBCHAIN&quot;</div><div class="code_line">&nbsp;&nbsp;TrickSubclassMutex &nbsp;msgList(&amp;H30E) = &quot;WM_H8) = WM_NCACTIVATEWM_CTLCOLORSCROLLBARWM_CHANGECBCHAINHSCROLLCLIPBOARD&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H30F) = &quot;WM_QUERYNEWPALETTE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H310) = &quot;WM_PALETTEISCHANGING&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H311) = &quot;WM_PALETTECHANGED&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H312) = &quot;WM_HOTKEY&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H317) = &quot;WM_PRINT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H318) = &quot;WM_PRINTCLIENT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;WM_MDICASCADEmsgList(&amp;H319) = &quot;WM_APPCOMMAND&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H358) = &quot;WM_HANDHELDFIRST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H35F) = &quot;WM_HANDHELDLAST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H360) = &quot;WM_AFXFIRST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H37F) = &quot;WM_AFXLAST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H380) = &quot;WM_PENWINFIRST&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H381) = &quot;WM_RCRESULT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H382) = &quot;WM_HOOKRCRESULT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H383) = &quot;WM_GLOBALRCCHANGE&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H384) = &quot;WM_SKB&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H385) = &quot;WM_PENCTL&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H386) = &quot;WM_PENMISC&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H387) = &quot;WM_CTLINIT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H388) = &quot;WM_PENEVENT&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;msgList(&amp;H38F) = &quot;WM_PENWINLAST&quot;</div><div class="code_line">End Sub</div></ol></div></div></div></div><br>
Форма:<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&#39; frmMain.frm - демонстрация работы многопоточности в NativeDLL на примере внедрения DLL и выполнению сабклассинга</div><div class="code_line">&#39; © Кривоус Анатолий Анатольевич (The trick), 2014</div><div class="code_line">&nbsp;</div><div class="code_line">Option Explicit</div><div class="code_line">&nbsp;</div><div class="code_line">Dim isDown &nbsp; &nbsp; &nbsp;As Boolean &nbsp; &nbsp; &nbsp;&#39; Флаг поиска</div><div class="code_line">Dim curHwnd &nbsp; &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &#39; Текущее сабклассируемое окно</div><div class="code_line">Dim prevWnd &nbsp; &nbsp; As Long &nbsp; &nbsp; &nbsp; &nbsp; &#39; Предыдущее помеченное окно</div><div class="code_line">Dim mIcon &nbsp; &nbsp; &nbsp; As StdPicture &nbsp; &#39; Иконка окна</div><div class="code_line">Dim iconHeight &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &#39; Высота состояния иконки</div><div class="code_line">Dim msgList() &nbsp; As String &nbsp; &nbsp; &nbsp; &#39; Список сообщений</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Обработчик сабклассируемого окна (указатели соответствуют адресам в АП сабклассируемого процесса)</div><div class="code_line">Public Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, defCall As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; В зависимости от выбора вкладки:</div><div class="code_line">&nbsp;&nbsp; &nbsp;Select Case tabMain.SelectedItem.Index</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Ограничение на минимальный размер окна</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Select Case uMsg</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case WM_GETMINMAXINFO</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Dim mmInf &nbsp; As MINMAXINFO</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем структуру MINMAXINFO из процесса, в котором нужное окно</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If ReadProcessMemory(hProcess, ByVal lParam, mmInf, Len(mmInf), 0) = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Устанавливаем ограничения</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mmInf.ptMinTrackSize.x = sldWidth.Value</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;mmInf.ptMinTrackSize.y = sldHeight.Value</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Записываем назад в АП нужного процесса</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WriteProcessMemory hProcess, ByVal lParam, mmInf, Len(mmInf), 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Вызов по умолчанию не нужен</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;defCall = False</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End Select</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Клик в окне, просто меняем цвет фона вкладки и показываем лейбл</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Select Case uMsg</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case WM_LBUTTONDOWN</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;picContainer(1).BackColor = vbHighlight</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lblClick.Visible = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Case WM_LBUTTONUP</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;picContainer(1).BackColor = vbButtonFace</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lblClick.Visible = False</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End Select</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 3</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Лог сообщений</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Dim sMsg As String</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Проверяем имя сообщения</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If uMsg &#62; UBound(msgList) Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sMsg = &quot;Unknown 0x&quot; &amp; Hex(uMsg)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If Len(msgList(uMsg)) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sMsg = &quot;Unknown 0x&quot; &amp; Hex(uMsg)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sMsg = msgList(uMsg)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Добавляем в список вместе с параметрами</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;With lvwMsg.ListItems.Add(, , sMsg)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.SubItems(1) = wParam</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.SubItems(2) = lParam</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Чтобы видно было всегда было последнее сообщение</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;.Selected = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End With</div><div class="code_line">&nbsp;&nbsp; &nbsp;End Select</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Получить хендл окна в котором находится курсор</div><div class="code_line">Private Function GetWindowFromCursor() As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim pt As POINTAPI</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем координаты курсора</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetCursorPos pt</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем хендл окна</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetWindowFromCursor = WindowFromPoint(pt.x, pt.y)</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Пометить окно рамкой</div><div class="code_line">Private Sub MarkWindow(ByVal hwnd As Long)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim hRgn &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim r2 &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dc &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim rc &nbsp; &nbsp; &nbsp;As RECT</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Создаем регион для того, чтобы в него записать регион окна</div><div class="code_line">&nbsp;&nbsp; &nbsp;hRgn = CreateRectRgn(0, 0, 1, 1)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем контекст устройства окна</div><div class="code_line">&nbsp;&nbsp; &nbsp;dc = GetWindowDC(hwnd)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем регион окна</div><div class="code_line">&nbsp;&nbsp; &nbsp;If (GetWindowRgn(hwnd, hRgn) And (Not NULLREGION)) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Если регион - нулевой или ошибка</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем прямоугольник окна</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetWindowRect hwnd, rc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Удаляем предыдущий созданный регион</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;DeleteObject hRgn</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Преобразуме координаты окна в свою СО</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;OffsetRect rc, -rc.Left, -rc.Top</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Создаем ркгион по прямоугольнику окна</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;hRgn = CreateRectRgn(rc.Left, rc.Top, rc.Right, rc.Bottom)</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем режим наложения</div><div class="code_line">&nbsp;&nbsp; &nbsp;r2 = GetROP2(dc)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Задаем XOR наложение, теперь рисуя белым цветом мы получаем инверсию цветов.</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если еще раз нарисовать в том же месте, то фон восстановится на первоначальный</div><div class="code_line">&nbsp;&nbsp; &nbsp;SetROP2 dc, R2_XORPEN</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Рисуем рамку</div><div class="code_line">&nbsp;&nbsp; &nbsp;FrameRgn dc, hRgn, GetStockObject(WHITE_BRUSH), 3, 3</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Устанавливаем режим наложения, как был</div><div class="code_line">&nbsp;&nbsp; &nbsp;SetROP2 dc, r2</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Освободить контекст</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReleaseDC hwnd, dc</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Удалить регион</div><div class="code_line">&nbsp;&nbsp; &nbsp;DeleteObject hRgn</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Загрузка</div><div class="code_line">Private Sub Form_Load()</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Текущий путь - папка проекта</div><div class="code_line">&nbsp;&nbsp; &nbsp;ChDir App.Path: ChDrive App.Path</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Инициализация</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Not Initialize() Then End</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Загрузка иконки</div><div class="code_line">&nbsp;&nbsp; &nbsp;Set mIcon = LoadResPicture(101, vbResBitmap)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Высота иконки (3 состояния)</div><div class="code_line">&nbsp;&nbsp; &nbsp;iconHeight = ScaleY(mIcon.Height, vbHimetric, vbPixels) \ 3</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Рисуем иконку по умолчанию (Stopped)</div><div class="code_line">&nbsp;&nbsp; &nbsp;picIcon.PaintPicture mIcon, 0, 0, , iconHeight, , , , iconHeight</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Загружаем список сообщений</div><div class="code_line">&nbsp;&nbsp; &nbsp;SetWMList msgList()</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Статус</div><div class="code_line">&nbsp;&nbsp; &nbsp;Me.Caption = &quot;Stopped&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Обновление контролов</div><div class="code_line">&nbsp;&nbsp; &nbsp;sldWidth_Change</div><div class="code_line">&nbsp;&nbsp; &nbsp;sldHeight_Change</div><div class="code_line">&nbsp;&nbsp; &nbsp;tabMain_Click</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Завершение</div><div class="code_line">Private Sub Form_Unload(Cancel As Integer)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If curHwnd Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Если был сабклассинг - снимаем</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;StopSubclass curHwnd</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Деинициализация</div><div class="code_line">&nbsp;&nbsp; &nbsp;Clear</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Изменение размера вкладки</div><div class="code_line">Private Sub picContainer_Resize(Index As Integer)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Index = 2 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; В режиме отображения списка, растягиваем его на всю вкладку</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lvwMsg.Move 0, 0, picContainer(Index).ScaleWidth, picContainer(Index).ScaleHeight</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Клик по иконке окна</div><div class="code_line">Private Sub picIcon_Click()</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если был сабклассинг, то останавливаем</div><div class="code_line">&nbsp;&nbsp; &nbsp;If curHwnd Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;StopSubclass curHwnd</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Сброс текущего окна</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;curHwnd = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Обновляем иконку</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;picIcon.PaintPicture mIcon, 0, 0, , iconHeight, , , , iconHeight</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Обновляем статус</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Me.Caption = &quot;Stopped&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Нажатие кнопки мыши на иконке окна</div><div class="code_line">Private Sub picIcon_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если нет сабклассинга то</div><div class="code_line">&nbsp;&nbsp; &nbsp;If curHwnd = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Начать поиск окон</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;isDown = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Иконка указателя мыши - перекрестие</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;picIcon.MousePointer = vbCrosshair</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Обновляем иконку</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;picIcon.PaintPicture mIcon, 0, 0, , iconHeight, , iconHeight, , iconHeight</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Предыдущего маркированного окна пока еще не было</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;prevWnd = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Перемещение мыши при поиске окна</div><div class="code_line">Private Sub picIcon_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если идет поиск окон</div><div class="code_line">&nbsp;&nbsp; &nbsp;If isDown Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Dim handle As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем окно под курсором</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;handle = GetWindowFromCursor</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Если есть окно под курсором</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If handle Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Если оно соответствует предыдущему, то выходим</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If handle = prevWnd Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Exit Sub</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Иначе обновляем предыдущее окно (стираем рамку)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;MarkWindow prevWnd</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Рисуем рамку на новом окне</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;MarkWindow handle</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Предыдущее окно - текущее</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;prevWnd = handle</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Хендл окна в заголовок</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Me.Caption = Hex(handle)</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Отпускание мыши при поиске окон</div><div class="code_line">Private Sub picIcon_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim handle As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Поиск окон закончен</div><div class="code_line">&nbsp;&nbsp; &nbsp;isDown = False</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если есть активный сабкласинг, то выходим (отключится в событии Click)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If curHwnd Then Exit Sub</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Курсор мыши по умолчанию</div><div class="code_line">&nbsp;&nbsp; &nbsp;picIcon.MousePointer = vbDefault</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем окно под курсором</div><div class="code_line">&nbsp;&nbsp; &nbsp;handle = GetWindowFromCursor</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если есть такое окно и не было ошибок</div><div class="code_line">&nbsp;&nbsp; &nbsp;If handle Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Если хендл совпадает с предыдущим маркированным окном</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If handle = prevWnd Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Стираем рамку</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;MarkWindow handle</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Включаем сабклассинг</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If Not StartSubclass(handle) Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Me.Caption = &quot;Stopped&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;picIcon.PaintPicture mIcon, 0, 0, , iconHeight, , , , iconHeight: Exit Sub</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Текущее окно</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;curHwnd = handle</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;picIcon.PaintPicture mIcon, 0, 0, , iconHeight, , iconHeight * 2, , iconHeight</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Me.Caption = &quot;Running &quot; &amp; Hex(curHwnd)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;picIcon.PaintPicture mIcon, 0, 0, , iconHeight, , , , iconHeight</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Me.Caption = &quot;Stopped&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Sub</div><div class="code_line">Private Sub sldWidth_Change()</div><div class="code_line">&nbsp;&nbsp; &nbsp;lblWidth.Caption = &quot;Width: &quot; &amp; sldWidth.Value</div><div class="code_line">End Sub</div><div class="code_line">Private Sub sldWidth_Scroll()</div><div class="code_line">&nbsp;&nbsp; &nbsp;sldWidth_Change</div><div class="code_line">End Sub</div><div class="code_line">Private Sub sldHeight_Change()</div><div class="code_line">&nbsp;&nbsp; &nbsp;lblHeight.Caption = &quot;Height: &quot; &amp; sldHeight.Value</div><div class="code_line">End Sub</div><div class="code_line">Private Sub sldHeight_Scroll()</div><div class="code_line">&nbsp;&nbsp; &nbsp;sldHeight_Change</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">Private Sub tabMain_Click()</div><div class="code_line">&nbsp;&nbsp; &nbsp;Static prevTab As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;picContainer(prevTab).Visible = False</div><div class="code_line">&nbsp;&nbsp; &nbsp;prevTab = tabMain.SelectedItem.Index - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;picContainer(prevTab).Move tabMain.ClientLeft, tabMain.ClientTop, tabMain.ClientWidth, tabMain.ClientHeight</div><div class="code_line">&nbsp;&nbsp; &nbsp;picContainer(prevTab).Visible = True</div><div class="code_line">End Sub</div></ol></div></div></div></div><br>
Разберем подробно код. При загрузке формы вызываем функцию <strong class='tag-b'>Initialize</strong>, которая инициализирует данные необходимые для сабклассинга. Во-первых создаем мьютекс для синхронизации, файл-маппинг для обмена данными и проецируем его представление, регистрируем сообщение <strong class='tag-b'>WM_SENDMESSAGE</strong>, загружаем библиотеку с процедурой хука и сабклассим главное окно для приема сообщений. Далее при успехе загружаем иконку для состояний сабклассинга и загружаем список сообщений.<br>
Для старта сабклассинга нужно зажать кнопку мыши на контроле <strong class='tag-b'>picIcon</strong> и переместить ее на нужный контрол. При этом идет получение хендла окна под курсором и его маркировка рамкой. Для рамки берется либо регион окна, если он существует, в противном случае он создается на основе прямоугольника окна. Регион обрисовывается рамкой через <strong class='tag-b'>R2_XOR</strong> наложение (<strong class='tag-b'>vbXorPen</strong>), для снятия пометки просто еще раз рисуется рамка. При отпускании кнопки над окном, получаем его хендл и запускаем функцию <strong class='tag-b'>StartSubclass</strong>. В этой процедуре мы проверяем поток (в своем потоке я запретил перехватывать сообщения т.к. может произойти рекурсия и вылет), при необходимости устанавливаем сабклассинг. Далее открываем процесс-&quot;жертву&quot;, т.к. нам понадобится чтение и запись в его адресное пространство при обработке сообщений, передавая флаги <strong class='tag-b'>PROCESS_VM_OPERATION</strong>, <strong class='tag-b'>PROCESS_VM_WRITE</strong>, <strong class='tag-b'>PROCESS_VM_READ</strong>. Теперь для того чтобы начать сабклассинг нужно подготовить данные для процесса-&quot;жертвы&quot;, поэтому захватываем мьютекс и после этого ставим хук <strong class='tag-b'>WH_GETMESSAGE</strong> в потоке процесса-&quot;жертвы&quot;. После этого копируем данные в общую память, можем быть уверенными что поток-&quot;жертва&quot; не будет оттуда читать. Даже если процедура <strong class='tag-b'>GetMsgProc</strong> начнет свое выполнение она будет ждать в функции <strong class='tag-b'>WaitForSingleObject</strong> пока мы не освободим мьютекс. После копирования освобождаем мьютекс, теперь все готово.<br>
После получения очередного сообщения окном-&quot;жертвой&quot; мы передаем его нашему приложению из процедуры <strong class='tag-b'>WndProc</strong> находящейся в DLL, которая загружена в АП процесса-&quot;жертвы&quot;. В нашем приложении мы при получении <strong class='tag-b'>WM_SENDMESSAGE</strong> копируем данные из общей памяти и передаем их на обработку методу формы <strong class='tag-b'>WndProc</strong>.<br>
В этом методе, мы в зависимости от выбранной вкладки так или иначе обрабатываем сообщения. В первом случае мы ограничиваем минимальный рамер окна, посредством обработки сообщения <strong class='tag-b'>WM_GETMINMAXINFO</strong>. Нужно помнить что адреса передаваемые в оконную процедуру - это адреса в АП процесса-&quot;жертвы&quot;, для нашего процесса они недействительны. Из-за этого мы вместо <strong class='tag-b'>CopyMemory</strong> используем <strong class='tag-b'>ReadProcessMemory</strong> и <strong class='tag-b'>WriteProcessMemory</strong>. Во-втором обрабатываем <strong class='tag-b'>WM_LBUTTONDOWN</strong> и <strong class='tag-b'>WM_LBUTTONUP</strong> и в своем процессе помечаем вкладку. В-третьем просто заносим название сообщения и параметры в список.<br>
Для остановки сабклассинга нужно нажать на иконку, которая будет помечена как &quot;STOP&quot;. Тем самым вызывается функция <strong class='tag-b'>StopSubclass</strong>. В ней мы передаем окну-&quot;жертве&quot; сообщение <strong class='tag-b'>WM_SENDMESSAGE</strong>, тем самым говоря что мы заканчиваем сабклассинг. В DLL, в функции <strong class='tag-b'>WndProc</strong>, как я описал выше, мы производим деинициализацию. После деинициализации происходит возврат в наше приложение и снимается хук посредством вызова <strong class='tag-b'>UnhookWindowsHookEx</strong>. После система выгружает нашу DLL из памяти процесса-&quot;жертвы&quot;.<br>
<div class='tag-align-center'><img class='tag-img' src='http://s7.hostingkartinok.com/uploads/images/2014/11/1c3e4cfd142bf29b88ec216d94ce2cdd.png' alt='user posted image'></div><br>
Как мы увидели DLL, написанная на VB6, отлично работает в чужих программах и потоках. Данная DLL написана только для тестирования и демонстрации возможностей VB6. Я не ставил перед собой задачи написания законченной DLL для использования в проектах, поэтому DLL намеренно обладает ограничениями и имеет неправильную архитектуру (нельзя делать множественный сабклассинг и другие ограничения и баги), отсутствуют проверки. Для демонстрации возможностей этого достаточно. <a class='tag-url' href='http://www.youtube.com/v/_RyToQAEtKU' target='_blank'>Демонстрация.</a> <br>
<hr><br>
Как мы могли убедиться что многопоточность вполне работает в программах написанных на VB6, и DLL, написанные на VB6 работают в любых программах.<br>
Всем спасибо за внимание, удачи.<br>
<span class="b-attach" data-size="69560" data-hits="228" data-attach-id="43648" data-attach-post-id="3574987">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3574987&amp;attach_id=43648' title='Скачать файл' target='_blank'>SubclassNativeDLL.rar</a> (, : 228)
		</span>]]></description>
        <author>TheTrik</author>
        <category>Visual Basic: Общие вопросы</category>
      </item>
	
      </channel>
      </rss>
	