|
-
Feb 12th, 2015, 03:15 PM
#1
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.
-
Feb 12th, 2015, 06:07 PM
#2
Re: [VB6] - Multithreading in VB6 part 2 - the creation of Native DLL.
 Originally Posted by The trick
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)
-
Mar 17th, 2016, 08:38 AM
#3
New Member
Re: [VB6] - Multithreading in VB6 part 2 - the creation of Native DLL.
 Originally Posted by The trick
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?
-
Mar 17th, 2016, 09:05 AM
#4
Re: [VB6] - Multithreading in VB6 part 2 - the creation of Native DLL.
 Originally Posted by firehacker
Isn't that fair to mention who actually discovered these undocumented keys?
 Originally Posted by The trick
 Originally Posted by The trick
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)
-
Mar 17th, 2016, 11:17 AM
#5
New Member
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:
 Originally Posted by Bonnie West
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.
-
Jan 30th, 2020, 11:18 PM
#6
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.
-
Jan 30th, 2020, 11:01 PM
#7
Re: [VB6] - Multithreading in VB6 part 2 - the creation of Native DLL.
 Originally Posted by The trick
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 /ENTRY llMain /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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|