-
May 10th, 2019, 03:31 AM
#1
Thread Starter
Hyperactive Member
initializing runtime in standard dll
Dear Trick,
I have gone thru your examples in code bank regarding multithreading.
When we want to call an exported function of an activex dll we can intialize the runtime
using the following code in DllMain() (code from modMainDLL.bas of GraphicsDLL project) and works perfectly.
Code:
If fdwReason = DLL_PROCESS_ATTACH Then
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
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
lpInst_ = lpInst: lpUnk_ = lpUnk: lpVBHdr_ = lpVBHdr: hInstance = hInstDll
But when I use the same code to initialize the runtime thru DllMain() for calling a exported function in a
standard dll just like the callbackdll in vbmultithreadingmodule callback example provided by you in "multithreading without dependencies" it fails.Please clarify what are the changes I have to do in DLLMain() for initializing the runtime properly in the standard dll.
regards,
JSVenu
-
May 10th, 2019, 04:15 AM
#2
Re: initializing runtime in standard dll
What's the threading model of the dll?
We should play by the COM rules.
In order to call an arbitrary exported function from the dll we should initialize the project context.
There are the several types of the internal structures which the runtime uses for working with different threads. The project context is the internal structure which contains all the infos about the project (all the global/static variables, all the declared apis etc.) For example, when we create an ActiveX VB6-class instance and then destroy it the runtime checks if there are the global variables and cleanup them, calls FreeLibrary for declared APIs, etc.
When we have an apartment threading dll each thread can have its own copy of all the project specific data. For non-apartment threading dll we should create all the objects in the main STA.
To initialize a project specific data we just should create an object within calling STA. That's all. If you want to use the exported functions from your dll just create an public object from this dll and then you can call any exported function without restriction within STA. When you finish work with the STA you just destroy the object and the runtime'll clean up all the project specific data.
The main thing is it isn't recommended to create the objects from DllMain because we can't control the live of the objects. For example if we create 10 objects (DLL_THREAD_ATTACH) and then the dll is being unloaded (DLL_PROCESS_DETACH) we can't delete 10 objects from the unloading thread (we should work with the VB6-object only from its STA).
-
May 10th, 2019, 06:03 AM
#3
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
Thankyou for the reply.But in a standard dll we cannot set the threading model of the dll thru project properties since it is of type standard exe.This can be set in activex dll only.
I am not able to display form of standard dll thru its exported function SetCallback1.
When I click on add callback button in which I call setcallback1 which I added in callback dll exports as follows:
Private Function SetCallback1()
Dim y As Form1 ' Form1 is existing in the dll
Set y = New Form1
y.Show vbModal
End Function
After entering interval and key I am calling the above setcallback1 function.But nothing is displayed.Please clarify.
I modified the callback example of vbmultithreading module provided by you.
Complete code link https://www.sendspace.com/file/0a8dku
Please clarify the modification I have to make for this to work perfectly.
regards,
JSvenu
-
May 10th, 2019, 06:21 AM
#4
Re: initializing runtime in standard dll
But in a standard dll we cannot set the threading model of the dll thru project properties since it is of type standard exe
Just create an ActiveX dll. There is no difference - you can export a function from any PE file.
-
May 11th, 2019, 02:03 AM
#5
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
I understand that we can export a function from activex dll and the graphics dll is working perfectly.
But you were able to initlaize runtime in new thread in standard dll and call callbackfunction of exe.
But here I am not able to initialize runtime in current thread of standard dll even by using the following code in the start
of exported function setcallback1 of standard dll.
CreateIExprSrvObj(0, 4, 0)
CoInitialize ByVal 0&
...
VBDllGetClassObject hModule, 0, pVBHeader, tClsId, tIID, 0
I think I am missing something.
Complete code link https://www.sendspace.com/file/0a8dku
Please clarify the modification I have to make for this to work perfectly.
regards,
JSvenu
-
May 12th, 2019, 08:53 AM
#6
Re: initializing runtime in standard dll
I made the example. (see InitProjectContextDll demo)
This example shows the ability to use the exported functions from the VB6-ActiveX-DLL. It creates the 5 threads which call the exported function (CreateForm). This function creates the modeless form and allows to set the callback function which is called when an user click on the button. The callback function is called in the form's thread and the code initializes the runtime for the executable as well as for the Dll.
The most initeresting the DLL project-context initializer class:
Code:
Option Explicit
Private Const CC_STDCALL As Long = 4
Private Declare Function LoadLibrary Lib "kernel32" _
Alias "LoadLibraryW" ( _
ByVal lpLibFileName As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32" ( _
ByVal hModule As Long, _
ByVal lpProcName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" ( _
ByVal hLibModule As Long) As Long
Private Declare Function GetMem4 Lib "msvbvm60" ( _
ByRef pSrc As Any, _
ByRef pDst As Any) As Long
Private Declare Function lstrcmpA Lib "kernel32" ( _
ByRef lpString1 As Any, _
ByRef lpString2 As Any) As Long
Private Declare Function memcpy Lib "kernel32" _
Alias "RtlMoveMemory" ( _
ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long) As Long
Private Declare Function DispCallFunc Lib "oleaut32.dll" ( _
ByVal pvInstance As IUnknown, _
ByVal oVft As Long, _
ByVal cc As Long, _
ByVal vtReturn As VbVarType, _
ByVal cActuals As Long, _
ByRef prgvt As Any, _
ByRef prgpvarg As Any, _
ByRef pvargResult As Variant) As Long
Private m_cFactory As IUnknown
Private m_cContext As Object
Private m_hLibrary As Long
' // Call exported function from DLL
Public Function CallFunc( _
ByRef sFuncName As String, _
ByVal eRetType As VbVarType, _
ParamArray vParams() As Variant) As Variant
Dim iTypes() As Integer
Dim lList() As Long
Dim vParam() As Variant
Dim lIndex As Long
Dim hr As Long
Dim hLib As Long
Dim pfn As Long
Dim pList As Long
Dim pTypes As Long
If m_hLibrary = 0 Then Err.Raise 5
pfn = GetProcAddress(m_hLibrary, sFuncName)
If pfn = 0 Then Err.Raise 5
If LBound(vParams) <= UBound(vParams) Then
ReDim lList(UBound(vParams))
ReDim iTypes(UBound(vParams))
ReDim vParam(UBound(vParams))
For lIndex = 0 To UBound(vParams)
vParam(lIndex) = vParams(lIndex)
lList(lIndex) = VarPtr(vParams(lIndex))
iTypes(lIndex) = VarType(vParams(lIndex))
Next
pList = VarPtr(lList(0))
pTypes = VarPtr(iTypes(0))
End If
hr = DispCallFunc(Nothing, pfn, CC_STDCALL, eRetType, UBound(vParams) - LBound(vParams) + 1, ByVal pTypes, ByVal pList, CallFunc)
If hr Then Err.Raise 5: Exit Function
End Function
' // Init project context for dll
' // DLL should has the dummy class called "CInitContext"
Public Function InitVbProjContext( _
ByRef sLibName As String) As Boolean
Dim pVBHeader As Long
Dim pCOMData As Long
Dim lOfstRegInfo As Long
Dim pRegInfo As Long
Dim pfn As Long
Dim hLib As Long
Dim pClassName As Long
Dim iTypes(2) As Integer
Dim vParams(2) As Variant
Dim lList(2) As Long
Dim bIID(1) As Currency
Dim cFactory As IUnknown
Dim cObject As IUnknown
Dim hr As Long
Dim vRet As Variant
Free
hLib = LoadLibrary(StrPtr(sLibName))
If hLib = 0 Then Exit Function
pfn = GetProcAddress(hLib, "DllGetClassObject")
If pfn = 0 Then GoTo CleanUp
' // Get VBHeader
GetMem4 ByVal pfn + 2, pVBHeader
' // Get COM data
GetMem4 ByVal pVBHeader + &H54, pCOMData
' // Get Reg info
GetMem4 ByVal pCOMData, lOfstRegInfo
pRegInfo = pCOMData + lOfstRegInfo
' // Search for CInitContext CLSID
Do
GetMem4 ByVal pRegInfo + 4, pClassName
pClassName = pCOMData + pClassName
' // Check the class name
If lstrcmpA(ByVal pClassName, ByVal "CInitContext") = 0 Then
' // Setup DllGetClassObject
iTypes(0) = vbLong
iTypes(1) = vbLong
iTypes(2) = vbLong
' // IClassFactory
bIID(0) = 0.0001@
bIID(1) = 504403158265495.5712@
vParams(0) = pRegInfo + &H14
vParams(1) = VarPtr(bIID(0))
vParams(2) = VarPtr(cFactory)
lList(0) = VarPtr(vParams(0))
lList(1) = VarPtr(vParams(1))
lList(2) = VarPtr(vParams(2))
hr = DispCallFunc(Nothing, pfn, CC_STDCALL, vbLong, 3, iTypes(0), lList(0), vRet)
If hr >= 0 And vRet >= 0 Then
' // Call IClassFactory::CreateInstance
' // IUnknown
bIID(0) = 0
vParams(0) = 0&
vParams(2) = VarPtr(cObject)
hr = DispCallFunc(cFactory, &HC, CC_STDCALL, vbLong, 3, iTypes(0), lList(0), vRet)
If hr >= 0 And vRet >= 0 Then
Set m_cFactory = cFactory
Set m_cContext = cObject
m_hLibrary = hLib
InitVbProjContext = True
Exit Do
End If
End If
End If
GetMem4 ByVal pRegInfo, lOfstRegInfo
pRegInfo = pCOMData + lOfstRegInfo
Loop While lOfstRegInfo > 0
CleanUp:
If Not InitVbProjContext Then
If hLib Then
FreeLibrary hLib
End If
End If
End Function
Private Sub Free()
Set m_cContext = Nothing
Set m_cFactory = Nothing
If m_hLibrary Then
FreeLibrary m_hLibrary
m_hLibrary = 0
End If
End Sub
Private Sub Class_Terminate()
Free
End Sub
Last edited by The trick; May 14th, 2019 at 05:27 AM.
-
May 12th, 2019, 12:24 PM
#7
Member
Re: initializing runtime in standard dll
In the ide after i closed the main form i have this error:
and when started the compiled exe:
DllUsage
---------------------------
Run-time error '98':
A property or method call cannot include a reference to a private object, either as an argument or as a return value
-
May 14th, 2019, 12:50 AM
#8
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
Thankyou for the awesome activex dll example.This also works well like graohics dll.
But my doubt was about initializing runtime for standard dll(similar to callbackdll in "multithreading without dependencies").
You were providing initcurrentthreadandcallfunction for initializing current thread.
For initializing current thread you were gathering some information from DllGetClassObject exported function for getting vbheader and giving input to vbdllgetclassobject .
But in a standard dll DllGetClassobject is not exported.
You have already showed in "multithreading in standard exe" how to get this information when dllgetclassobject is not present in export table.This was done thru getting module instance and then e_lfanew and then AddressOfEntryPoint and finally vbheader.This is passed to vbdllgetclassobject.
I tried the same to initialize runtime in standard dll since this is also of type standard exe.But nothing was happening.
My doubt is when we are able to initialize runtime in standard exe(as in "multithreading in standard exe") why we cannot initialize runtime in standard dll since it is also of type standard exe.
Am I missing something please clarify.
regards,
JSVenu
-
May 14th, 2019, 05:33 AM
#9
Re: initializing runtime in standard dll
Originally Posted by BD48
In the ide after i closed the main form i have this error:
and when started the compiled exe:
DllUsage
---------------------------
Run-time error '98':
A property or method call cannot include a reference to a private object, either as an argument or as a return value
Thank you for testing!
The bug in IDE was because the MT module has the error (it clears the code heap before the message window was destroyed). The bug in EXE was my mistake (i forgot to call EnablePrivateMarshaling) in the project.
I've updated the example and upload it as the demo of the VbTrickThreading usage.
-
May 14th, 2019, 05:37 AM
#10
Re: initializing runtime in standard dll
Originally Posted by jsvenu
Dear Trick,
Thankyou for the awesome activex dll example.This also works well like graohics dll.
But my doubt was about initializing runtime for standard dll(similar to callbackdll in "multithreading without dependencies").
You were providing initcurrentthreadandcallfunction for initializing current thread.
For initializing current thread you were gathering some information from DllGetClassObject exported function for getting vbheader and giving input to vbdllgetclassobject .
But in a standard dll DllGetClassobject is not exported.
You have already showed in "multithreading in standard exe" how to get this information when dllgetclassobject is not present in export table.This was done thru getting module instance and then e_lfanew and then AddressOfEntryPoint and finally vbheader.This is passed to vbdllgetclassobject.
I tried the same to initialize runtime in standard dll since this is also of type standard exe.But nothing was happening.
My doubt is when we are able to initialize runtime in standard exe(as in "multithreading in standard exe") why we cannot initialize runtime in standard dll since it is also of type standard exe.
Am I missing something please clarify.
regards,
JSVenu
I gave the worked example. Why don't you use it? This is more simple to use AX-dll instead Std-XE-dll. Why do you need the complexity?
-
May 14th, 2019, 05:55 AM
#11
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
I am sending a exe as well as standard dll.https://www.sendspace.com/file/ifhuq8
I am able to display form in exe in new thread of dll.(using initcurrentthreadandcallfunction)
But I am not able to display form of dll in exe in main thread as well as new thread even when I use
initcurrentthreadandcallfunction.
Please clarify .
regards,
JSVenu
-
May 14th, 2019, 06:28 AM
#12
Re: initializing runtime in standard dll
You don't initialize the project context therefore you can't use the arbitrary code and forms. Just see my example with AX-dll and use it with exported functions.
-
May 14th, 2019, 07:39 AM
#13
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
It is just a matter of understanding internals of standard dll in vb6 as I came to know about it from the callbackdll sample of vbmultithreading module.
We are using standard exe and activex exe in vb6 .Similary I wanted to study activex dll vs standard dll and their run time initialization
for use in any thread.So you mean we cannot initialize project context for standard dll exported functions for use of arbitrary code and forms.I was interested in standard dll since it was the one ie., win32 dll I used in vc 6.0 frequently.I was also interested in implicit linking of dll more instead of explicit linking ie., loadlibrary and getprocaddress.
regards,
JSVenu
-
May 14th, 2019, 08:34 AM
#14
Re: initializing runtime in standard dll
jsvenu, you can initialize the runtime for a STD-EXE-Dll as well but you need to ensure the proper uninitialization (DllCanUnloadNow/Tracking objects lifetime/etc). There is no difference between the AX-DLL and the STD-EXE-Dll just for the EXE you need to make the more manual work.
Regarding usage in C++ you can use both AX-DLL/STD-EXE-Dll there is no difference:
(screenshot of the small example of usage STD-EXE-Dll in pure C)
-
May 14th, 2019, 10:14 AM
#15
Member
Re: initializing runtime in standard dll
Originally Posted by The trick
Thank you for testing!
The bug in IDE was because the MT module has the error (it clears the code heap before the message window was destroyed). The bug in EXE was my mistake (i forgot to call EnablePrivateMarshaling) in the project.
I've updated the example and upload it as the demo of the VbTrickThreading usage.
The trick,it worked perfectly, Thank You
-
May 19th, 2019, 04:10 AM
#16
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
Sorry for the delay.
Thankyou for providing the c++ usage code of exported function CreateForm of Testdll.dll of InitProjectContextDll project.
I have tried to call CreateForm exported function of Testdll.dll of InitProjectContextDll project in c++ as follows:
#include <windows.h>
int main(int argc, char* argv[])
{
HINSTANCE hlib=LoadLibrary("TestDll.dll");//success
IUnknown *pForm;
IOleWindow *pwnd;
HRESULT hr;
MSG msg;
BOOL bret;
HWND hwnd;
IUnknown *(__stdcall CreateForm)()=(IUnknown*(__stdcall *)())GetProcAddress(hlib,"CreateForm");//success
if (!CreateForm)
return 1;
pForm=CreateForm();//fails giving access violation.
hr=pForm->QueryInterface((const struct _GUID &)pForm,(void **)&IID_IOleWindow);
hr=pwnd->GetWindow(&hwnd);
pwnd->Release();
SysFreeString(sMsg);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
But the line pForm=CreateForm(); in the above code gives access violation in the main thread of c++ console application.
I understand that the code fails because the runtime initialization of the exported function is in DllUsage.exe of InitProjectContextDll.
1. Can you please move the runtime initialization of calling exported function to testdll dll project completely instead of in DllUsage exe project so that I can run the above c++ client code successfully.
2. What are the changes required in Testdll.dll (activex dll) after this transfer of runtime initialization from DLLUsage exe for Testdll to work also as standard dll.
Please clarify?
regards,
JSVenu
-
May 25th, 2019, 05:46 AM
#17
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
I solved the problem of calling CreateForm exported function of activex dll from c++
by all the following three methods:
(a) initializing runtime in dllmain using vbdllgetclassobject.
or
(b) initializing runtime in new function using cocreateinstance of dummy class of dll and calling it in the export function itself.
or
(c)
initializing runtime using IClassFactory method as done in initprojContextdll project's InitVbProjContext() method of DllUsage project.
But for all the above methods the dll is required to have
1.a minimum empty dummy class with instancing property of multiuse or global multiuse.
This type of class exists in any activex dll and the dll also
2.exports dllgetclassobject method.
But when we use standard dll which is of type standard exe it does not export DllGetClassobject and do not have any class of instancing type multiuse or global multiuse.
Is there any way to achieve the above for the standard dll at runtime so that the exported function of standard dll can be called from c++ successfully using CreatePrivateClass method or dynamically creating multiuse instancing type class in standard dll.
regards,
JSVenu
-
May 25th, 2019, 11:46 AM
#18
Re: initializing runtime in standard dll
If you'd let others know, what your "end-goal" is (what you really want, finally) -
then you'd get more help I guess.
As it is, I can only guess that your end-goal is, to make "VB6-produced binaries easily consumable in C++".
In case "yes, that's it"
- why go through all that trouble with flat-stdcall-exports in VB6?
- when it's easy enough to instantiate a COM-Object from a normally compiled VB6-Ax-Dll in C++
Is it the "but those Ax-Dlls need prior registering to be consumable in C++" - thing?
That'd also be easy enough to solve (since one can load Objects from unregistered COM-Dlls on the C++-end just fine).
Olaf
-
May 25th, 2019, 03:20 PM
#19
Re: initializing runtime in standard dll
You can initialize the runtime in the DLLMain as well but that isn't good approach. Just make an exported function which initializes the runtime and just call it after LoadLibrary.
-
May 26th, 2019, 10:58 AM
#20
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Originally Posted by The trick
You can initialize the runtime in the DLLMain as well but that isn't good approach. Just make an exported function which initializes the runtime and just call it after LoadLibrary.
Dear Trick,
I have also done the runtime initialization without using dllmain in the exported function itself in the dll.
by using all the above methods .In the first method I had to use I had to use VirtualQuery api and allocationbase member
of memory_basic_information structure for getting dll module handle(hInnstdll) through which I got vbheader .But this method of getting vbheader returns incorrect structure since this is not equal to the lpVBHdr structure which we get when we use dllgetclassobject as follows"
lpProc = GetProcAddress(hInstDll, "DllGetClassObject")
If lpProc = 0 Then Exit Function
GetMem4 ByVal lpProc + 2, lpVBHdr
But my problem is I am not able to get the information we want for vbdllgetclassobject parameters through dllgetclassobject thru standard dll since it does not export dllgetclassobject.
Same is the case when I use second method in which I give multiuse class of actx dllfor cocreateinstance which is not available in my standard dll since the class is not multiuse type in standard dll as it is of type standard exe.
code for second method:
hin= GetModuleHandle("MSVBVM60.DLL")
hinsetsyserr= GetProcAddress(hin, "__vbaSetSystemError")
Call RtlMoveMemory(hinsetsyserr, ByVal hinsetsyserr+ 9, 4)
Call RtlMoveMemory(hinsetsyserr, ByVal hinsetsyserr, 4)
If TlsGetValue(hinsetsyserr) <> 0 Then
Call CoCreateInstance(CLSIDFromProgID(PROGID_DUMMY), Nothing, CLSCTX_INPROC_SERVER, VBGUIDFromString("{00000000-0000-0000-C000-000000000046}"), Nothing)
If there is some way of creating a multiuse instancing class in standard dll we can easily initialize runtime.
Please clarify.
regards,
JSvenu
-
Jun 10th, 2019, 04:57 AM
#21
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
I have already done this in vc++ 6.0 in which I call exported function of an .exe win32 application
in another win32 application by loading the first application exe as dll using LoadLibrary in the second application.
After a call to LoadLibrary(), we get a valid HINSTANCE handle. However, when loading an .EXE file with LoadLibrary() , two important things are NOT happening:
The CRT is not initialized, including any global variables and,
The Import Address Table is not correctly configured, which means that all calls to imported functions will crash.
Therefore we have to update IAT and initialize crt and after that we can call any exported function without crash.
All these are done in the following link
https://www.codeproject.com/Articles...ssion-Possible
Can the same be achieved in vb6.If so can you please provide a working vb6 example similar to this.
regards,
JSVenu
-
Jun 10th, 2019, 06:54 AM
#22
Re: initializing runtime in standard dll
Why don't you want to call LoadLibrary and then call DllGetClassObject? All will work without any troubles? Why do you need these difficulties?
-
Jun 10th, 2019, 08:21 AM
#23
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Originally Posted by The trick
Why don't you want to call LoadLibrary and then call DllGetClassObject? All will work without any troubles? Why do you need these difficulties?
Dear Trick,
But DllGetClassObject is not exported by standard dll and so after calling LoadLibrary we cannot call DllGetClassObject
and so we have to use different way for calling exported function of standard dll.
regards,
JSVenu
-
Jun 10th, 2019, 09:46 AM
#24
Re: initializing runtime in standard dll
Originally Posted by jsvenu
Dear Trick,
But DllGetClassObject is not exported by standard dll and so after calling LoadLibrary we cannot call DllGetClassObject
and so we have to use different way for calling exported function of standard dll.
regards,
JSVenu
I don't understand you. You load a library and call GetProcAddress("DllGetClassObject"). What's the problem? Okay, if you don't want to call DllGetClassObject just export other function which you intend to call which'll call DllGetClassObject.
-
Jun 10th, 2019, 12:04 PM
#25
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Originally Posted by The trick
I don't understand you. You load a library and call GetProcAddress("DllGetClassObject"). What's the problem? Okay, if you don't want to call DllGetClassObject just export other function which you intend to call which'll call DllGetClassObject.
Dear Trick,
What I mean is after loadlibrary when I call GetProcAddress(hlib,""DllGetClassObject") it will return null because DllGetClassObject does not exist in the export table which can be checked by dependency walker tool or dumpbin -EXPORTS command in the standard dll which I mean is a standard exe type project with output as .dll when we make project.exe and give project.dll instead of project.exe during saving.Here I am specifying standard dll which I mean is not activex dll and it is of type standard exe with output written as .dll file.So for initializing runtime we cannot call dllgetclassobject either directly or using getprocaddress since it does not exist in the export table of standard exe (standard dll).So for initializing the runtime I cannot use dllgetclassobject.So I was trying for other way to initialize runtime for this standard exe type dll with startup as sub main.The same thing we could achieve in vc++ win32 app using two exes with one exe exporting functions which can be imported in other exe using loadlibrary and then updating IAT and initializing c++ runtime (crt) and then calling any exported function without crash which I already sent in the article "loading exe as dll" in the link
https://www.codeproject.com/Articles...ssion-Possible
regards,
JSVenu
-
Jun 11th, 2019, 02:13 AM
#26
Re: initializing runtime in standard dll
Why do you want to export from the EXE rather than the DLL? Just change the project type to ActiveX Dll and all'll work.
-
Jun 28th, 2019, 07:40 AM
#27
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
I finally did the runtime initialization of standard or activex dll project context without depending on
DllGetClassObject function.So the code can be used irrespective of type of dll .I am including the code
for the modified CContextHolder class of the DllUsage standard exe project.This project can take TestDll
dll project in either activex or standard dll(standard exe) which exports functions in InitProjectContextDll
example provided by you.
Code:
Code :
'''''''''''Code modified by JSVenu for runtime initialization of activex/standard dll''''''''''''
Option Explicit
Private Const CC_STDCALL As Long = 4
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Private Type MEMORY_BASIC_INFORMATION
BaseAddress As Long
AllocationBase As Long
AllocationProtect As Long
RegionSize As Long
State As Long
Protect As Long
lType As Long
End Type
Private Declare Function LoadLibrary Lib "kernel32" _
Alias "LoadLibraryW" ( _
ByVal lpLibFileName As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32" ( _
ByVal hModule As Long, _
ByVal lpProcName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" ( _
ByVal hLibModule As Long) As Long
Private Declare Function GetMem4 Lib "msvbvm60" ( _
ByRef pSrc As Any, _
ByRef pDst As Any) As Long
Private Declare Function lstrcmpA Lib "kernel32" ( _
ByRef lpString1 As Any, _
ByRef lpString2 As Any) As Long
Private Declare Function memcpy Lib "kernel32" _
Alias "RtlMoveMemory" ( _
ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long) As Long
Private Declare Function DispCallFunc Lib "oleaut32.dll" ( _
ByVal pvInstance As IUnknown, _
ByVal oVft As Long, _
ByVal cc As Long, _
ByVal vtReturn As VbVarType, _
ByVal cActuals As Long, _
ByRef prgvt As Any, _
ByRef prgpvarg As Any, _
ByRef pvargResult As Variant) As Long
Private Declare Function VirtualQuery Lib "kernel32.dll" ( _
ByRef lpAddress As Any, _
ByRef lpBuffer As MEMORY_BASIC_INFORMATION, _
ByVal dwLength As Long _
) As Long
Private Declare Sub RtlMoveMemory Lib "kernel32.dll" ( _
ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long _
)
Private Declare Sub UserDllMain Lib "MSVBVM60.DLL" ( _
ByRef Unknown1 As Long, _
ByRef Unknown2 As Long, _
ByVal Unknown3_hInstance As Long, _
ByVal Unknown4_Always1 As Long, _
ByVal Unknown5_Always0 As Long _
)
Private Declare Function CreateIExprSrvObj Lib "MSVBVM60.DLL" ( _
ByVal Unknown1_Always0 As Long, _
ByVal Unknown2_Always4 As Long, _
ByVal Unknown3_Always0 As Long _
) As Long
Private Declare Function CoInitialize Lib "ole32.dll" (ByRef pvReserved As Any) As Long
Private Declare Function CoUninitialize Lib "ole32.dll" Alias "CoUnInitialize" () As Long
Private Declare Function VBDllGetClassObject Lib "MSVBVM60.DLL" ( _
ByRef Unknown1 As Long, _
ByRef Unknown2 As Long, _
ByVal Unknown3_VBHeader As Long, _
ByRef rclsid As Long, _
ByRef riid As Any, _
ByRef ppv As Long _
) As Long
Private Declare Function IIDFromString Lib "ole32.dll" ( _
ByVal lpsz As Long, _
ByRef pIID As GUID _
) As Long
Private m_cFactory As IUnknown
Private m_cContext As Object
Private m_hLibrary As Long
' // Call exported function from DLL
Public Function CallFunc( _
ByRef sFuncName As String, _
ByVal eRetType As VbVarType, _
ParamArray vParams() As Variant) As Variant
Dim iTypes() As Integer
Dim lList() As Long
Dim vParam() As Variant
Dim lIndex As Long
Dim hr As Long
Dim hLib As Long
Dim pfn As Long
Dim pList As Long
Dim pTypes As Long
If m_hLibrary = 0 Then Err.Raise 5
pfn = GetProcAddress(m_hLibrary, sFuncName)
If pfn = 0 Then Err.Raise 5
If LBound(vParams) <= UBound(vParams) Then
ReDim lList(UBound(vParams))
ReDim iTypes(UBound(vParams))
ReDim vParam(UBound(vParams))
For lIndex = 0 To UBound(vParams)
vParam(lIndex) = vParams(lIndex)
lList(lIndex) = VarPtr(vParams(lIndex))
iTypes(lIndex) = VarType(vParams(lIndex))
Next
pList = VarPtr(lList(0))
pTypes = VarPtr(iTypes(0))
End If
MsgBox "run export"
hr = DispCallFunc(Nothing, pfn, CC_STDCALL, eRetType, UBound(vParams) - LBound(vParams) + 1, ByVal pTypes, ByVal pList, CallFunc)
MsgBox "after run export"
If hr Then Err.Raise 5: Exit Function
End Function
Private Function SearchVBHeader(ByVal hLibIns As Long) As Long
Dim mbi As MEMORY_BASIC_INFORMATION, lpCodeSection As Long, bBuffer() As Byte, i As Long
VirtualQuery ByVal hLibIns, mbi, LenB(mbi)
lpCodeSection = mbi.BaseAddress + mbi.RegionSize
VirtualQuery ByVal lpCodeSection, mbi, LenB(mbi)
ReDim bBuffer(mbi.RegionSize - 1&)
RtlMoveMemory bBuffer(0), ByVal mbi.BaseAddress, mbi.RegionSize
SearchVBHeader = InStrB(bBuffer, StrConv("VB5!", vbFromUnicode))
If SearchVBHeader Then
SearchVBHeader = SearchVBHeader + mbi.BaseAddress - 1&
End If
End Function
' // Init project context for dll
' // DLL should has the dummy class called "CInitContext"
Public Function InitVbProjContext( _
ByRef sLibName As String) As Boolean
'''''''''Some variables added by JSVenu''''''''''''''''''''''''''
Dim pVBHeader As Long
Dim pVBHeaderdllvq As Long
Dim pCOMData As Long
Dim lOfstRegInfo As Long
Dim pRegInfo As Long
Dim pfn As Long
Dim hLib As Long
Dim pClassName As Long
Dim iTypes(2) As Integer
Dim vParams(2) As Variant
Dim lList(2) As Long
Dim bIID(1) As Currency
Dim cFactory As IUnknown
Dim cObject As IUnknown
Dim hr As Long
Dim vRet As Variant
Dim ptr As Long
Dim hLibInstance As Long
Dim hLibvqi As Long
Dim HResult As Long, IID_IClassFactory As GUID, U1 As Long, U2 As Long, dwStartAddress As Long
Dim qobj As Long
Free
hLib = LoadLibrary(StrPtr(sLibName))
If hLib = 0 Then Exit Function
'''''''''''''''''''''''''''''''''''''Code added by JSVenu'''''''''''''''''''''''''''''
pVBHeader = SearchVBHeader(hLib)
CreateIExprSrvObj 0&, 4&, 0&
CoInitialize ByVal 0&
HResult = IIDFromString(StrPtr("{00000001-0000-0000-C000-000000000046}"), IID_IClassFactory)
If HResult < 0& Then
Exit Function
End If
UserDllMain U1, U2, hLib, 1&, 0&
If pVBHeader Then
'VBDllGetClassObject hLib, U2, pVBHeader, 0&, IID_IClassFactory, 0&
VBDllGetClassObject U1, U2, pVBHeader, 0&, IID_IClassFactory, 0&
'VBDllGetClassObject(hinstdll, lvb, ByVal fakehead, aiid, riid, ofac)
m_hLibrary = hLib
InitVbProjContext = True
Exit Function
End If
'''''''''''''''''''''''''''''''End of Code by JSVenu'''''''''''''''''''''''''''''''''''
pfn = GetProcAddress(hLib, "DllGetClassObject")
If pfn = 0 Then GoTo CleanUp
' // Get VBHeader
GetMem4 ByVal pfn + 2, pVBHeader
MsgBox pVBHeader
' // Get COM data
GetMem4 ByVal pVBHeader + &H54, pCOMData
' // Get Reg info
GetMem4 ByVal pCOMData, lOfstRegInfo
pRegInfo = pCOMData + lOfstRegInfo
' // Search for CInitContext CLSID
Do
GetMem4 ByVal pRegInfo + 4, pClassName
pClassName = pCOMData + pClassName
' // Check the class name
If lstrcmpA(ByVal pClassName, ByVal "CInitContext") = 0 Then
' // Setup DllGetClassObject
iTypes(0) = vbLong
iTypes(1) = vbLong
iTypes(2) = vbLong
' // IClassFactory
bIID(0) = 0.0001@
bIID(1) = 504403158265495.5712@
vParams(0) = pRegInfo + &H14
vParams(1) = VarPtr(bIID(0))
vParams(2) = VarPtr(cFactory)
lList(0) = VarPtr(vParams(0))
lList(1) = VarPtr(vParams(1))
lList(2) = VarPtr(vParams(2))
hr = DispCallFunc(Nothing, pfn, CC_STDCALL, vbLong, 3, iTypes(0), lList(0), vRet)
If hr >= 0 And vRet >= 0 Then
' // Call IClassFactory::CreateInstance
' // IUnknown
bIID(0) = 0
vParams(0) = 0&
vParams(2) = VarPtr(cObject)
hr = DispCallFunc(cFactory, &HC, CC_STDCALL, vbLong, 3, iTypes(0), lList(0), vRet)
If hr >= 0 And vRet >= 0 Then
Set m_cFactory = cFactory
Set m_cContext = cObject
m_hLibrary = hLib
InitVbProjContext = True
Exit Do
End If
End If
End If
GetMem4 ByVal pRegInfo, lOfstRegInfo
pRegInfo = pCOMData + lOfstRegInfo
Loop While lOfstRegInfo > 0
CleanUp:
If Not InitVbProjContext Then
If hLib Then
FreeLibrary hLib
End If
End If
End Function
Private Sub Free()
Set m_cContext = Nothing
Set m_cFactory = Nothing
If m_hLibrary Then
FreeLibrary m_hLibrary
m_hLibrary = 0
End If
End Sub
Private Sub Class_Terminate()
Free
End Sub
'''''End of code'''''
regards,
JSVenu
Last edited by jsvenu; Feb 7th, 2020 at 09:10 AM.
-
Jul 26th, 2019, 11:28 AM
#28
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
Is there a way to initialize runtime and at the same time get the class object of the activex dll using vbdllgetclassobject so that we can call any methods of
the class and exported functions of activex dll.I can see that vbdllgetclassobject has last parameter as IClassfactory object.But how to get this object so that
we can call instance of the class of activex dll from this class factory.Can you clarify me with an example.Already yo have shown how to do this with dllgetclassobject
in InitProjectContextDll example.In all the examples you provided for multithreading the last parameter of vbdllgetclassobject was not used.
Therefore I request you to provide an example for getting the IClassfactory object using vbdllgetclassobject last parameter.
regards,
JSVenu
-
Jul 27th, 2019, 12:45 AM
#29
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Originally Posted by jsvenu
Dear Trick,
Is there a way to initialize runtime and at the same time get the class object of the activex dll using vbdllgetclassobject so that we can call any methods of
the class and exported functions of activex dll.I can see that vbdllgetclassobject has last parameter as IClassfactory object.But how to get this object so that
we can call instance of the class of activex dll from this class factory.Can you clarify me with an example.Already yo have shown how to do this with dllgetclassobject
in InitProjectContextDll example.In all the examples you provided for multithreading the last parameter of vbdllgetclassobject was not used.
Therefore I request you to provide an example for getting the IClassfactory object using vbdllgetclassobject last parameter.
regards,
JSVenu
Dear Trick,
I solved the problem as follows:
I changed vbdllgetclassobject api declaration last parameter type from long to Any as follows:
Private Declare Function VBDllGetClassObject Lib "MSVBVM60.DLL" (gloaders As Long, gvb As Long, ByVal gvbtab As Long, rclsid As Long, riid As GUID, ppv As Any) As Long
Dim ofac As Object
VBDllGetClassObject hLib, U2, pVBHeader, aiid, IID_IClassFactory, ofac
Set m_cContext = ofac
Now everything works fine.
regards,
JSVenu
Last edited by jsvenu; Jul 27th, 2019 at 05:36 AM.
Reason: for providing vbdllgetclassobject last parameter type modification
-
Jul 27th, 2019, 05:40 AM
#30
Thread Starter
Hyperactive Member
Re: initializing runtime in standard dll
Dear Trick,
After obtaining m_cContext as above Can you tell me how to obtain m_cFactory and how to access a method say abc as follows in CInitContext of TestDll from DllUsage application of InitProjectContextDll project.
Sub abc() 'defined in CInitContext class
MsgBox "abc"
End Sub
regards,
JSVenu
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
|