<?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=399617&amp;view=findpost&amp;p=3574991</guid>
        <pubDate>Wed, 18 Feb 2015 18:00:29 +0000</pubDate>
        <title>Многопоточность в VB6 часть 4</title>
        <link>https://forum.sources.ru/index.php?showtopic=399617&amp;view=findpost&amp;p=3574991</link>
        <description><![CDATA[TheTrik: Всем привет. Сейчас у меня мало времени, поэтому я уже не так часто уделяю внимание бейсику и реже появляюсь на форумах. Сегодня я опять буду говорить о многопоточности, на этот раз в <strong class='tag-b'>Standart EXE</strong>. Сразу скажу что все о чем я пишу является моим личным исследованием и может в чем-то не соответствовать действительности; также из-за моего недостатка времени я буду дополнять этот пост по мере дальнейшего прогресса в исследовании данного вопроса. Итак начнем.<br>
Как я говорил до этого для того чтобы многопоточность работала нужно инициализировать рантайм. Без инициализации мы можем работать очень ограниченно, в том смысле что COM не будет работать, т.е. грубо говоря вся мощь бейсика будет недоступна. Можно работать с API, объявленными в tlb, некоторыми функциями, также убирая проверку <strong class='tag-b'>__vbaSetSystemError</strong>, можно использовать <strong class='tag-b'>Declared</strong>-функции. Все предыдущие публикации показывали работу в отдельных DLL, и мы легко могли инициализировать рантайм используя <strong class='tag-b'>VBDllGetClassObject</strong> функцию для этого. Сегодня мы попытаемся инициализировать рантайм в обычном EXE, т.е. не используя внешние зависимости. Не для кого не секрет что любое приложение написанное в VB6 состоит из хидера проекта, в котором содержится очень много информации о проекте которую рантайм использует для работы: <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">Type VbHeader</div><div class="code_line">&nbsp;&nbsp; &nbsp;szVbMagic &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As String * 4</div><div class="code_line">&nbsp;&nbsp; &nbsp;wRuntimeBuild &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;szLangDll &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As String * 14</div><div class="code_line">&nbsp;&nbsp; &nbsp;szSecLangDll &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As String * 14</div><div class="code_line">&nbsp;&nbsp; &nbsp;wRuntimeRevision &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwLCID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwSecLCID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpSubMain &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpProjectInfo &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;fMdlIntCtls &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;fMdlIntCtls2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwThreadFlags &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwThreadCount &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;wFormCount &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;wExternalCount &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;dwThunkCount &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpGuiTable &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpExternalCompTable &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpComRegisterData &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;bszProjectDescription &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;bszProjectExeName &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;bszProjectHelpFile &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;bszProjectName &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
В этой структуре большое количество полей описывать все я не буду, отмечу только что эта структура ссылается на множество других структур. Некоторые из них нам понадобятся в дальнейшем, например поле <strong class='tag-b'>lpSubMain</strong>, в котором содержится адрес процедуры <strong class='tag-b'>Main</strong>, если она определена, иначе там 0.<br>
Подавляющее большинство EXE файлов начинаются со следующего кода:<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">PUSH xxxxxxxx</div><div class="code_line">CALL MSVBVM60.ThunRTMain</div></ol></div></div></div></div><br>
Как раз <strong class='tag-b'>xxxxxxxx</strong> указывает на структуру <strong class='tag-b'>VBHeader</strong>. Эта особенность позволит найти эту структуру внутри EXE для инициализации рантайма. В одной из предыдущих частей я описывал как достать из <strong class='tag-b'>ActiveX DLL</strong> эту структуру - для этого нужно было считать данные в одной из экспортируемых функций (к примеру <strong class='tag-b'>DllGetClassObject</strong>). Для получения из EXE - мы также воспользуемся тем-же методом. Для начала нужно найти точку входа (entry point), т.е. адрес с которого начинается выполнение EXE. Этот адрес можно получить из структуры <strong class='tag-b'>IMAGE_OPTIONAL_HEADER</strong> - поле <strong class='tag-b'>AddressOfEntryPoint</strong>. Сама структура <strong class='tag-b'>IMAGE_OPTIONAL_HEADER</strong> расположена в PE заголовке, а PE заголовок находится по смещению заданному в поле <strong class='tag-b'>e_lfanew</strong> структуры <strong class='tag-b'>IMAGE_DOS_HEADER</strong>, ну а структура <strong class='tag-b'>IMAGE_DOS_HEADER</strong> расположена по адресу <strong class='tag-b'>App.hInstance</strong> (или <strong class='tag-b'>GetModuleHandle</strong>). Указатель на <strong class='tag-b'>VbHeader</strong> будет лежать по смещению <strong class='tag-b'>AddressOfEntryPoint + 1</strong>, т.к. опкод команды <strong class='tag-b'>push</strong> в данном случае 0x68h. Итак, собирая все вместе, получим функцию для получения хидера:<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; // Get VBHeader structure</div><div class="code_line">Private Function GetVBHeader() As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ptr &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get e_lfanew</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 ByVal hModule + &amp;H3C, ptr</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get AddressOfEntryPoint</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 ByVal ptr + &amp;H28 + hModule, ptr</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get VBHeader</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 ByVal ptr + hModule + 1, GetVBHeader</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Теперь если передать эту структуру функции <strong class='tag-b'>VBDllGetClassObject</strong> в новом потоке, то, грубо говоря, эта функция запустит наш проект на выполнение согласно переданной структуре. Конечно смысла в этом мало - это тоже самое что начать выполнение приложения заново в новом потоке. Например если была задана функция <strong class='tag-b'>Main</strong>, то и выполнение начнется опять с нее, а если была форма, то с нее. Нужно как-то сделать так, чтобы проект выполнялся с другой, нужной нам, функции. Для этого можно изменить поле <strong class='tag-b'>lpSubMain</strong> структуры <strong class='tag-b'>vbHeader</strong>. Я тоже сначала сделал так, но это ничего не дало. Как выяснилось, внутри рантайма есть один глобальный объект, который хранит ссылки на проекты и связанные с ними объекты и если передать тот же самый хидер в <strong class='tag-b'>VBDllGetClassObject</strong>, то рантайм проверит, не загружался ли такой проект, и если загружался, то просто запустит новую копию без разбора структуры <strong class='tag-b'>vbHeader</strong>, на основании предыдущего разбора. Поэтому я решил поступить так - можно скопировать структуру <strong class='tag-b'>vbHeader</strong> в другое место и использовать ее. Сразу замечу, что в этой структуре последние 4 поля - это смещения относительно начала структуры, поэтому при копировании струкутуры их нужно будет скорректировать. Если теперь попробовать передать эту структуру в <strong class='tag-b'>VBDllGetClassObject</strong>, то все будет отлично если в качестве стартапа установлена <strong class='tag-b'>Sub Main</strong>, если же форма, то будет запущена и форма и после нее <strong class='tag-b'>Main</strong>. Для исключения такого поведения нужно поправить кое-какие данные на которые ссылается хидер. Я пока точно не знаю что это за данные, т.к. не разбирался в этом, но &quot;поковырявшись&quot; внутри рантайма я нашел их место положение. Поле <strong class='tag-b'>lpGuiTable</strong> структуры <strong class='tag-b'>vbHeader</strong> ссылается на список структур <strong class='tag-b'>tGuiTable</strong>, которые описывают формы в проекте. Структуры идут последовательно, число структур соответствует полю <strong class='tag-b'>wFormCount</strong> структуры <strong class='tag-b'>vbHeader</strong>. В сети я так и не нашел нормальное описание структуры <strong class='tag-b'>tGuiTable</strong>, вот что есть:<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">Type tGuiTable</div><div class="code_line">&nbsp;&nbsp; &nbsp;lStructSize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;uuidObjectGUI &nbsp; &nbsp; &nbsp; &nbsp;As uuid</div><div class="code_line">&nbsp;&nbsp; &nbsp;Unknown1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Unknown2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Unknown3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Unknown4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lObjectID &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Unknown5 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;fOLEMisc &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;uuidObject &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As uuid</div><div class="code_line">&nbsp;&nbsp; &nbsp;Unknown6 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Unknown7 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;aFormPointer &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Unknown8 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">End Type</div></ol></div></div></div></div><br>
Как выяснилось внутри рантайма есть код, который проверяет поле <strong class='tag-b'>Unknown5</strong> каждой структуры:<br>
<div class='tag-align-center'><img class='tag-img' src='http://s7.hostingkartinok.com/uploads/images/2015/02/c4354e5dc51517f63f9ff10c42c3e3de.png' alt='user posted image'></div><br>
Я проставил комментарии; из них видно что <strong class='tag-b'>Unknown5</strong> содержит флаги и если установлен 5-й бит, то происходит запись ссылки на какой-то объект, заданный регистром EAX, в поле со смещением 0x30 объекта заданного регистром EDX. Что за объекты - я не знаю, возможно позже разберусь с этим, нам важен сам факт записи какого-то значения в поле со смещением 0x30. Теперь, если дальше начать исследовать код то можно наткнутся на такой фрагмент:<br>
<div class='tag-align-center'><img class='tag-img' src='http://s7.hostingkartinok.com/uploads/images/2015/02/4af108e7a1a4527ab9db0fdd45aaacd4.png' alt='user posted image'></div><br>
Скажу что объект на который указывает ESI, тот же самый объект что в предыдущей рассматриваемой процедуре (регистр EDX). Видно что тестируется значение этого поля на -1 и на 0, и если там любое из этих чисел то запускается процедура <strong class='tag-b'>Main</strong> (если она задана); иначе запускается первая форма.<br>
Итак, теперь чтобы гарантированно запускать только <strong class='tag-b'>Sub Main</strong>, мы изменяем флаг <strong class='tag-b'>lpGuiTable.Unknown5</strong>, сбрасывая пятый бит. Для установки новой <strong class='tag-b'>Sub Main</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; // Modify VBHeader to replace Sub Main</div><div class="code_line">Private Sub ModifyVBHeader(ByVal newAddress As Long)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ptr &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim old &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim flag &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim count &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim size &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ptr = lpVBHeader + &amp;H2C</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Are allowed to write in the page</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualProtect ByVal ptr, 4, PAGE_READWRITE, old</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Set a new address of Sub Main</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 newAddress, ByVal ptr</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualProtect ByVal ptr, 4, old, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Remove startup form</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 ByVal lpVBHeader + &amp;H4C, ptr</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get forms count</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 ByVal lpVBHeader + &amp;H44, count</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Do While count &#62; 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Get structure size</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal ptr, size</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Get flag (unknown5) from current form</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal ptr + &amp;H28, flag</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; When set, bit 5,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If flag And &amp;H10 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Unset bit 5</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;flag = flag And &amp;HFFFFFFEF</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Are allowed to write in the page</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;VirtualProtect ByVal ptr, 4, PAGE_READWRITE, old</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Write changet flag</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;GetMem4 flag, ByVal ptr + &amp;H28</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Restoring the memory attributes</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;VirtualProtect ByVal ptr, 4, old, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;count = count - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ptr = ptr + size</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Sub</div></ol></div></div></div></div><br>
Теперь, если попробовать запустить эту процедуру перед передачей хидера в <strong class='tag-b'>VBDllGetClassObject</strong>, то будет запускаться процедура, определенная нами. Впрочем многопоточность уже будет работать, но это не удобно, т.к. отсутствует механизм передачи параметра в поток как это реализовано в <strong class='tag-b'>CreateThread</strong>. Для того чтобы сделать полный аналог <strong class='tag-b'>CreateThread</strong> я решил создать аналогичную функцию, которая будет проводить все инициализации и после выполнять вызов переданной функции потока вместе с параметром. Для того чтобы была возможность передать параметр в <strong class='tag-b'>Sub Main</strong>, я использовал локальное хранилище потока (<strong class='tag-b'>TLS</strong>). Мы выделяем индекс для TLS. После выделения индекса мы сможем задавать значение этого индекса, специфичное для каждого потока. В общем идея такова, создаем новый поток, где стартовой функцией будет специальная функция <strong class='tag-b'>ThreadProc</strong>, в параметр которой передаем структуру из двух полей - адреса пользовательской функции и адреса параметра. В этой процедуре мы будем инициализировать рантайм для нового потока и сохранять в TLS переданный параметр. В качестве процедуры <strong class='tag-b'>Main</strong> создадим бинарный код, который будет доставать данные из TLS, формировать стек и прыгать на пользовательскую функцию. В итоге получился такой модуль:<br>
<em class='tag-i'>modMultiThreading.bas</em><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; modMultiThreading.bas - The module provides support for multi-threading.</div><div class="code_line">&#39; © Кривоус Анатолий Анатольевич (The trick), 2015</div><div class="code_line">&nbsp;</div><div class="code_line">Option Explicit</div><div class="code_line">&nbsp;</div><div class="code_line">Private Type uuid</div><div class="code_line">&nbsp;&nbsp; &nbsp;data1 &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;data2 &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;data3 &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;data4(7) &nbsp; &nbsp;As Byte</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">Private Type threadData</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpParameter As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpAddress &nbsp; As Long</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">Private tlsIndex &nbsp; &nbsp;As Long &nbsp;&#39; Index of the item in the TLS. There will be data specific to the thread.</div><div class="code_line">Private lpVBHeader &nbsp;As Long &nbsp;&#39; Pointer to VBHeader structure.</div><div class="code_line">Private hModule &nbsp; &nbsp; As Long &nbsp;&#39; Base address.</div><div class="code_line">Private lpAsm &nbsp; &nbsp; &nbsp; As Long &nbsp;&#39; Pointer to a binary code.</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Create a new thread</div><div class="code_line">Public Function vbCreateThread(ByVal lpThreadAttributes As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal dwStackSize As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal lpStartAddress As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal lpParameter As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal dwCreationFlags As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lpThreadId As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim InIDE &nbsp; As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Debug.Assert MakeTrue(InIDE)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If InIDE Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Dim ret As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ret = MsgBox(&quot;Multithreading not working in IDE.&quot; &amp; vbNewLine &amp; &quot;Run it in the same thread?&quot;, vbQuestion Or vbYesNo)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If ret = vbYes Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Run function in main thread</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ret = DispCallFunc(ByVal 0&amp;, lpStartAddress, CC_STDCALL, vbEmpty, 1, vbLong, VarPtr(CVar(lpParameter)), CVar(0))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If ret Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Err.Raise ret</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;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Alloc new index from thread local storage</div><div class="code_line">&nbsp;&nbsp; &nbsp;If tlsIndex = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;tlsIndex = TlsAlloc()</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If tlsIndex = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get module handle</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hModule = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;hModule = GetModuleHandle(ByVal 0&amp;)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Create assembler code</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpAsm = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lpAsm = CreateAsm()</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If lpAsm = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get pointer to VBHeader and modify</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpVBHeader = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lpVBHeader = GetVBHeader()</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If lpVBHeader = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ModifyVBHeader lpAsm</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpThreadData &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmpData &nbsp; &nbsp; &nbsp; &nbsp; As threadData</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Alloc thread-specific memory for threadData structure</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpThreadData = HeapAlloc(GetProcessHeap(), 0, Len(tmpData))</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpThreadData = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Set parameters</div><div class="code_line">&nbsp;&nbsp; &nbsp;tmpData.lpAddress = lpStartAddress</div><div class="code_line">&nbsp;&nbsp; &nbsp;tmpData.lpParameter = lpParameter</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Copy parameters to thread-specific memory</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem8 tmpData, ByVal lpThreadData</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Create thread</div><div class="code_line">&nbsp;&nbsp; &nbsp;vbCreateThread = CreateThread(ByVal lpThreadAttributes, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dwStackSize, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;AddressOf ThreadProc, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ByVal lpThreadData, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dwCreationFlags, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;lpThreadId)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Initialize runtime for new thread and run procedure</div><div class="code_line">Private Function ThreadProc(lpParameter As threadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim iid &nbsp; &nbsp; &nbsp; &nbsp; As uuid</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim clsid &nbsp; &nbsp; &nbsp; As uuid</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpNewHdr &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim hHeap &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Initialize COM</div><div class="code_line">&nbsp;&nbsp; &nbsp;vbCoInitialize ByVal 0&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; IID_IUnknown</div><div class="code_line">&nbsp;&nbsp; &nbsp;iid.data4(0) = &amp;HC0: iid.data4(7) = &amp;H46</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Store parameter to thread local storage</div><div class="code_line">&nbsp;&nbsp; &nbsp;TlsSetValue tlsIndex, lpParameter</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Create the copy of VBHeader</div><div class="code_line">&nbsp;&nbsp; &nbsp;hHeap = GetProcessHeap()</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpNewHdr = HeapAlloc(hHeap, 0, &amp;H6A)</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal lpNewHdr, ByVal lpVBHeader, &amp;H6A</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Adjust offsets</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim names() &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim diff &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim Index &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim names(3)</div><div class="code_line">&nbsp;&nbsp; &nbsp;diff = lpNewHdr - lpVBHeader</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory names(0), ByVal lpVBHeader + &amp;H58, &amp;H10</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For Index = 0 To 3</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;names(Index) = names(Index) - diff</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;CopyMemory ByVal lpNewHdr + &amp;H58, names(0), &amp;H10</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; This line calls the binary code that runs the asm function.</div><div class="code_line">&nbsp;&nbsp; &nbsp;VBDllGetClassObject VarPtr(hModule), 0, lpNewHdr, clsid, iid, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Free memeory</div><div class="code_line">&nbsp;&nbsp; &nbsp;HeapFree hHeap, 0, ByVal lpNewHdr</div><div class="code_line">&nbsp;&nbsp; &nbsp;HeapFree hHeap, 0, lpParameter</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Get VBHeader structure</div><div class="code_line">Private Function GetVBHeader() As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ptr &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; </div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get e_lfanew</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 ByVal hModule + &amp;H3C, ptr</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get AddressOfEntryPoint</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 ByVal ptr + &amp;H28 + hModule, ptr</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get VBHeader</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 ByVal ptr + hModule + 1, GetVBHeader</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Modify VBHeader to replace Sub Main</div><div class="code_line">Private Sub ModifyVBHeader(ByVal newAddress As Long)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ptr &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim old &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim flag &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim count &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim size &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ptr = lpVBHeader + &amp;H2C</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Are allowed to write in the page</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualProtect ByVal ptr, 4, PAGE_READWRITE, old</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Set a new address of Sub Main</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 newAddress, ByVal ptr</div><div class="code_line">&nbsp;&nbsp; &nbsp;VirtualProtect ByVal ptr, 4, old, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Remove startup form</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 ByVal lpVBHeader + &amp;H4C, ptr</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Get forms count</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem2 ByVal lpVBHeader + &amp;H44, count</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Do While count &#62; 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Get structure size</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal ptr, size</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Get flag (unknown5) from current form</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal ptr + &amp;H28, flag</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; When set, bit 5,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If flag And &amp;H10 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Unset bit 5</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;flag = flag And &amp;HFFFFFFEF</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Are allowed to write in the page</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;VirtualProtect ByVal ptr, 4, PAGE_READWRITE, old</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Write changet flag</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;GetMem4 flag, ByVal ptr + &amp;H28</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Restoring the memory attributes</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;VirtualProtect ByVal ptr, 4, old, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;End If</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;count = count - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ptr = ptr + size</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Loop</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Sub</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Create binary code.</div><div class="code_line">Private Function CreateAsm() As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim hMod &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpProc &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ptr &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;hMod = GetModuleHandle(ByVal StrPtr(&quot;kernel32&quot;))</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpProc = GetProcAddress(hMod, &quot;TlsGetValue&quot;)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpProc = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ptr = VirtualAlloc(ByVal 0&amp;, &amp;HF, MEM_RESERVE Or MEM_COMMIT, PAGE_EXECUTE_READWRITE)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If ptr = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; push &nbsp;tlsIndex</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; call &nbsp;TLSGetValue</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; pop &nbsp; ecx</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; push &nbsp;DWORD [eax]</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; push &nbsp;ecx</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; jmp &nbsp; DWORD [eax + 4]</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 &amp;H68, ByVal ptr + &amp;H0: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;GetMem4 &amp;HE800, ByVal ptr + &amp;H4</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 &amp;HFF590000, ByVal ptr + &amp;H8: &nbsp; &nbsp;GetMem4 &amp;H60FF5130, ByVal ptr + &amp;HC</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 &amp;H4, ByVal ptr + &amp;H10: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;GetMem4 tlsIndex, ByVal ptr + 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetMem4 lpProc - ptr - 10, ByVal ptr + 6</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;CreateAsm = ptr</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">Private Function MakeTrue(value As Boolean) As Boolean</div><div class="code_line">&nbsp;&nbsp; &nbsp;MakeTrue = True: value = True</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Все API декларации я сделал в отдельной библиотеке типов - <strong class='tag-b'>EXEInitialize.tlb</strong>. Пока найден один недостаток - не работают формы с приватными контролами, если разберусь в чем причина - исправлю. Работает только в скомпилированном варианте.<br>
<hr><br>
В архиве содержится несколько тестов.<br>
1-й: создание формы в новом потоке, с возможностью блокировки ввода посредством длинного цикла.<br>
2-й: обработка событий от объекта, метод которого вызван в другом потоке. Сразу скажу так делать нельзя и неправильно, т.к. передавать между потоками ссылку без маршаллинга опасно и может привести к глюкам, к тому же обработка события выполняется в другом потоке. Этот пример я оставил в качестве <span class='tag-u'>демонстрации работы многопоточности</span>, а не для использования в повседневных задачах.<br>
3-й: демонстрация изменения значения общей переменной в одном потоке и считывание его из другого.<br>
<a class='tag-url' href='http://www.youtube.com/v/W83gi9z1mHA' target='_blank'>Видео.</a><br>
<br>
<a class='tag-url' href='https://yadi.sk/d/F0o3et53guX6Q' target='_blank'>Скачать метериалы.</a><br>
<br>
Всем удачи&#33;]]></description>
        <author>TheTrik</author>
        <category>Visual Basic: Общие вопросы</category>
      </item>
	
      </channel>
      </rss>
	