Results 1 to 33 of 33

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

Hybrid View

  1. #1

    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.

  2. #2
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

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

    Quote Originally Posted by The trick View Post
    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
    Fantastic trick!



    BTW, don't know if you already came across this, but I thought you might be interested in seeing this guy's similar guide to constructing standard DLLs using VB6.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  3. #3

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

    Quote Originally Posted by The trick View Post
    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
    Isn't that fair to mention who actually discovered these undocumented keys?

  4. #4
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

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

    Quote Originally Posted by firehacker View Post
    Isn't that fair to mention who actually discovered these undocumented keys?
    Quote Originally Posted by The trick View Post
    ... there are a few tricks you can use to create a native DLL, from the substitution of the linker and ending undocumented sections in vbp-file.
    Quote Originally Posted by The trick View Post
    Special thanks I would like to express Vladislav Petrovsky (aka. Hacker) for the discovery of undocumented keys compiler / linker.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  5. #5

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

    I was using "Hybrid" topic display mode. In this mode links such as your:
    Quote Originally Posted by Bonnie West View Post
    Yet another way of setting the /LARGEADDRESSAWARE flag is by exploiting the undocumented [VBCompiler] option for .VBP files:
    brings me to this (http://www.vbforums.com/showthread.p...id#post4835355) post which is displayed alone (i.e. without preceding posts) in hybrid mode.

    So, since this post (post #3 when in linear topic display mode) that mentions [VBCompiler] doesn't contain a word about me, I mistakenly thought The trick decided not to mention me.

  6. #6
    PowerPoster
    Join Date
    Jan 2020
    Posts
    5,538

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

    vb STANDAND DLL,a api show form1,vb crash,maybe need use "COMDllLoader"?

    ' References:
    ' VBoostTypes6.olb (VBoost Object Types (6.0))
    ' ObjCreate.olb (VBoost: Object Creation and Security)
    ' This file is from the CD-ROM accompanying the book:
    ' Advanced Visual Basic 6: Power Techniques for Everyday Programs

    Code:
    Option Explicit
    
    Private m_fInit As Boolean
    Public IID_IClassFactory As IID
    Public IID_IUnknown As IID
    Private m_FDDllGetClassObject As FunctionDelegator
    Private m_pCallDllGetClassObject As ICallDllGetClassObject
    Private m_FDDllCanUnloadNow As FunctionDelegator
    Private m_pCallDllCanUnloadNow As ICallDllCanUnloadNow
    
    Private Sub Init()
        IID_IClassFactory = IIDFromString(strIID_IClassFactory)
        IID_IUnknown = IIDFromString(strIID_IUnknown)
        Set m_pCallDllGetClassObject = InitDelegator(m_FDDllGetClassObject)
        Set m_pCallDllCanUnloadNow = InitDelegator(m_FDDllCanUnloadNow)
        m_fInit = True
    End Sub
    
    Public Function GetDllClassObject(ByVal DllPath As String, CLSID As CLSID, hModDll As hInstance) As IClassFactory
        If Not m_fInit Then Init
        If hModDll = 0 Then
            hModDll = LoadLibraryEx(DllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)
            If hModDll = 0 Then
                Err.Raise &H80070000 + Err.LastDllError
            End If
        End If
        m_FDDllGetClassObject.pfn = GetProcAddress(hModDll, "DllGetClassObject")
        If m_FDDllGetClassObject.pfn = 0 Then
            Err.Raise &H80070000 + Err.LastDllError
        End If
        Set GetDllClassObject = m_pCallDllGetClassObject.Call(CLSID, IID_IClassFactory)
    End Function
    
    Public Sub TestUnloadDll(hModDll As hInstance)
        If hModDll Then
            If Not m_fInit Then Init
            m_FDDllCanUnloadNow.pfn = GetProcAddress(hModDll, "DllCanUnloadNow")
            If m_FDDllCanUnloadNow.pfn = 0 Then
                Err.Raise &H80070000 + Err.LastDllError
            End If
            If m_pCallDllCanUnloadNow.Call = 0 Then
                FreeLibrary hModDll
                hModDll = 0
            End If
        End If
    End Sub
    Last edited by xiaoyao; Jan 30th, 2020 at 11:41 PM.

  7. #7
    PowerPoster
    Join Date
    Jan 2020
    Posts
    5,538

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

    Quote Originally Posted by The trick View Post
    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
    [VBCompiler]
    LinkSwitches=/DLL /ENTRYllMain /EXPORT:Sum /EXPORT:ShowForm

    Code:
    Public Sub ShowForm()
    IntDll  'InitRuntime
    Msg "ShowForm"
    Dim f As Form1
    Set f = New Form1
    f.Show 1
    Set f = Nothing
    vbCoUninitialize
    End Sub
    when i call "ShowForm" in vc++ or (visual freebasic)
    it's successful,but when exe unload ,it's error happend(crash),how to fix vb standad.
    if we USE " DLL injection" to other exe(application),for best we can DLL_PROCESS_ATTACH AND unload dll more times.
    but it's can't unload dll.
    i want to fireevents "DLL_PROCESS_ATTACH " when load dll
    load dll
    unload dll
    load dll
    unload dll
    ****
    I want to load and unload the DLL several times, the operation will not crash
    maybe we need call api "DllCanUnloadNow","DllUnregisterServer"?
    chinese:我想多次加载卸载DLL,随便操作都不会崩溃就好了
    Last edited by xiaoyao; Jan 30th, 2020 at 11:06 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