<?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=399614&amp;view=findpost&amp;p=3574985</guid>
        <pubDate>Wed, 18 Feb 2015 17:48:05 +0000</pubDate>
        <title>Многопоточность в VB6 часть 2</title>
        <link>https://forum.sources.ru/index.php?showtopic=399614&amp;view=findpost&amp;p=3574985</link>
        <description><![CDATA[TheTrik: Сегодня я расскажу о еще одном методе написания многопоточных программ на VB6, а именно создание потока в Native DLL. В принципе здесь нет ничего сложного, передаем в <strong class='tag-b'>CreateThread</strong> адрес экспортируемой функции и она будет исполнена в другом потоке. Все бы хорошо, но стандартными, документированными возможностями VB6 не позволяет создавать нативные DLL. Но не все так плохо, есть несколько приемов, с помощью которых можно создать нативную DLL, начиная от подмены линкера, <a class='tag-url' href='http://bbs.vbstreets.ru/viewtopic.php?t=34902' target='_blank'>FNDLL</a> и заканчивая <a class='tag-url' href='http://goo.gl/H4kMNk' target='_blank'>недокументированными секциями в vbp-файле</a>. Как раз последний способ мы и будем использовать для создания DLL. Для начала нужно решить, что нам вообще нужно от DLL, чтобы можно было применить многопоточность. В прошлый раз я делал загрузку файла, сейчас я решил уделить внимание вычислениям. Т.е. в новом потоке у нас будут производится вычисления, а основной поток будет обслуживать GUI. Для теста я разработал DLL для работы с графикой, а если быть точнее то в DLL будут функции, которые преобразуют растровое изображение - накладывают различные эффекты. <br>
Как-то давно, когда я начинал программировать, и изучал фильтры на основе свертки, то мне очень не нравилась &quot;тормознутость&quot; этих методов. Теперь есть возможность засунуть вычисления в другой поток без блокировки главного. Я создал 10 функций, которые будут экспортироваться:<ol class="tag-list" type="1"><li>Brightness - Яркость</li><li>Contrast - Контрастность</li><li>Saturation - Насыщенность</li><li>GaussianBlur - Размытие</li><li>EdgeDetect - Выделение контуров</li><li>Sharpen - Резкость</li><li>Emboss - Тиснение</li><li>Minimum - Минимум</li><li>Maximum - Максимум</li><li>FishEye - &quot;Рыбий глаз&quot;</li></ol><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; modEffects.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">Private Type ThreadData</div><div class="code_line">&nbsp;&nbsp; &nbsp;pix() &nbsp; &nbsp; &nbsp; As Byte &nbsp; &nbsp; &#39; Двухмерный массив пикселей рисунка (w-1,h-1)</div><div class="code_line">&nbsp;&nbsp; &nbsp;value &nbsp; &nbsp; &nbsp; As Single &nbsp; &#39; Значение эффекта</div><div class="code_line">&nbsp;&nbsp; &nbsp;percent &nbsp; &nbsp; As Single &nbsp; &#39; Процент выполнения 0..1</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Функция изменения яркости</div><div class="code_line">Public Function Brightness(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim col() &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim x &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim y &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmp &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;On Error GoTo ERRORLABEL</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#60; -1 Then value = -1</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#62; 1 Then value = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim col(255)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For x = 0 To 255</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;tmp = x + value * 255</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If tmp &#62; 255 Then tmp = 255 Else If tmp &#60; 0 Then tmp = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;col(x) = tmp</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;For y = 0 To UBound(dat.pix, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For x = 0 To UBound(dat.pix, 1)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x, y) = col(dat.pix(x, y))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dat.percent = y / UBound(dat.pix, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;dat.percent = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;Brightness = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">ERRORLABEL:</div><div class="code_line">&nbsp;</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 Contrast(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim col() &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim x &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim y &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmp &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;On Error GoTo ERRORLABEL</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#60; 0 Then value = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#62; 100 Then value = 100</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim col(255)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For x = 0 To 255</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;tmp = 128 + (value ^ 3) * (x - 128)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If tmp &#62; 255 Then tmp = 255 Else If tmp &#60; 0 Then tmp = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;col(x) = tmp</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;For y = 0 To UBound(dat.pix, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For x = 0 To UBound(dat.pix, 1)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x, y) = col(dat.pix(x, y))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dat.percent = y / UBound(dat.pix, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;dat.percent = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;Contrast = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">ERRORLABEL:</div><div class="code_line">&nbsp;</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 Saturation(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim x &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim y &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim w &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim h &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmp &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim r &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim g &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim b &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim br &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;On Error GoTo ERRORLABEL</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#62; 1 Then value = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#60; 0 Then value = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;w = UBound(dat.pix, 1) \ 4</div><div class="code_line">&nbsp;&nbsp; &nbsp;h = UBound(dat.pix, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For y = 0 To h</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For x = 0 To w</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b = dat.pix(x * 4, y)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;g = dat.pix(x * 4 + 1, y)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;r = dat.pix(x * 4 + 2, y)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;br = 0.3 * r + 0.59 * g + 0.11 * b</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;r = r * value + br * (1 - value)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;g = g * value + br * (1 - value)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;b = b * value + br * (1 - value)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x * 4, y) = b</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x * 4 + 1, y) = g</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x * 4 + 2, y) = r</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dat.percent = y / h</div><div class="code_line">&nbsp;&nbsp; &nbsp;Next</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;dat.percent = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;Saturation = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">ERRORLABEL:</div><div class="code_line">&nbsp;</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 GaussianBlur(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim kernel() &nbsp; &nbsp;As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim size &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim half &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim weight &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim gx &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmp() &nbsp; &nbsp; &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim x &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim y &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim w &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim h &nbsp; &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;Dim acc &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim wFrom &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim wTo &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim norm() &nbsp; &nbsp; &nbsp;As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lnorm &nbsp; &nbsp; &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim px &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; &nbsp; &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;On Error GoTo ERRORLABEL</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#60; 0 Then value = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#62; 255 Then value = 255</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;size = CLng(value) * 2</div><div class="code_line">&nbsp;&nbsp; &nbsp;half = -Int(-size / 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim kernel(size)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(half) = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim norm(half)</div><div class="code_line">&nbsp;&nbsp; &nbsp;lnorm = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;For weight = 1 To half</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;gx = 3 * weight / half</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;kernel(half - weight) = Exp(-gx * gx / 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;kernel(half + weight) = kernel(half - weight)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lnorm = lnorm + kernel(half + weight) * 2</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;For x = 0 To half</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;norm(x) = lnorm</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lnorm = lnorm - kernel(x)</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;w = UBound(dat.pix, 1) \ 4</div><div class="code_line">&nbsp;&nbsp; &nbsp;h = UBound(dat.pix, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim tmp(w * 4, h)</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For y = 0 To h</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For x = 0 To w - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If x &#60; half Then wFrom = x Else wFrom = half</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If x &#62; w - half Then wTo = w - x Else wTo = half</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For px = 0 To 3</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For index = -wFrom To wTo</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = acc + dat.pix((x + index) * 4 + px, y) * kernel(index + half)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = acc / norm(half * 2 - (wTo + wFrom))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If acc &#62; 255 Then acc = 255</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;tmp(x * 4 + px, y) = acc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dat.percent = y / h / 2</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;For x = 0 To w - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For y = 0 To h</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If y &#60; half Then wFrom = y Else wFrom = half</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If y &#62; h - half Then wTo = h - y Else wTo = half</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For px = 0 To 4</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For index = -wFrom To wTo</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = acc + tmp(x * 4 + px, y + index) * kernel(index + half)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = acc / norm(half * 2 - (wTo + wFrom))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If acc &#62; 255 Then acc = 255</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x * 4 + px, y) = acc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dat.percent = x / w / 2 + 0.5</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;dat.percent = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;GaussianBlur = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">ERRORLABEL:</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; // Минимум</div><div class="code_line">Public Function Minimum(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim x &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim y &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim w &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim h &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim px &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim hlf &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim fx &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim fy &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tx &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ty &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dx &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dy &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim acc &nbsp; &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmp() &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;On Error GoTo ERRORLABEL</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#60; 0 Then value = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#62; 255 Then value = 255</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;w = UBound(dat.pix, 1) \ 4</div><div class="code_line">&nbsp;&nbsp; &nbsp;h = UBound(dat.pix, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;hlf = CLng(dat.value)</div><div class="code_line">&nbsp;&nbsp; &nbsp;tmp = dat.pix</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For y = 0 To h</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If y &#60; hlf Then fy = y Else fy = hlf</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If y &#62; h - hlf Then ty = h - y Else ty = hlf</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For x = 0 To w</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If x &#60; hlf Then fx = x Else fx = hlf</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If x &#62; w - hlf Then tx = w - x Else tx = hlf</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For px = 0 To 3</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = 255</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For dx = -fx To tx: For dy = -fy To ty</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If tmp((x + dx) * 4 + px, y + dy) &#60; acc Then acc = tmp((x + dx) * 4 + px, y + dy)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next: Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x * 4 + px, y) = acc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dat.percent = y / h</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</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;dat.percent = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;Minimum = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">ERRORLABEL:</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; // Максимум</div><div class="code_line">Public Function Maximum(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim x &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim y &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim w &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim h &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim px &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim hlf &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim fx &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim fy &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tx &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ty &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dx &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dy &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim acc &nbsp; &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmp() &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;On Error GoTo ERRORLABEL</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#60; 0 Then value = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#62; 255 Then value = 255</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;w = UBound(dat.pix, 1) \ 4</div><div class="code_line">&nbsp;&nbsp; &nbsp;h = UBound(dat.pix, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;hlf = CLng(dat.value)</div><div class="code_line">&nbsp;&nbsp; &nbsp;tmp = dat.pix</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For y = 0 To h</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If y &#60; hlf Then fy = y Else fy = hlf</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If y &#62; h - hlf Then ty = h - y Else ty = hlf</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For x = 0 To w</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If x &#60; hlf Then fx = x Else fx = hlf</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If x &#62; w - hlf Then tx = w - x Else tx = hlf</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For px = 0 To 3</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For dx = -fx To tx: For dy = -fy To ty</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If tmp((x + dx) * 4 + px, y + dy) &#62; acc Then acc = tmp((x + dx) * 4 + px, y + dy)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next: Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x * 4 + px, y) = acc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dat.percent = y / h</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</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;dat.percent = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;Maximum = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">ERRORLABEL:</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; // Тиснение</div><div class="code_line">Public Function Emboss(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim kernel() &nbsp; &nbsp;As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; &nbsp; &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim kernel(2, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(0, 0) = -value ^ 2: &nbsp;kernel(1, 0) = -value: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kernel(2, 0) = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(0, 1) = -value: &nbsp; &nbsp; &nbsp;kernel(1, 1) = 9: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kernel(2, 1) = value</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(0, 2) = 0: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kernel(1, 2) = value: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kernel(2, 2) = value ^ 2</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Emboss = Convolution(dat, kernel)</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 EdgeDetect(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim kernel() As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; &nbsp; &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim kernel(2, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(0, 0) = 0: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kernel(1, 0) = -value: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kernel(2, 0) = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(0, 1) = -value: &nbsp; &nbsp; &nbsp;kernel(1, 1) = value * 4: &nbsp; &nbsp; &nbsp; kernel(2, 1) = -value</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(0, 2) = 0: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kernel(1, 2) = -value: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kernel(2, 2) = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;EdgeDetect = Convolution(dat, kernel)</div><div class="code_line">&nbsp;</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 Sharpen(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim kernel() &nbsp; &nbsp;As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; &nbsp; &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim kernel(2, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(0, 0) = 0: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kernel(1, 0) = -value: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kernel(2, 0) = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(0, 1) = -value: &nbsp; &nbsp; &nbsp;kernel(1, 1) = value * 4 + 9: &nbsp; kernel(2, 1) = -value</div><div class="code_line">&nbsp;&nbsp; &nbsp;kernel(0, 2) = 0: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; kernel(1, 2) = -value: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;kernel(2, 2) = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Sharpen = Convolution(dat, kernel)</div><div class="code_line">&nbsp;</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 FishEye(dat As ThreadData) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim x &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim y &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim cx &nbsp; &nbsp; &nbsp;As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim cy &nbsp; &nbsp; &nbsp;As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim nx &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ny &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim r &nbsp; &nbsp; &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmp() &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim w &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim h &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim value &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim px &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;On Error GoTo ERRORLABEL</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;w = UBound(dat.pix, 1) \ 4 + 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;h = UBound(dat.pix, 2) + 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;value = dat.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#62; 1 Then value = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;If value &#60; 0 Then value = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;tmp = dat.pix</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For y = 0 To h - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For x = 0 To w - 1</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cx = x / w - 0.5: cy = y / h - 0.5</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;r = Sqr(cx * cx + cy * cy)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;nx = (cx + 0.5 + value * cx * ((r - 1) / 0.5)) * (w - 1)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ny = (cy + 0.5 + value * cy * ((r - 1) / 0.5)) * (h - 1)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For px = 0 To 3</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x * 4 + px, y) = tmp(nx * 4 + px, ny)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dat.percent = y / h</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;dat.percent = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;FishEye = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">ERRORLABEL:</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 Convolution(dat As ThreadData, kernel() As Single) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim x &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim y &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim w &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim h &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dx &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dy &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim tmp() &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim valFx &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim valFy &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim valTx &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim valTy &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim acc &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim px &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim hlfSize As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;On Error GoTo ERRORLABEL</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;w = UBound(dat.pix, 1)</div><div class="code_line">&nbsp;&nbsp; &nbsp;h = UBound(dat.pix, 2)</div><div class="code_line">&nbsp;&nbsp; &nbsp;hlfSize = UBound(kernel) \ 2</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;tmp = dat.pix</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;For y = 0 To h</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If y &#60; hlfSize Then valFy = y Else valFy = hlfSize</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If y &#62; h - hlfSize Then valTy = h - y Else valTy = hlfSize</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;For x = 0 To w</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;px = x \ 4</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If px &#60; hlfSize Then valFx = px Else valFx = hlfSize</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If px &#62; w \ 4 - hlfSize Then valTx = w \ 4 - px Else valTx = hlfSize</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For dy = -valFy To valTy</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;For dx = -valFx To valTx</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = acc + tmp(x + dx * 4, y + dy) * kernel(dx + hlfSize, dy + hlfSize)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;acc = acc \ ((valFx + valTx + 1) * (valFy + valTy + 1))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;If acc &#62; 255 Then acc = 255 Else If acc &#60; 0 Then acc = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;dat.pix(x, y) = acc</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Next</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dat.percent = y / h</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;Convolution = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;dat.percent = 1</div><div class="code_line">ERRORLABEL:</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">End Function &#39;</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
Все функции имеют один и тот же прототип для того чтобы можно было вызывать из в отдельно потоке, принимают структуру <strong class='tag-b'>ThreadData</strong> в качестве аргумента. Опишу поля подробней: <ul class="tag-list"><li><strong class='tag-b'>pix()</strong> - двухмерный массив пикселов типа <strong class='tag-b'>Byte</strong>, первая размерность задает <strong class='tag-b'>RGBQUAD</strong> поля по горизонтали, вторая по вертикали. Т.е. <strong class='tag-b'>pix(0,0)</strong> содержит синюю компоненту 0x0 пиксела, pix(1,0) - зеленую комопненту 0x0 пиксела, <strong class='tag-b'>pix(2,0)</strong> - красную компоненту,<strong class='tag-b'> pix(4,0)</strong> - синюю компоненту 1x0 пиксела и т.д. Как видно на вход подается массив пикселов в формате 32 бит на пиксел. Отсюда следует что первая размерность будет в 4 раза больше чем ширина картинки, а вторая - соответствовать высоте.</li><li><strong class='tag-b'>value</strong> - величина эффекта. Например для <strong class='tag-b'>GaussianBlur</strong> этот параметр отвечает за силу размытия, а в &quot;Рыбьем глазе&quot; за величину искажения. Для каждого эффекта свои диапазоны изменения <strong class='tag-b'>value</strong>.</li><li><strong class='tag-b'>percent</strong> - это ответный параметр. В нем содержится значение, характеризующее процент выполнения функции и из него мы в основном потоке будем обновлять прогрессбар. Диапазон от 0 до 1.</li></ul>Также помимо основных экспортируемых функций, у нас содержится еще вспомогательная неэкспортируемая функция <strong class='tag-b'>Convolution</strong>, которая вычисляет свертку. На основании свертки в моей реализации работают эффекты тиснения, выделения краев и резкости.<br>
На этом описание модуля закончено, теперь перейдем непосредственно к созданию DLL.<br>
Итак, как я уже сказал мы будем создавать DLL с помощью недокументированных ключей компиляции. С этим понятно, теперь предстоит сделать выбор - какой тип проекта выбрать. Забегая вперед скажу что лучше выбрать <strong class='tag-b'>ActiveX Dll</strong>, т.к. из нее легко получить некоторую информацию, которая нам нужна будет в дальнейшем. Хотя можно использовать и <strong class='tag-b'>Standart EXE</strong>, разницы особой нет. Если почитать о ключах компиляции, то автор топика (Хакер) написал<div class='tag-quote'><span class='tag-quote-prefix'>Цитата</span> <span class='tag-quote__quote-info'>&quot;Хакер&quot;</span><div class='quote '>никакой «инициализации рантайма» нет</div></div>, поэтому мы сами будем инициализировать рантайм. Об ограничениях неинициализированного рантайма я немного писал в предыдущем посте. Сама инициализация не нужна, если к примеру использовать эту DLL в VB6, т.к. рантайм (а точнее поток) уже инициализирован. Так что для обычных функций, вызываемых в том же потоке из VB6 такая DLL будет выполнять свои задачи на 100%. Именно поэтому можно в сети встретить много дисскусий что нативные DLL, созданные в VB6 не работают в других языках. Все дело в инициализации.<br>
Как же нам инициализировать поток для полноценной работы нашей DLL? Во-первых, нам нужно определить свою точку входа <strong class='tag-b'>DllMain</strong>. Как это сделать? Для этого существует ключ <strong class='tag-b'>ENTRY</strong> линкера. Вписываем имя нашей функции и наша DLL стартует с нее. Прототип этой функции должен быть следующим:<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">Public Function DllMain(ByVal hInstDLL As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
В <strong class='tag-b'>hInstDLL</strong> - передается базовый адрес загрузки модуля (он же <strong class='tag-b'>hInstance</strong>, <strong class='tag-b'>hModule</strong>), в <strong class='tag-b'>fdwReason</strong> передается значение указывающее причину вызова этой функции. Существует 4 случая вызова этой функции, когда DLL загружается в адресное пространство процесса (<strong class='tag-b'>DLL_PROCESS_ATTACH</strong>), когда создается новый поток в процессе (<strong class='tag-b'>DLL_THREAD_ATTACH</strong>) и соответственно два парных противоположных случая при корректном завершении потока (<strong class='tag-b'>DLL_THREAD_DETACH</strong>) и выгрузке DLL из памяти (<strong class='tag-b'>DLL_PROCESS_DETACH</strong>), также корректном. <strong class='tag-b'>lpReserved</strong> - нам не важен. Теперь при загрузке DLL будет вызываться наша функция и мы сможем делать инициализацию. С этим понятно. Теперь представим ситуацию, что DLL загрузилась в АП процесса, а процесс создал поток и оба вызвали функцию Foo, что будет? Какое значение будет иметь переменная Temp после окончания потоков?<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; Код DLL</div><div class="code_line">Dim Temp As Long</div><div class="code_line">&nbsp;</div><div class="code_line">Public Sub foo()</div><div class="code_line">&nbsp;&nbsp; &nbsp;Temp = App.ThreadID</div><div class="code_line">End Sub</div></ol></div></div></div></div><br>
Все зависит от того, какой поток последним запишет значение в переменную <strong class='tag-b'>Temp</strong>, а это нельзя знать точно. Возникла проблема - переменные уровня модуля стали разделяемыми, они доступны всем потокам процесса для модификации, а это может породить много ошибок (состояние гонки, блокировки и т.п.). К счастью есть выход из этой ситуации  - использование локального хранилища потока (TLS) для хранения потокозависимых данных. Можно делать это вручную через специальные функции (<strong class='tag-b'>TlsAlloc</strong>, <strong class='tag-b'>TlsFree</strong>, <strong class='tag-b'>TlsSetValue</strong>, <strong class='tag-b'>TlsGetValue</strong>), либо поручить эту задачу компилятору, что более удобней. Для этого существует опция <strong class='tag-b'>Threading model</strong> в свойствах проекта. Если там стоит <strong class='tag-b'>Single Threaded</strong>, то все переменные будут общими, а если <strong class='tag-b'>Apartment Threaded</strong> - то каждый поток получит свою копию переменных. С этим понятно. В нашем модуле нет общих переменных поэтому мы выбираем <strong class='tag-b'>Single Threaded</strong>. <br>
Теперь по поводу инициализации рантайма. Методика инициализации рантайма для создания Native DLL, которая будет описана дальше, впервые была <a class='tag-url' href='http://bbs.vbstreets.ru/viewtopic.php?t=34902' target='_blank'>продемонстрирована и описана</a> в проекте FireNativeDLL. Учитывая то, что <strong class='tag-b'>ActiveX DLL </strong>работают в многопоточных программах (без труда можно работать с такой DLL например в <strong class='tag-b'>Delphi</strong> или <strong class='tag-b'>C++</strong>), то значит можно инициализировать поток пойдя методом создания объекта. После просмотра внутренностей <strong class='tag-b'>ActiveX DLL</strong>, было выявлено что точка входа вызывает <strong class='tag-b'>UserDllMain</strong> из рантайма, передавая первыми двумя параметрами два указателя:<br>
<img class='tag-img' src='http://s7.hostingkartinok.com/uploads/images/2014/11/35001f2ecf22ac36893cc1c6906fa4bf.png' alt='user posted image'><br>
Итак, чтобы начать инициализацию нужно вызвать из нашей точки входа <strong class='tag-b'>UserDllMain</strong> из VB6, но нужно достать 2 параметра. Пока мы этого делать не будем, т.к. одного вызова <strong class='tag-b'>UserDllMain</strong> недостаточно, иначе можно было бы не заморачиваться а оставить как есть, она вызывается по умолчанию. Инициализация потока выполняется при создании объекта из ActiveX DLL. Для того чтобы создать объект нужно вызвать функцию <strong class='tag-b'>DllGetClassObject</strong> из DLL. Давайте посмотрим как выглядит эта функция внутри, а заодно и другие экспортируемые функции:<br>
<img class='tag-img' src='http://s7.hostingkartinok.com/uploads/images/2014/11/5395cc0c01bab30a901c3f95837a8ad0.png' alt='user posted image'><br>
Функция <strong class='tag-b'>DllGetClassObject</strong> пересылает данные в функцию <strong class='tag-b'>VBDllGetClassObject</strong> из рантайма дополнительно передавая первыми тремя параметрами указатели. Видно что 2 указателя, передаваемые в <strong class='tag-b'>UserDllMain</strong> первыми двумя параметрами, эквивалентны первым двум указателям передаваемым в <strong class='tag-b'>VBDllGetClassObject</strong>, а третий параметр соответствует структуре <strong class='tag-b'>VBHeader</strong> которая описывает проект. В моей версии рантайма первым параметром (<strong class='tag-b'>lphInst</strong>) передается указатель в который <strong class='tag-b'>UserDllMain</strong> записывает <strong class='tag-b'>hInstance</strong> библиотеки, второй (<strong class='tag-b'>lpUnk</strong>) параметр не используется ни одной функцией. Возможно что в каких-нибудь других версиях рантайма эти параметры будут использоваться по-другому, поэтому стоит передать правильные значения.<br>
Теперь нужно получить адреса этих данных. Для этого, анализируя опкоды, получаем их к примеру из <strong class='tag-b'>DllGetClassObject</strong>:<ul class="tag-list"><li>Адрес <strong class='tag-b'>VBHeader</strong> будет равен адресу функции <strong class='tag-b'>DllGetClassObject</strong> + 2 (пропускаем опкод <strong class='tag-b'>POP EAX</strong>, и <strong class='tag-b'>PUSH</strong>)</li><li>Адрес <strong class='tag-b'>lpUnk</strong> будет равен адресу функции <strong class='tag-b'>DllGetClassObject</strong> + 7</li><li>Адрес <strong class='tag-b'>lphInstance</strong> будет равен адресу функции <strong class='tag-b'>DllGetClassObject</strong> + 12</li></ul>Получить адрес из <strong class='tag-b'>UserDllMain</strong> очень просто, т.к. нам известен хендл библиотеки (он передается первым параметром); вызываем <strong class='tag-b'>GetProcAddress</strong> и получаем адрес <strong class='tag-b'>DllGetClassObject</strong>. Далее получаем значения через <strong class='tag-b'>GetMem4</strong>. Хочу отметить что все API функции должны быть объявлены в библиотеке типов, для этого я скомпилировал <strong class='tag-b'>DllInitialize.tlb</strong>, после компиляции она не нужна. Для вызова <strong class='tag-b'>VBDllGetClassObject</strong> используем в качестве <strong class='tag-b'>IID</strong> - <strong class='tag-b'>IUnknown</strong>, в качестве <strong class='tag-b'>CLSID</strong> - <strong class='tag-b'>IID_NULL</strong>. Также для инициализации <strong class='tag-b'>COM</strong> должна быть вызвана функция <strong class='tag-b'>CoInitialize</strong>. Если теперь попробовать собрать DLL, то все будет работать, но нужно учитывать что при первом вызове <strong class='tag-b'>VBDllGetClassObject</strong> все модульные переменные инициализируются значениями по умолчанию. Поэтому нужно полученные переменные до вызова сохранить в локальных переменных, а после уже можно сохранять в модульные. Также нужно учитывать потоковую модель проекта: для <strong class='tag-b'>Apartment</strong>, в функции DllMain не должно быть обращений к модульным переменным. Для обеих моделей я создал 2 модуля:<br>
Для <strong class='tag-b'>single threaded</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; modMainDLL.bas &nbsp;- инициализация DLL (Single thread)</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">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">Public hInstance &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;</div><div class="code_line">Private lpInst_ &nbsp; &nbsp; As Long</div><div class="code_line">Private lpUnk_ &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">Private lpVBHdr_ &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; Точка входа</div><div class="code_line">Public Function DllMain(ByVal hInstDll As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpProc &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpInst &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpUnk &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpVBHdr &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; При создании процесса инициализируем адреса нужных переменных</div><div class="code_line">&nbsp;&nbsp; &nbsp;If fdwReason = DLL_PROCESS_ATTACH Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем нужные нам данные, VBHeader, и два указателя необходимых для инициализации</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lpProc = GetProcAddress(hInstDll, &quot;DllGetClassObject&quot;)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If lpProc = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal lpProc + 2, lpVBHdr</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal lpProc + 7, lpUnk</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal lpProc + 12, lpInst</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;DllMain = InitRuntime(lpInst, lpUnk, lpVBHdr, hInstDll, fdwReason, lpvReserved)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lpInst_ = lpInst: lpUnk_ = lpUnk: lpVBHdr_ = lpVBHdr: hInstance = hInstDll</div><div class="code_line">&nbsp;&nbsp; &nbsp;ElseIf fdwReason = DLL_THREAD_ATTACH Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;DllMain = InitRuntime(lpInst_, lpUnk_, lpVBHdr_, hInstDll, fdwReason, lpvReserved)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;vbCoUninitialize</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;DllMain = UserDllMain(lpInst_, lpUnk_, hInstDll, fdwReason, ByVal lpvReserved)</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</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 InitRuntime(ByVal lpInst As Long, ByVal lpUnk As Long, ByVal lpVBHdr As Long, ByVal hInstDll As Long, _</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim iid &nbsp; &nbsp; As uuid</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim clsid &nbsp; As uuid</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;InitRuntime = UserDllMain(lpInst, lpUnk, hInstDll, fdwReason, ByVal lpvReserved)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If InitRuntime Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;vbCoInitialize ByVal 0&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;iid.data4(0) = &amp;HC0: iid.data4(7) = &amp;H46 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; IUnknown</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;VBDllGetClassObject lpInst, lpUnk, lpVBHdr, clsid, iid, 0 &nbsp; &#39; Инициализация потока</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Для <strong class='tag-b'>apartment threaded</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; modMainDLL.bas &nbsp;- инициализация DLL (Apartment threaded)</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">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">Public hInstance &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;</div><div class="code_line">Private lpInst_ &nbsp; &nbsp; As Long</div><div class="code_line">Private lpUnk_ &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">Private lpVBHdr_ &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; Точка входа, здесь не должно быть обращения к внешним переменным, т.е. public, private, static</div><div class="code_line">Public Function DllMain(ByVal hInstDLL As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) 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 lpInst &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpUnk &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpVBHdr &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;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; При создании процесса или потока</div><div class="code_line">&nbsp;&nbsp; &nbsp;If fdwReason = DLL_PROCESS_ATTACH Or fdwReason = DLL_THREAD_ATTACH Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем нужные нам данные, VBHeader, и два указателя необходимых для инициализаци</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Каждый поток содержит свои данные (публичные, статичные переменные и т.д.)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;lpProc = GetProcAddress(hInstDLL, &quot;DllGetClassObject&quot;)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If lpProc = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal lpProc + 2, lpVBHdr</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal lpProc + 7, lpUnk</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;GetMem4 ByVal lpProc + 12, lpInst</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Инициализация COM</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;vbCoInitialize ByVal 0&amp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Эта функция вызывается из ActiveX DLL</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;DllMain = UserDllMain(lpInst, lpUnk, hInstDLL, fdwReason, ByVal lpvReserved)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If DllMain = 0 Then Exit Function</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;iid.data4(0) = &amp;HC0: iid.data4(7) = &amp;H46 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; IUnknown</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;VBDllGetClassObject lpInst, lpUnk, lpVBHdr, clsid, iid, 0 &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;SetPublicVariable lpInst, lpUnk, lpVBHdr, hInstDLL</div><div class="code_line">&nbsp;&nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;vbCoUninitialize</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;DllMain = DefMainDLL(hInstDLL, fdwReason, ByVal lpvReserved)</div><div class="code_line">&nbsp;&nbsp; &nbsp;End If</div><div class="code_line">&nbsp;</div><div class="code_line">End Function</div><div class="code_line">&nbsp;</div><div class="code_line">Private Sub SetPublicVariable(ByVal lpInst As Long, ByVal lpUnk As Long, ByVal lpVBHdr As Long, ByVal hInstDLL As Long)</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpInst_ = lpInst: lpUnk_ = lpUnk: lpVBHdr_ = lpVBHdr: hInstance = hInstDLL</div><div class="code_line">End Sub</div><div class="code_line">Private Function DefMainDLL(ByVal hInstDLL As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;DefMainDLL = UserDllMain(lpInst_, lpUnk_, hInstDLL, fdwReason, ByVal lpvReserved)</div><div class="code_line">End Function</div></ol></div></div></div></div><br>
Итак, теперь мы умеем инициализировать рантайм и можем приступить к компиляции нативной DLL. В файл проекта добавляем вот эти строки <a class='tag-url' href='http://goo.gl/H4kMNk' target='_blank'>позволяющие указать дополнительные ключи компилятора и линкера</a>:<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">[VBCompiler]</div><div class="code_line">LinkSwitches= /ENTRY:DllMain /EXPORT:Brightness /EXPORT:Contrast /EXPORT:Saturation /EXPORT:GaussianBlur /EXPORT:EdgeDetect /EXPORT:Sharpen /EXPORT:Emboss /EXPORT:Minimum /EXPORT:Maximum /EXPORT:FishEye</div></ol></div></div></div></div><br>
И настраиваем потоковую модель проекта в <strong class='tag-b'>single threaded</strong>, также нужно в проект добавить класс, иначе проект не скомпилируется. По желанию можно также добавить функциональность <strong class='tag-b'>ActiveX DLL</strong>, тогда можно с этой DLL работать и как с <strong class='tag-b'>ActiveX</strong>, и как с обычной нативной импортируя функции.<br>
Для тестирования DLL была написана мини-программа:<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; Демонстрация использования многопоточности в NativeDLL на примере графических эффектов</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; Структура, идентичная объявленной в DLL</div><div class="code_line">Private Type ThreadData</div><div class="code_line">&nbsp;&nbsp; &nbsp;pix() &nbsp; &nbsp; &nbsp; As Byte</div><div class="code_line">&nbsp;&nbsp; &nbsp;value &nbsp; &nbsp; &nbsp; As Single</div><div class="code_line">&nbsp;&nbsp; &nbsp;percent &nbsp; &nbsp; As Single</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">Private Type BITMAPINFOHEADER</div><div class="code_line">&nbsp;&nbsp; &nbsp;biSize &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;biWidth &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;biHeight &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;biPlanes &nbsp; &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;biBitCount &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;biCompression &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;biSizeImage &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;biXPelsPerMeter As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;biYPelsPerMeter As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;biClrUsed &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;biClrImportant &nbsp;As Long</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">Private Type BITMAPINFO</div><div class="code_line">&nbsp;&nbsp; &nbsp;bmiHeader &nbsp; &nbsp; &nbsp; As BITMAPINFOHEADER</div><div class="code_line">&nbsp;&nbsp; &nbsp;bmiColors &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">Private Type OPENFILENAME</div><div class="code_line">&nbsp;&nbsp; &nbsp;lStructSize &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;hwndOwner &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;hInstance &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpstrFilter &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpstrCustomFilter &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;nMaxCustFilter &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;nFilterIndex &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpstrFile &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;nMaxFile &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpstrFileTitle &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;nMaxFileTitle &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpstrInitialDir &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpstrTitle &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Flags &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;nFileOffset &nbsp; &nbsp; &nbsp; &nbsp; As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;nFileExtension &nbsp; &nbsp; &nbsp;As Integer</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpstrDefExt &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lCustData &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpfnHook &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpTemplateName &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">End Type</div><div class="code_line">&nbsp;</div><div class="code_line">Private Declare Function GetOpenFileName Lib &quot;comdlg32.dll&quot; Alias &quot;GetOpenFileNameW&quot; (pOpenfilename As OPENFILENAME) As Long</div><div class="code_line">Private Declare Function GetDIBits Lib &quot;gdi32&quot; (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long</div><div class="code_line">Private Declare Function SetDIBitsToDevice Lib &quot;gdi32&quot; (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage 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 CreateThread Lib &quot;kernel32&quot; (lpThreadAttributes As Any, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long</div><div class="code_line">Private Declare Function LoadLibrary Lib &quot;kernel32&quot; Alias &quot;LoadLibraryW&quot; (ByVal lpLibFileName As Long) As Long</div><div class="code_line">Private Declare Function GetProcAddress Lib &quot;kernel32&quot; (ByVal hModule As Long, ByVal lpProcName As String) As Long</div><div class="code_line">Private Declare Function FreeLibrary Lib &quot;kernel32&quot; (ByVal hLibModule As Long) 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 GetExitCodeThread Lib &quot;kernel32&quot; (ByVal hThread As Long, lpExitCode As Long) As Long</div><div class="code_line">&nbsp;</div><div class="code_line">Private Const STILL_ACTIVE &nbsp;As Long = &amp;H103&amp;</div><div class="code_line">Private Const INFINITE &nbsp; &nbsp; &nbsp;As Long = -1&amp;</div><div class="code_line">&nbsp;</div><div class="code_line">Dim hLib &nbsp; &nbsp;As Long &nbsp; &nbsp; &nbsp; &nbsp; &#39; hInstance библиотеки</div><div class="code_line">Dim td &nbsp; &nbsp; &nbsp;As ThreadData &nbsp; &#39; Данные потока</div><div class="code_line">Dim hThread As Long &nbsp; &nbsp; &nbsp; &nbsp; &#39; Описатель потока</div><div class="code_line">Dim pic &nbsp; &nbsp; As StdPicture &nbsp; &#39; Изображение</div><div class="code_line">Dim bi &nbsp; &nbsp; &nbsp;As BITMAPINFO &nbsp; &#39; Информация об изображении</div><div class="code_line">Dim quene &nbsp; As Boolean &nbsp; &nbsp; &nbsp;&#39; Флаг очереди</div><div class="code_line">&nbsp;</div><div class="code_line">&#39; // Нажатие на кнопку загрузки рисунка</div><div class="code_line">Private Sub cmdLoad_Click()</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Загружаем</div><div class="code_line">&nbsp;&nbsp; &nbsp;LoadImage</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; Загружаем DLL</div><div class="code_line">&nbsp;&nbsp; &nbsp;ChDir App.Path: ChDrive App.Path</div><div class="code_line">&nbsp;&nbsp; &nbsp;hLib = LoadLibrary(StrPtr(&quot;..\GraphicsDLL\GraphicsDLL.dll&quot;))</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hLib = 0 Then MsgBox &quot;Неудалось загрузить DLL&quot;: End</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Загружаем картинку по умолчанию</div><div class="code_line">&nbsp;&nbsp; &nbsp;LoadImage &quot;defpic.jpg&quot;</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;&#39; Если поток выполняется ждем завершения</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hThread Then WaitForSingleObject hThread, INFINITE</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Выгружаем библиотеку</div><div class="code_line">&nbsp;&nbsp; &nbsp;FreeLibrary hLib</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 RunEffect()</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;Select Case cboEffect.ListIndex</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 0: picImage.PaintPicture pic, 0, 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#39; Исходное изображение</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 1: RunProcedure &quot;Brightness&quot;, sldValue / 50 - 1 &nbsp; &nbsp;&#39; Яркость</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 2: RunProcedure &quot;Contrast&quot;, sldValue / 50 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Контрастность</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 3: RunProcedure &quot;Saturation&quot;, sldValue / 100 &nbsp; &nbsp; &nbsp; &#39; Насыщенность</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 4: RunProcedure &quot;GaussianBlur&quot;, sldValue / 2 &nbsp; &nbsp; &nbsp; &#39; Размытие</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 5: RunProcedure &quot;EdgeDetect&quot;, sldValue / 2 + 1 &nbsp; &nbsp; &#39; Выделение контуров</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 6: RunProcedure &quot;Sharpen&quot;, sldValue / 3 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Резкость</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 7: RunProcedure &quot;Emboss&quot;, sldValue / 10 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; Тиснение</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 8: RunProcedure &quot;Minimum&quot;, sldValue / 10 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#39; Минимум</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 9: RunProcedure &quot;Maximum&quot;, sldValue / 10 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#39; Максимум</div><div class="code_line">&nbsp;&nbsp; &nbsp;Case 10: RunProcedure &quot;FishEye&quot;, sldValue / 100 &nbsp; &nbsp; &nbsp; &nbsp; &#39; Рыбий глаз</div><div class="code_line">&nbsp;&nbsp; &nbsp;End Select</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; // Загрузить картинку</div><div class="code_line">Private Sub LoadImage(Optional ByVal fileName As String)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim ofn &nbsp; &nbsp; As OPENFILENAME</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim title &nbsp; As String</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim out &nbsp; &nbsp; As String</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim filter &nbsp;As String</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim i &nbsp; &nbsp; &nbsp; As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dx &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim dy &nbsp; &nbsp; &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если поток выполняется ждем завершения</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hThread Then WaitForSingleObject hThread, INFINITE</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если имя файла не задано, то показываем диалог открытия файла</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Len(fileName) = 0 Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ofn.nMaxFile = 260</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;out = String(260, vbNullChar)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;title = &quot;Open image&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;filter = &quot;Picture file&quot; &amp; vbNullChar &amp; &quot;*.bmp;*.jpg&quot; &amp; vbNullChar</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ofn.hwndOwner = Me.hWnd</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ofn.lpstrTitle = StrPtr(title)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ofn.lpstrFile = StrPtr(out)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ofn.lStructSize = Len(ofn)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;ofn.lpstrFilter = StrPtr(filter)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;If GetOpenFileName(ofn) = 0 Then Exit Sub</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; Получаем имя файла</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;i = InStr(1, out, vbNullChar, vbBinaryCompare)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;fileName = Left$(out, i - 1)</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;On Error Resume Next</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Загружаем картинку</div><div class="code_line">&nbsp;&nbsp; &nbsp;Set pic = LoadPicture(fileName)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If Err.Number Then MsgBox &quot;Ошибка загрузки изображения&quot;, vbCritical: Exit Sub</div><div class="code_line">&nbsp;&nbsp; &nbsp;On Error GoTo 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Установка постоянных атрибутов картинки</div><div class="code_line">&nbsp;&nbsp; &nbsp;bi.bmiHeader.biSize = Len(bi.bmiHeader)</div><div class="code_line">&nbsp;&nbsp; &nbsp;bi.bmiHeader.biBitCount = 32</div><div class="code_line">&nbsp;&nbsp; &nbsp;bi.bmiHeader.biHeight = ScaleY(pic.Height, vbHimetric, vbPixels)</div><div class="code_line">&nbsp;&nbsp; &nbsp;bi.bmiHeader.biWidth = ScaleX(pic.Width, vbHimetric, vbPixels)</div><div class="code_line">&nbsp;&nbsp; &nbsp;bi.bmiHeader.biPlanes = 1</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Массив пикселей</div><div class="code_line">&nbsp;&nbsp; &nbsp;ReDim td.pix(bi.bmiHeader.biWidth * 4 - 1, bi.bmiHeader.biHeight - 1)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Проверка размеров</div><div class="code_line">&nbsp;&nbsp; &nbsp;If bi.bmiHeader.biWidth &#62; picCanvas.ScaleWidth Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;hsbScroll.Max = bi.bmiHeader.biWidth - picCanvas.ScaleWidth</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;hsbScroll.Visible = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dx = -hsbScroll.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dx = (picCanvas.ScaleWidth - bi.bmiHeader.biWidth) / 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;hsbScroll.value = 0: hsbScroll.Visible = False</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;If bi.bmiHeader.biHeight &#62; picCanvas.ScaleHeight Then</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;vsbScroll.Max = bi.bmiHeader.biHeight - picCanvas.ScaleHeight</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;vsbScroll.Visible = True</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dy = -vsbScroll.value</div><div class="code_line">&nbsp;&nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;dy = (picCanvas.ScaleHeight - bi.bmiHeader.biHeight) / 2</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;vsbScroll.value = 0: vsbScroll.Visible = False</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;picImage.Move dx, dy, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Отображаем ее</div><div class="code_line">&nbsp;&nbsp; &nbsp;cboEffect.ListIndex = 0: RunEffect</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 RunProcedure(Name As String, ByVal value As Single)</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim lpProc As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если в очереди уже есть вызов выходим</div><div class="code_line">&nbsp;&nbsp; &nbsp;If quene Then Exit Sub</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если поток активен, то ставим в очередь текущий вызов и выходим</div><div class="code_line">&nbsp;&nbsp; &nbsp;If hThread Then quene = True: Exit Sub</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем адрес функции</div><div class="code_line">&nbsp;&nbsp; &nbsp;lpProc = GetProcAddress(hLib, Name)</div><div class="code_line">&nbsp;&nbsp; &nbsp;If lpProc = 0 Then MsgBox &quot;Невозможно найти функцию&quot;: Exit Sub</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Устанавливаем значение эффекта</div><div class="code_line">&nbsp;&nbsp; &nbsp;td.value = value</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем пиксели рисунка</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetDIBits picCanvas.hdc, pic.Handle, 0, bi.bmiHeader.biHeight, td.pix(0, 0), bi, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Создаем поток</div><div class="code_line">&nbsp;&nbsp; &nbsp;hThread = CreateThread(ByVal 0&amp;, 0, lpProc, td, 0, 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Включаем таймер прогрессбара</div><div class="code_line">&nbsp;&nbsp; &nbsp;tmrUpdate.Enabled = True</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 sldValue_Change()</div><div class="code_line">&nbsp;&nbsp; &nbsp;RunEffect</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 cboEffect_Click()</div><div class="code_line">&nbsp;&nbsp; &nbsp;RunEffect</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 tmrUpdate_Timer()</div><div class="code_line">&nbsp;&nbsp; &nbsp;Dim status &nbsp;As Long</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Устанавливаем процент</div><div class="code_line">&nbsp;&nbsp; &nbsp;prgProgress.value = td.percent</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Получаем код завершения потока</div><div class="code_line">&nbsp;&nbsp; &nbsp;GetExitCodeThread hThread, status</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если поток активен, выходим</div><div class="code_line">&nbsp;&nbsp; &nbsp;If status = STILL_ACTIVE Then Exit Sub</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Поток завершился, отключаем таймер</div><div class="code_line">&nbsp;&nbsp; &nbsp;tmrUpdate.Enabled = False</div><div class="code_line">&nbsp;&nbsp; &nbsp;If status 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;SetDIBitsToDevice picImage.hdc, 0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, 0, 0, 0, bi.bmiHeader.biHeight, td.pix(0, 0), bi, 0</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;picImage.Refresh</div><div class="code_line">&nbsp;&nbsp; &nbsp;Else</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&#39; При неудаче (функция эффекта возвратила 0)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;MsgBox &quot;Функция потерпела неудачу&quot;, vbExclamation</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;CloseHandle hThread</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Поток завершен</div><div class="code_line">&nbsp;&nbsp; &nbsp;hThread = 0</div><div class="code_line">&nbsp;&nbsp; &nbsp;&#39; Если в очереди был вызов, то вызываем</div><div class="code_line">&nbsp;&nbsp; &nbsp;If quene Then quene = False: RunEffect</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 vsbScroll_Change() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; &nbsp; |</div><div class="code_line">&nbsp;&nbsp; &nbsp;picImage.Top = -vsbScroll.value &nbsp; &nbsp; &#39; &nbsp; |</div><div class="code_line">End Sub &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#39; &nbsp; |</div><div class="code_line">Private Sub vsbScroll_Scroll() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; &nbsp; |</div><div class="code_line">&nbsp;&nbsp; &nbsp;vsbScroll_Change &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; &nbsp; |</div><div class="code_line">End Sub &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#39; &nbsp; |</div><div class="code_line">Private Sub hsbScroll_Change() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; &nbsp; |</div><div class="code_line">&nbsp;&nbsp; &nbsp;picImage.Left = -hsbScroll.value &nbsp; &nbsp;&#39; &nbsp; |</div><div class="code_line">End Sub &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#39; &nbsp; |</div><div class="code_line">Private Sub hsbScroll_Scroll() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; &nbsp; |</div><div class="code_line">&nbsp;&nbsp; &nbsp;hsbScroll_Change &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&#39; &nbsp; |</div><div class="code_line">End Sub &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &#39; &nbsp; |</div><div class="code_line">&#39; // ---------------------------------------+</div></ol></div></div></div></div><br>
Программа достаточно простая, все действия прокомментированы. Основные моменты я дополнительно поясню. При загрузке формы загружается наша DLL, и хендл библиотеки сохраняется в переменной hLib. Далее загружается изображение по умолчанию, расположенное в папке проекта. В процедуре загрузки изображения (<strong class='tag-b'>LoadImage</strong>), заполняются основные поля структуры <strong class='tag-b'>BITMAPINFO</strong> и выделяется массив под пиксели рисунка, для того чтобы потом можно было получить их через <strong class='tag-b'>GetDiBits</strong>. Процедура <strong class='tag-b'>RunEffect</strong> запускает функцию из DLL в отдельном потоке (<strong class='tag-b'>RunProcedure</strong>). Для исключения запуска нескольких потоков  в процедуре <strong class='tag-b'>RunProcedure</strong> стоит проверка, если поток запущен, то установить переменную флаг (<strong class='tag-b'>quene</strong>) и выйти не запуская ничего. Если поток не запущен, то получить пиксели через <strong class='tag-b'>GetDiBits</strong>, и подготовив данные для потока (<strong class='tag-b'>td</strong>), запустить функцию в отдельном потоке. Также при создании включается таймер обновления состояния. В процедуре таймера обновляется состояние прогрессбара исходя из значения переменной <strong class='tag-b'>td.percent</strong>, и если поток успешно закончил свое выполнение (функция вернула не 0) обновляем данные в пикчербоксе через <strong class='tag-b'>SetDIBitsToDevice</strong>. При окончании, если в переменной <strong class='tag-b'>quene</strong> было <strong class='tag-b'>True</strong>, то запускаем эффект, это позволит изменять значение величины эффекта или сам эффект пока идет обработка.<br>
<div class='tag-align-center'><img class='tag-img' src='http://s7.hostingkartinok.com/uploads/images/2014/11/b53b5af895fa7a5576a6270009106388.png' alt='user posted image'></div><br>
Как видно из примера многопоточность отлично работает в VB6. К тому же эту DLL можно использовать в любом ЯП. В следующей части я опишу пример внедрения DLL и переопределение оконной процедуры, что даст возможность отслеживать различные события в других приложениях, перехватывать API функции и многое другое.<br>
<hr><br>
Все вышеописанное является моим личным исследованием и поэтому могут быть любые &quot;подводные камни&quot;, о которых я не знаю. О любых багах можете сообщать мне, я постараюсь решить. Отдельную благодарность хотелось бы выразить <a class='tag-url' href='http://goo.gl/SAUqzS' target='_blank'>Владиславу Петровскому (aka. Хакер)</a>, за открытие недокументированных ключей компилятора/компоновщика.<br>
<span class="b-attach" data-size="95274" data-hits="203" data-attach-id="43647" data-attach-post-id="3574985">
			<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=3574985&amp;attach_id=43647' title='Скачать файл' target='_blank'>GraphicsNativeDLL.rar</a> (, : 203)
		</span>]]></description>
        <author>TheTrik</author>
        <category>Visual Basic: Общие вопросы</category>
      </item>
	
      </channel>
      </rss>
	