Results 1 to 10 of 10

Thread: [RESOLVED] How to find the correct ProgID to use with CreateObject Function?

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Resolved [RESOLVED] How to find the correct ProgID to use with CreateObject Function?

    There are two ways to use Regular Expression from VBScript:

    One is to reference to "Microsoft VBScript Regular Expression 5.5"
    The other, use CreateObject("VBScript.RegExp")

    OK, it is because I know the ProgID of the regular expression, so I can use the CreateObject function. What if I don't know the ProgID? So then how should I find it? And as I see there are two versions of RegExp there, what if I want to use a particular version?

    P.S CLSID is also applicable to CreateObject function?
    Last edited by bPrice; Jan 30th, 2015 at 09:57 PM.

  2. #2
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: How to find the correct ProgID to use with CreateObject Function?

    You can't directly make use of CLSID values in VB6. They get used under the covers when you have a reference set, but you cannot use them with CreateObject() calls and normally you'd never have a reason to.

    In VBScript RegExp is an intrinsic class you can create instances of using Set x = New RegExp. This will get you the class implementing the 5.5 interface, since the ancient 1.0 interface is only around for backward compatibility with very early days.

    So don't bother with the 1.0 interface, which was even more quirky than the current one (5.5). The strange numbering comes from the way Microsoft tried to realign script engine and scripting component versions with IE versions when they went to 2.0, which got numbered as 5.5 instead to match IE 5.5. This of course fell apart once they realized how interface version numbering is really meant to work, or perhaps it was an accident caused by some Marketing clown sticking his oar in where it did not belong. In any case there is no "newer version" even though other scripting components moved on to 5.6, 5.7, 5.8, etc. over time.

    I don't think modern versions of Windows even have a version dependent ProgID for late-binding 1.0 anymore, if they ever did. Just set a reference to the 5.5 typelib and call it good, there is no reason to do otherwise in a VB6 program. You don't want to use CreateObject() calls here.

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

    Re: How to find the correct ProgID to use with CreateObject Function?

    Quote Originally Posted by bPrice View Post
    There are two ways to use Regular Expression from VBScript:

    One is to reference to "Microsoft VBScript Regular Expression 5.5"
    The other, use CreateObject("VBScript.RegExp")
    The former is known as Early Binding while the latter is known as Late Binding. It is generally better to early bind object references.

    Quote Originally Posted by bPrice View Post
    And as I see there are two versions of RegExp there, what if I want to use a particular version?
    Version 1.0 of the Microsoft VBScript Regular Expressions library is obsolete. It is provided only for compatibility.

    As shown in the code below, both v1.0 and v5.5 have the same ProgIDs, therefore, you won't be able to specify the lower version if you late bind the RegExp object.

    Quote Originally Posted by bPrice View Post
    P.S CLSID is also applicable to CreateObject function?
    No. The Class parameter of the CreateObject function expects the ProgID only of the ActiveX object.

    Quote Originally Posted by bPrice View Post
    OK, it is because I know the ProgID of the regular expression, so I can use the CreateObject function. What if I don't know the ProgID? So then how should I find it?
    You could hunt for the programmatic identifier (ProgID) in the Registry. Or you could try this routine, which seems to be working correctly as far as I can tell.

    Code:
    Option Explicit
    
    Private Type GUID
        Data1    As Long
        Data2    As Integer
        Data3    As Integer
        Data4(7) As Byte
    End Type
    
    Private Declare Function CLSIDFromString Lib "ole32.dll" (ByVal lpsz As Long, ByRef pclsid As Any) As Long
    Private Declare Function ProgIDFromCLSID Lib "ole32.dll" (ByRef CLSID As Any, ByRef lplpszProgID As Long) As Long
    Private Declare Function SysReAllocString Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long) As Long
    Private Declare Sub CoTaskMemFree Lib "ole32.dll" (Optional ByVal pv As Long)
    
    Public Function GetProgIDFromObject(ByVal Obj As Object) As String
        Const NOERROR = 0&, S_OK = 0&
        Dim lpszProgID As Long, sGUID As String, CLSID As GUID
        Dim oClassInfo As CoClassInfo, oInterfaceInfo As InterfaceInfo
    
        With TLIApplication.InterfaceInfoFromObject(Obj) 'Set a reference to TypeLib Information (TLBINF32.DLL)
            sGUID = .GUID
            For Each oClassInfo In .Parent.CoClasses
                For Each oInterfaceInfo In oClassInfo.Interfaces
                    If StrComp(sGUID, oInterfaceInfo.GUID) = 0 Then
                        If CLSIDFromString(StrPtr(oClassInfo.GUID), CLSID) = NOERROR Then
                            If ProgIDFromCLSID(CLSID, lpszProgID) = S_OK Then
                                SysReAllocString VarPtr(GetProgIDFromObject), lpszProgID
                                CoTaskMemFree lpszProgID
                                Exit Function
                            End If
                        End If
                    End If
                Next
            Next
        End With
    End Function
    Code:
    Private Sub Main()
        Debug.Print """"; GetProgIDFromObject(New ADODB.Stream); """"                        '"ADODB.Stream.6.0"
        Debug.Print """"; GetProgIDFromObject(New CDO.Message); """"                         '"CDO.Message.1"
        Debug.Print """"; GetProgIDFromObject(New IWshRuntimeLibrary.WshShell); """"         '"WScript.Shell.1"
        Debug.Print """"; GetProgIDFromObject(New MSHTML.HTMLDocument); """"                 '"htmlfile"
        Debug.Print """"; GetProgIDFromObject(New Scripting.FileSystemObject); """"          '"Scripting.FileSystemObject"
        Debug.Print """"; GetProgIDFromObject(New IWshRuntimeLibrary.FileSystemObject); """" '"Scripting.FileSystemObject"
        Debug.Print """"; GetProgIDFromObject(New SHDocVw.WebBrowser); """"                  '"Shell.Explorer.1"
        Debug.Print """"; GetProgIDFromObject(New Shell32.Shell); """"                       '"Shell.Application.1"
        Debug.Print """"; GetProgIDFromObject(New SpeechLib.SpVoice); """"                   '"SAPI.SpVoice.1"
        Debug.Print """"; GetProgIDFromObject(New stdole.StdFont); """"                      '"StdFont"
        Debug.Print """"; GetProgIDFromObject(New TaskScheduler.TaskScheduler); """"         '"Schedule.Service.1"
        Debug.Print """"; GetProgIDFromObject(New VBScript_RegExp_10.RegExp); """"           '"VBScript.RegExp"
        Debug.Print """"; GetProgIDFromObject(New VBScript_RegExp_55.RegExp); """"           '"VBScript.RegExp"
        Debug.Print """"; GetProgIDFromObject(New WbemScripting.SWbemLocator); """"          '"WbemScripting.SWbemLocator.1"
        Debug.Print """"; GetProgIDFromObject(New WIA.ImageFile); """"                       '"WIA.ImageFile.1"
        Debug.Print """"; GetProgIDFromObject(New WinHttp.WinHttpRequest); """"              '"WinHttp.WinHttpRequest.5.1"
    End Sub
    You might also want to try other viable solutions, like Schmidt's example here or Microsoft's C++ sample code in their KB article How To Get the CLSID and ProgID of a CoClass from the Type Library in OCX, DLL, and EXE Files.

    Note that the ProgID retrieved by the function above oftentimes includes the version number. Many ActiveX objects also registers a VersionIndependentProgID in addition to the ProgID. Whenever possible, you should use the version independent one. Just remove the version number from the returned ProgId and see if it still works.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  4. #4

    Thread Starter
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: How to find the correct ProgID to use with CreateObject Function?

    Bonnie:

    Your reply is very helpful but code provided doesn't work on my machine. The code here for the GetProgIDFromObject seems to lack several type declarations, i.e. oClassInfo. And the submain looks weird as there are so many semicolons in one single line and is it possible to use New keyword when passing parameters?

    The latter problem might be okay but there is definitely missing type declarations.

    I will follow the links and read more first.

    Regardless of the above, I saw

    Code:
     Debug.Print """"; GetProgIDFromObject(New VBScript_RegExp_10.RegExp); """"           '"VBScript.RegExp"
        Debug.Print """"; GetProgIDFromObject(New VBScript_RegExp_55.RegExp); """"           '"VBScript.RegExp"
    So both 10 and 55 version of RegExp use the same ProgID. How do I know for sure if I get the 55 version of RegExp by CreateObject function.

  5. #5

    Thread Starter
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: How to find the correct ProgID to use with CreateObject Function?

    Quote Originally Posted by dilettante View Post
    Just set a reference to the 5.5 typelib and call it good, there is no reason to do otherwise in a VB6 program. You don't want to use CreateObject() calls here.
    Well actually I'm using VBA for Excel. I wrote several subroutines that make use of RegExp but when I copy and paste them to ther Workbooks, I have to set the reference once again. I do this every time and it's kinda tedious. Right now I've already replaced parts like

    Code:
    Dim mRX As New RegExp
    Dim mMS As MatchCollection
    Dim mM As Match
    to

    Code:
        Dim mRX As Object
        Set mRX = CreateObject("VBScript.RegExp")
        Dim mMS As Object
        Dim mM As Object
    However, the fact that the ProgID of RegExp doesn't specify which version I am using kinda worries me. I don't want make any mistakes as it involves a lot string replacement.

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

    Re: How to find the correct ProgID to use with CreateObject Function?

    Quote Originally Posted by bPrice View Post
    ... but code provided doesn't work on my machine. The code here for the GetProgIDFromObject seems to lack several type declarations, i.e. oClassInfo.
    Uh, did you remember to "Set a reference to TypeLib Information (TLBINF32.DLL)"? The missing object types are declared there.

    Quote Originally Posted by bPrice View Post
    And the submain looks weird as there are so many semicolons in one single line ...
    The semicolons tells the Print method to print multiple expressions on the same line without any intervening character(s). This achieves the same effect as concatenating the (String) expressions.

    Quote Originally Posted by bPrice View Post
    ... and is it possible to use New keyword when passing parameters?
    Yes. The New keyword is used for explicitly instantiating a new object (or implicitly, as in the case of As New). It can be used anywhere you want to pass or reference a new object instance. Here are a couple more examples:

    Code:
    With New Collection
        .Add New Collection
    End With
    Quote Originally Posted by bPrice View Post
    How do I know for sure if I get the 55 version of RegExp by CreateObject function.
    If you don't get an "Object doesn't support this property or method" error when invoking any class method/property available only on the higher version (such as the Multiline property), then you are definitely not using the older version.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  7. #7
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: How to find the correct ProgID to use with CreateObject Function?

    Then you are posting in the wrong forum. Try the one for Office macro scripting.

    But as it says on MSDN:

    When given the version-independent ProgID, the CLSIDFromProgID function returns the CLSID of the current version.
    And CreateObject makes use of CLSIDFromProgID.

    There are no version-dependent ProgIDs for these two classes so there is little risk of ever creating an instance of the old 1.0 RegExp class using CreateObject calls.
    Last edited by dilettante; Feb 1st, 2015 at 01:02 AM.

  8. #8

    Thread Starter
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: How to find the correct ProgID to use with CreateObject Function?

    Quote Originally Posted by dilettante View Post
    And CreateObject makes use of CLSIDFromProgID.

    There are no version-dependent ProgIDs for these two classes so there is little risk of ever creating an instance of the old 1.0 RegExp class using CreateObject calls.
    Thank you for the tip

    Quote Originally Posted by dilettante View Post
    Then you are posting in the wrong forum. Try the one for Office macro scripting.
    Come on, don't shove me out of here. I like this Forum And you guys are great. As far as this question concerns, what difference does it make to post the thread elsewhere.

  9. #9

    Thread Starter
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    341

    Re: How to find the correct ProgID to use with CreateObject Function?

    Quote Originally Posted by Bonnie West View Post
    Uh, did you remember to "Set a reference to TypeLib Information (TLBINF32.DLL)"? The missing object types are declared there.
    I was going to rate this post but as it said:

    You must spread some Reputation around before giving it to Bonnie West again.
    Can't do that too often

  10. #10
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: How to find the correct ProgID to use with CreateObject Function?

    Wrong forum is wrong forum. But the main reason to post in the right place is to help future readers who find the thread by searching, though another important one is that the environments are different enough such a thread can quickly go down a rabbit hole of confusion.

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