Results 1 to 30 of 30

Thread: initializing runtime in standard dll

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  2. #2
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    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).

  3. #3

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  4. #4

  5. #5

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  6. #6
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    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

  7. #7
    Member
    Join Date
    May 2019
    Posts
    50

    Re: initializing runtime in standard dll

    In the ide after i closed the main form i have this error:

    Name:  err1.JPG
Views: 1657
Size:  205.2 KB

    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

  8. #8

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  9. #9
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    Re: initializing runtime in standard dll

    Quote Originally Posted by BD48 View Post
    In the ide after i closed the main form i have this error:

    Name:  err1.JPG
Views: 1657
Size:  205.2 KB

    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.

  10. #10
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    Re: initializing runtime in standard dll

    Quote Originally Posted by jsvenu View Post
    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?

  11. #11

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  12. #12

  13. #13

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  14. #14

  15. #15
    Member
    Join Date
    May 2019
    Posts
    50

    Re: initializing runtime in standard dll

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

  16. #16

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  17. #17

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  18. #18
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    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

  19. #19

  20. #20

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    Re: initializing runtime in standard dll

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

  21. #21

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  22. #22

  23. #23

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    Re: initializing runtime in standard dll

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

  24. #24
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,671

    Re: initializing runtime in standard dll

    Quote Originally Posted by jsvenu View Post
    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.

  25. #25

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    Re: initializing runtime in standard dll

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

  26. #26

  27. #27

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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.

  28. #28

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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

  29. #29

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    Re: initializing runtime in standard dll

    Quote Originally Posted by jsvenu View Post
    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

  30. #30

    Thread Starter
    Hyperactive Member
    Join Date
    Apr 2015
    Posts
    356

    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
  •  



Click Here to Expand Forum to Full Width