Results 1 to 33 of 33

Thread: [VB6] - Multithreading in VB6 part 2 - the creation of Native DLL.

Threaded View

  1. #3

    Thread Starter
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,797

    Re: [VB6] - Multithreading in VB6 part 2 - the creation of Native DLL.

    Get the address of "UserDllMain" is very simple, because we know the handle of the library (it is passed as the first parameter); call "GetProcAddress" and get the address "DllGetClassObject". Next, we obtain the values through "GetMem4". I want to note that all API functions must be declared in a type library for this I compiled "DllInitialize.tlb", after compiling it does not need. To call "VBDllGetClassObject" use as "IID - IUnknown", as "CLSID - IID_NULL". Also, for initialization "COM" function must be called "CoInitialize". If we now try to collect a DLL, it will work, but keep in mind that the first call "VBDllGetClassObject" all unit variables are initialized to default values. Therefore it is necessary to call derived variables stored in local variables, and then it is already possible to maintain a modular. You also need to consider the threading model of the project: to "Apartment", as a function of "DllMain" should not be appeals to modular variables. For both models, I created two modules:
    For single threaded:
    Code:
    ' modMainDLL.bas  - инициализация DLL (Single thread)
    ' © Кривоус Анатолий Анатольевич (The trick), 2014
    
    Option Explicit
    
    Private Type uuid
        data1       As Long
        data2       As Integer
        data3       As Integer
        data4(7)    As Byte
    End Type
    
    Public hInstance    As Long
    
    Private lpInst_     As Long
    Private lpUnk_      As Long
    Private lpVBHdr_    As Long
    
    ' Точка входа
    Public Function DllMain(ByVal hInstDll As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long
        Dim lpProc      As Long
        Dim lpInst      As Long
        Dim lpUnk       As Long
        Dim lpVBHdr     As Long
        
        ' При создании процесса инициализируем адреса нужных переменных
        If fdwReason = DLL_PROCESS_ATTACH Then
            ' Получаем нужные нам данные, VBHeader, и два указателя необходимых для инициализации
            lpProc = GetProcAddress(hInstDll, "DllGetClassObject")
            If lpProc = 0 Then Exit Function
            GetMem4 ByVal lpProc + 2, lpVBHdr
            GetMem4 ByVal lpProc + 7, lpUnk
            GetMem4 ByVal lpProc + 12, lpInst
            DllMain = InitRuntime(lpInst, lpUnk, lpVBHdr, hInstDll, fdwReason, lpvReserved)
            lpInst_ = lpInst: lpUnk_ = lpUnk: lpVBHdr_ = lpVBHdr: hInstance = hInstDll
        ElseIf fdwReason = DLL_THREAD_ATTACH Then
            DllMain = InitRuntime(lpInst_, lpUnk_, lpVBHdr_, hInstDll, fdwReason, lpvReserved)
        Else
            vbCoUninitialize
            DllMain = UserDllMain(lpInst_, lpUnk_, hInstDll, fdwReason, ByVal lpvReserved)
        End If
        
    End Function
    
    Private Function InitRuntime(ByVal lpInst As Long, ByVal lpUnk As Long, ByVal lpVBHdr As Long, ByVal hInstDll As Long, _
                                 ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long
        Dim iid     As uuid
        Dim clsid   As uuid
        
        InitRuntime = UserDllMain(lpInst, lpUnk, hInstDll, fdwReason, ByVal lpvReserved)
        If InitRuntime Then
            vbCoInitialize ByVal 0&
            iid.data4(0) = &HC0: iid.data4(7) = &H46                    ' IUnknown
            VBDllGetClassObject lpInst, lpUnk, lpVBHdr, clsid, iid, 0   ' Инициализация потока
        End If
    End Function
    For apartment threaded:
    Code:
    ' modMainDLL.bas  - инициализация DLL (Apartment threaded)
    ' © Кривоус Анатолий Анатольевич (The trick), 2014
    
    Option Explicit
    
    Private Type uuid
        data1       As Long
        data2       As Integer
        data3       As Integer
        data4(7)    As Byte
    End Type
    
    Public hInstance    As Long
    
    Private lpInst_     As Long
    Private lpUnk_      As Long
    Private lpVBHdr_    As Long
    
    ' Точка входа, здесь не должно быть обращения к внешним переменным, т.е. public, private, static
    Public Function DllMain(ByVal hInstDLL As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long
        Dim iid         As uuid
        Dim clsid       As uuid
        Dim lpInst     As Long
        Dim lpUnk      As Long
        Dim lpVBHdr    As Long
        Dim lpProc  As Long
        
        ' При создании процесса или потока
        If fdwReason = DLL_PROCESS_ATTACH Or fdwReason = DLL_THREAD_ATTACH Then
            ' Получаем нужные нам данные, VBHeader, и два указателя необходимых для инициализаци
            ' Каждый поток содержит свои данные (публичные, статичные переменные и т.д.)
            lpProc = GetProcAddress(hInstDLL, "DllGetClassObject")
            If lpProc = 0 Then Exit Function
            GetMem4 ByVal lpProc + 2, lpVBHdr
            GetMem4 ByVal lpProc + 7, lpUnk
            GetMem4 ByVal lpProc + 12, lpInst
            ' Инициализация COM
            vbCoInitialize ByVal 0&
            ' Эта функция вызывается из ActiveX DLL
            DllMain = UserDllMain(lpInst, lpUnk, hInstDLL, fdwReason, ByVal lpvReserved)
            If DllMain = 0 Then Exit Function
            iid.data4(0) = &HC0: iid.data4(7) = &H46                            ' IUnknown
            VBDllGetClassObject lpInst, lpUnk, lpVBHdr, clsid, iid, 0           ' Инициализация потока
            ' Тут глобальные и статичные переменные обнуляются, восстанавливаем их
            SetPublicVariable lpInst, lpUnk, lpVBHdr, hInstDLL
        Else
            vbCoUninitialize
            DllMain = DefMainDLL(hInstDLL, fdwReason, ByVal lpvReserved)
        End If
    
    End Function
    
    Private Sub SetPublicVariable(ByVal lpInst As Long, ByVal lpUnk As Long, ByVal lpVBHdr As Long, ByVal hInstDLL As Long)
        lpInst_ = lpInst: lpUnk_ = lpUnk: lpVBHdr_ = lpVBHdr: hInstance = hInstDLL
    End Sub
    Private Function DefMainDLL(ByVal hInstDLL As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long
        DefMainDLL = UserDllMain(lpInst_, lpUnk_, hInstDLL, fdwReason, ByVal lpvReserved)
    End Function
    So now we know how to initialize the runtime and can begin to compile a native DLL. In the project file add these lines for specifying additional compiler and linker keys:
    Code:
    [VBCompiler]
    LinkSwitches= /ENTRY:DllMain /EXPORT:Brightness /EXPORT:Contrast /EXPORT:Saturation /EXPORT:GaussianBlur /EXPORT:EdgeDetect /EXPORT:Sharpen /EXPORT:Emboss /EXPORT:Minimum /EXPORT:Maximum /EXPORT:FishEye
    And adjusts the threading model of the project in single threaded, also need to add a class to the project, otherwise the project will not compile. Optionally, you can also add functionality ActiveX DLL, then you can work with this DLL and how ActiveX, and as with the conventional native importing function.
    Last edited by The trick; Feb 12th, 2015 at 03:20 PM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width