Option Explicit
 
'[rm_code]
'CodeId=64499
Private Declare Function CallWindowProc Lib "user32" _
Alias "CallWindowProcA" ( _
    ByVal adr As Long, _
    ByVal p1 As Long, _
    ByVal p2 As Long, _
    ByVal p3 As Long, _
    ByVal p4 As Long _
) As Long
 
Private Declare Function LoadLibrary Lib "kernel32" _
Alias "LoadLibraryA" ( _
    ByVal szLib As String _
) As Long
 
Private Declare Function GetProcAddress Lib "kernel32" ( _
    ByVal hModule As Long, _
    ByVal szFnc As String _
) As Long
 
Private Declare Function GetModuleHandle Lib "kernel32" _
Alias "GetModuleHandleA" ( _
    ByVal szModule As String _
) As Long
 
Private Declare Function LoadTypeLibEx Lib "oleaut32" ( _
    ByVal szFile As Long, _
    ByVal REGKIND As Long, _
    pptlib As Any _
) As Long
 
Private Declare Function StringFromGUID2 Lib "ole32" ( _
    tGuid As Any, _
    ByVal lpszString As String, _
    ByVal lMax As Long _
) As Long
 
Private Declare Sub CpyMem Lib "kernel32" _
Alias "RtlMoveMemory" ( _
    pDst As Any, _
    pSrc As Any, _
    ByVal dlen As Long _
)
 
Private Type IUnknown
    QueryInterface          As Long
    AddRef                  As Long
    Release                 As Long
End Type
 
Private Type IClassFactory
    IUnk                    As IUnknown
    CreateInstance          As Long
    Lock                    As Long
End Type
 
Private Type ITypeInfo
    IUnk                    As IUnknown
    GetTypeAttr             As Long
    GetTypeComp             As Long
    GetFuncDesc             As Long
    GetVarDesc              As Long
    GetNames                As Long
    GetRefTypeOfImplType    As Long
    GetImplTypeFlags        As Long
    GetIDsOfNames           As Long
    Invoke                  As Long
    GetDocumentation        As Long
    GetDllEntry             As Long
    GetRefTypeInfo          As Long
    AddressOfMember         As Long
    CreateInstance          As Long
    GetMops                 As Long
    GetContainingTypeLib    As Long
    ReleaseTypeAttr         As Long
    ReleaseFuncDesc         As Long
    ReleaseVarDesc          As Long
End Type
 
Private Type ITypeLib
    IUnk                    As IUnknown
    GetTypeInfoCount        As Long
    GetTypeInfo             As Long
    GetTypeInfoType         As Long
    GetTypeInfoOfGuid       As Long
    GetLibAttr              As Long
    GetTypeComp             As Long
    GetDocumentation        As Long
    IsName                  As Long
    FindName                As Long
    ReleaseTLibAttr         As Long
End Type
 
Private Type TYPEATTR
    guid(15)                As Byte
    lcid                    As Long
    dwReserved              As Long
    memidConstructor        As Long
    memidDestructor         As Long
    pstrSchema              As Long
    cbSizeInstance          As Long
    TYPEKIND                As Long
    cFuncs                  As Integer
    cVars                   As Integer
    cImplTypes              As Integer
    cbSizeVft               As Integer
    cbAlignment             As Integer
    wTypeFlags              As Integer
    wMajorVerNum            As Integer
    wMinorVerNum            As Integer
    tdescAlias              As Long
    idldescType             As Long
End Type
 
Private Enum TYPEKIND
    TKIND_ENUM
    TKIND_RECORD
    TKIND_MODULE
    TKIND_INTERFACE
    TKIND_DISPATCH
    TKIND_COCLASS
    TKIND_ALIAS
    TKIND_UNION
    TKIND_MAX
End Enum
 
Private Enum HRESULT
    S_OK = 0
End Enum
 
Private Type CoClass
    Name                As String
    guid()              As Byte
End Type
 
Private Type guid
    data1               As Long
    data2               As Integer
    data3               As Integer
    data4(7)            As Byte
End Type
 
Private Enum REGKIND
    REGKIND_DEFAULT
    REGKIND_REGISTER
    REGKIND_NONE
End Enum
 
Public Function CreateObjectFromFile( _
    ByVal strLibrary As String, _
    ByVal strClassName As String _
) As stdole.IUnknown
 
    Dim newobj              As stdole.IUnknown
    Dim udtCF               As IClassFactory
 
    Dim classid             As guid
    Dim IID_ClassFactory    As guid
    Dim IID_IUnknown        As guid
    Dim lib                 As String
 
    Dim obj                 As Long
    Dim vtbl                As Long
 
    Dim hModule             As Long
    Dim pFunc               As Long
    Dim udtCoCls()          As CoClass
 
    Dim i                   As Long
 
    With IID_ClassFactory
        .data1 = &H1
        .data4(0) = &HC0
        .data4(7) = &H46
    End With
 
    With IID_IUnknown
        .data4(0) = &HC0
        .data4(7) = &H46
    End With
 
    ' get all CoClasses from the type lib of
    ' the file, and find the GUID of the Prog ID
    If Not GetCoClasses(strLibrary, udtCoCls) Then
        Exit Function
    End If
 
    For i = 0 To UBound(udtCoCls)
        If StrComp(udtCoCls(i).Name, strClassName, vbTextCompare) = 0 Then
            CpyMem classid, udtCoCls(i).guid(0), Len(classid)
            Exit For
        End If
    Next
 
    If i = UBound(udtCoCls) + 1 Then
        Exit Function
    End If
 
    ' load the file, if it isn't yet
    hModule = GetModuleHandle(strLibrary)
    If hModule = 0 Then
        hModule = LoadLibrary(strLibrary)
        If hModule = 0 Then Exit Function
    End If
 
    pFunc = GetProcAddress(hModule, "DllGetClassObject")
    If pFunc = 0 Then Exit Function
 
    ' call DllGetClassObject to get a
    ' class factory for the class ID
    If 0 <> CallPointer(pFunc, _
                        VarPtr(classid), _
                        VarPtr(IID_ClassFactory), _
                        VarPtr(obj)) Then
 
        Exit Function
    End If
 
    ' IClassFactory VTable
    CpyMem vtbl, ByVal obj, 4
    CpyMem udtCF, ByVal vtbl, Len(udtCF)
 
    ' create an instance of the object
    If 0 <> CallPointer(udtCF.CreateInstance, _
                        obj, _
                        0, _
                        VarPtr(IID_IUnknown), _
                        VarPtr(newobj)) Then
 
        ' Set IClassFactory = Nothing
        CallPointer udtCF.IUnk.Release, obj
        Exit Function
    End If
 
    ' Set IClassFactory = Nothing
    CallPointer udtCF.IUnk.Release, obj
 
    Set CreateObjectFromFile = newobj
End Function
 
Private Function GetCoClasses( _
    ByVal strFile As String, _
    udtCoClasses() As CoClass _
) As Boolean
 
    Dim hRes            As HRESULT
 
    Dim udtITypeLib     As ITypeLib
    Dim udtITypeInfo    As ITypeInfo
    Dim udtTypeAttr     As TYPEATTR
 
    Dim oTypeLib        As Long
    Dim oTypeInfo       As Long
    Dim pVTbl           As Long
    Dim pAttr           As Long
 
    Dim lngTypeInfos    As Long
    Dim lngCoCls        As Long
    Dim strTypeName     As String
 
    Dim i               As Long
 
    ' load the type lib of the file
    hRes = LoadTypeLibEx(StrPtr(strFile), REGKIND_NONE, oTypeLib)
    If hRes <> S_OK Then Exit Function
 
    ' ITypeLib's VTable
    CpyMem pVTbl, ByVal oTypeLib, 4
    CpyMem udtITypeLib, ByVal pVTbl, Len(udtITypeLib)
 
    lngTypeInfos = CallPointer(udtITypeLib.GetTypeInfoCount, oTypeLib)
 
    For i = 0 To lngTypeInfos - 1
 
        hRes = CallPointer(udtITypeLib.GetTypeInfo, _
                           oTypeLib, i, _
                           VarPtr(oTypeInfo))
 
        If hRes <> S_OK Then GoTo NextItem
 
        ' ITypeInfo's VTable
        CpyMem pVTbl, ByVal oTypeInfo, 4
        CpyMem udtITypeInfo, ByVal pVTbl, Len(udtITypeInfo)
 
        ' TYPEATTR struct, which describes the type
        CallPointer udtITypeInfo.GetTypeAttr, oTypeInfo, VarPtr(pAttr)
        CpyMem udtTypeAttr, ByVal pAttr, Len(udtTypeAttr)
        CallPointer udtITypeInfo.ReleaseTypeAttr, oTypeInfo, pAttr
 
        ' name of the type
        CallPointer udtITypeLib.GetDocumentation, _
                    oTypeLib, i, _
                    VarPtr(strTypeName), _
                    0, 0, 0
 
        If udtTypeAttr.TYPEKIND = TKIND_COCLASS Then
            ReDim Preserve udtCoClasses(lngCoCls) As CoClass
 
            With udtCoClasses(lngCoCls)
                .guid = udtTypeAttr.guid
                .Name = strTypeName
            End With
 
            lngCoCls = lngCoCls + 1
        End If
 
        ' Set ITypeInfo = Nothing
        CallPointer udtITypeInfo.IUnk.Release, oTypeInfo
        oTypeInfo = 0
 
NextItem:
    Next
 
    ' Set ITypeLib = Nothing
    CallPointer udtITypeLib.IUnk.Release, oTypeLib
    '
    GetCoClasses = True
End Function
 
Private Function CallPointer( _
    ByVal fnc As Long, _
    ParamArray params() _
) As Long
 
    Dim btASM(&HEC00& - 1)  As Byte
    Dim pASM                As Long
    Dim i                   As Integer
 
    pASM = VarPtr(btASM(0))
 
    AddByte pASM, &H58                  ' POP EAX
    AddByte pASM, &H59                  ' POP ECX
    AddByte pASM, &H59                  ' POP ECX
    AddByte pASM, &H59                  ' POP ECX
    AddByte pASM, &H59                  ' POP ECX
    AddByte pASM, &H50                  ' PUSH EAX
 
    For i = UBound(params) To 0 Step -1
        AddPush pASM, CLng(params(i))   ' PUSH dword
    Next
 
    AddCall pASM, fnc                   ' CALL rel addr
    AddByte pASM, &HC3                  ' RET
 
    CallPointer = CallWindowProc(VarPtr(btASM(0)), _
                                 0, 0, 0, 0)
End Function
 
Private Sub AddPush(pASM As Long, lng As Long)
    AddByte pASM, &H68
    AddLong pASM, lng
End Sub
 
Private Sub AddCall(pASM As Long, addr As Long)
    AddByte pASM, &HE8
    AddLong pASM, addr - pASM - 4
End Sub
 
Private Sub AddLong(pASM As Long, lng As Long)
    CpyMem ByVal pASM, lng, 4
    pASM = pASM + 4
End Sub
 
Private Sub AddByte(pASM As Long, bt As Byte)
    CpyMem ByVal pASM, bt, 1
    pASM = pASM + 1
End Sub
 
' http://www.aboutvb.de/khw/artikel/khwcreateguid.htm
Private Function GUID2Str( _
    GUIDBytes() As Byte _
) As String
 
    Dim nTemp       As String
    Dim nGUID(15)   As Byte
    Dim nLength     As Long
 
    nTemp = Space$(78)
    CpyMem nGUID(0), GUIDBytes(0), 16
    nLength = StringFromGUID2(nGUID(0), nTemp, Len(nTemp))
    GUID2Str = Left$(StrConv(nTemp, vbFromUnicode), nLength - 1)
End Function