代码之家  ›  专栏  ›  技术社区  ›  Craig Gidney Mihai

如何以编程方式更新vb6项目中的ocx引用?

  •  4
  • Craig Gidney Mihai  · 技术社区  · 16 年前

    我定期打破二进制兼容性,需要重新编译由几十个ActiveX DLL和OCX组成的整个VB6应用程序。我已经编写了一个脚本来自动化这个过程,但是我遇到了一个问题。

    当使用项目兼容性重新编译OCX时,其版本将递增,并且引用OCX的项目将不会重新编译,直到其引用更新到新版本。当项目正常打开时,系统会自动选中此选项,并提示用户更新引用,但我需要在脚本中执行此操作。

    我该怎么做?

    4 回复  |  直到 6 年前
        1
  •  1
  •   StayOnTarget Charlie Flowers    6 年前

    我想您必须编辑项目文件(.vbp)、表单文件(.frm)和引用dll和ocx的控制文件(.ctl),并增加typelib版本号。

    您可以在注册表中找到控件/dll的最新类型库版本号。

    这可能是一个痛苦取决于你有多少文件。

    黑客会使用您的脚本用vb6打开主项目,并发送密钥以确认更新引用,然后保存项目。

    祝你好运

        2
  •  2
  •   RS Conley    16 年前

    我的项目维护了十多年,由二十多个ActiveX DLL和半打控件组成。也用脚本系统编译。

    我不建议你做你正在做的事。

    我们的工作如下

    1. 进行更改,包括添加 在IDE中测试。
    2. 我们从 从上到上的层次结构
    3. 我们将新编辑的文件复制到 例如,修订目录 601,然后602等
    4. 我们创建了setup.exe
    5. 设置完成后,我们复制 把修订目录放到我们的 兼容性主管。注意我们 从不指向已编译的二进制文件 在项目目录中。总是要 一个包含所有 DLL。

    这样做的原因是,如果使用OLE视图工具查看IDL源,您会发现任何引用的控件或DLL都是通过include添加到接口中的。如果您指向项目目录中的二进制文件,那么include将从注册表中提取,这会导致许多限制和兼容性。

    但是,如果引用的dll存在于用于二进制兼容性的二进制文件存在的目录中,则vb6将使用它而不是注册表中的任何内容。

    现在有一个问题,你会得到一个罕见的基础。考虑这个继承权

    • 肌瘤病
    • MyObjutDLL
    • 米伊德尔
    • 迈克斯

    如果在myutilitydll中向类添加属性或方法,则myuidll可能无法编译,因为如果幸运或出现类似[inref]的奇怪错误,则会出现二进制不兼容错误。在任何情况下,解决方案都是编译myutilitydll,然后立即将myutilitydll复制到兼容目录中。然后,其余的自动编译将正常工作。

    您可能希望将此步骤包括在自动生成中。

    请注意,在许多情况下,项目在IDE中都可以正常工作。如果你现在意识到了这一点,你可能会拔出你的头发。

        3
  •  2
  •   StayOnTarget Charlie Flowers    6 年前

    我们正在做类似的事情,即直接在vb6.vbp文件中操作对所用ocx的引用,在我们的 VB6 Project References Update Tool ( download here )通常,当使用的ActiveX更改其版本号、CLSID等时,它用于更新引用。

    enter image description here

    这些工具是开放源码的,所以每个对这个问题感兴趣的人都可以借用我们的VB代码片段来实现这样的任务。

    我们的工具是用VisualBasic6编写的,并使用tlbinf32.dll(typelib信息dll),它允许您以编程方式从类型库中提取信息。

        4
  •  1
  •   Craig Gidney Mihai    16 年前

    自我回答:我已经编写了一些vb6代码以编程方式进行升级。它没有经过广泛的测试,可能有一些错误在这里和那里为角落的情况,但我确实成功地使用了它。

    Option Explicit
    
    Const HKEY_LOCAL_MACHINE As Long = &H80000002
    Const KEY_ENUMERATE_SUB_KEYS As Long = 8
    Private Declare Function RegOpenKeyEx Lib "advapi32.dll" Alias "RegOpenKeyExA" (ByVal hKey As Long, ByVal lpSubKey As String, ByVal ulOptions As Long, ByVal samDesired As Long, phkResult As Long) As Long
    Private Declare Function RegEnumKeyEx Lib "advapi32.dll" Alias "RegEnumKeyExA" (ByVal hKey As Long, ByVal dwIndex As Long, ByVal lpName As String, lpcbName As Long, lpReserved As Long, ByVal lpClass As String, lpcbClass As Long, lpftLastWriteTime As Any) As Long
    Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long
    
    '''Returns the expected major version of a GUID if it exists, and otherwise returns the highest registered major version.
    Public Function GetOcxMajorVersion(ByVal guid As String, Optional ByVal expected_version As Long) As Long
        Const BUFFER_SIZE As Long = 255
        Dim reg_key As Long
        Dim ret As Long
        Dim enum_index As Long
        Dim max_version As Long: max_version = -1
    
        ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\Classes\TypeLib\{" & guid & "}", 0, KEY_ENUMERATE_SUB_KEYS, reg_key)
        If ret <> 0 Then Err.Raise ret, , "Failed to open registry key."
        Do
            'Store next subkey name in buffer
            Dim buffer As String: buffer = Space(BUFFER_SIZE)
            Dim cur_buffer_size As Long: cur_buffer_size = BUFFER_SIZE
            ret = RegEnumKeyEx(reg_key, enum_index, buffer, cur_buffer_size, ByVal 0&, vbNullString, ByVal 0&, ByVal 0&)
            If ret <> 0 Then Exit Do
            buffer = Left(buffer, cur_buffer_size)
    
            'Keep most likely version
            buffer = Split(buffer, ".")(0)
            If Not buffer Like "*[!0-9A-B]*" And Len(buffer) < 4 Then
                Dim v As Long: v = CLng("&H" & buffer) 'convert from hex
                If v = expected_version Then
                    max_version = v
                    Exit Do
                ElseIf max_version < v Then
                    max_version = v
                End If
            End If
    
            enum_index = enum_index + 1
        Loop
        RegCloseKey reg_key
    
        If max_version = -1 Then Err.Raise -1, , "Failed to enumerate any viable subkeys."
        GetOcxMajorVersion = max_version
    End Function
    
    Public Function RemoveFilename(ByVal path As String) As String
        Dim folders() As String: folders = Split(Replace(path, "/", "\"), "\")
        RemoveFilename = Left(path, Len(path) - Len(folders(UBound(folders))))
    End Function
    
    '''Changes any invalid OCX references to newer registered version
    Public Sub UpdateFileOCXReferences(ByVal path As String)
        Dim file_data As String
        Dim changes_made As Boolean
    
        'Read
        Dim fn As Long: fn = FreeFile
        Open path For Input As fn
            While Not EOF(fn)
                Dim line As String
                Line Input #fn, line
    
                'check for ocx reference line
                If LCase(line) Like "object*=*{*-*-*-*-*}[#]*#.#*[#]#*;*.ocx*" Then
                    'get guid
                    Dim guid_start As Long: guid_start = InStr(line, "{") + 1
                    Dim guid_end As Long: guid_end = InStr(line, "}")
                    Dim guid As String: guid = Mid(line, guid_start, guid_end - guid_start)
    
                    'get reference major version
                    Dim version_start As Long: version_start = InStr(line, "#") + 1
                    Dim version_end As Long: version_end = InStr(version_start + 1, line, ".")
                    Dim version_text As String: version_text = Mid(line, version_start, version_end - version_start)
    
                    'play it safe
                    If Len(guid) <> 32 + 4 Then Err.Raise -1, , "GUID has unexpected length."
                    If Len(version_text) > 4 Then Err.Raise -1, , "Major version is larger than expected."
                    If guid Like "*[!0-9A-F-]*" Then Err.Raise -1, , "GUID has unexpected characters."
                    If version_text Like "*[!0-9]*" Then Err.Raise -1, , "Major version isn't an integer."
    
                    'get registry major version
                    Dim ref_version As Long: ref_version = CLng(version_text)
                    Dim reg_version As Long: reg_version = GetOcxMajorVersion(guid, ref_version)
    
                    'change line if necessary
                    If reg_version < ref_version Then
                        Err.Raise -1, , "Registered version precedes referenced version."
                    ElseIf reg_version > ref_version Then
                        line = Left(line, version_start - 1) & CStr(reg_version) & Mid(line, version_end)
                        changes_made = True
                    End If
                End If
    
                file_data = file_data & line & vbNewLine
            Wend
        Close fn
    
        'Write
        If changes_made Then
            Kill path
            Open path For Binary As fn
                Put fn, , file_data
            Close fn
        End If
    End Sub
    
    '''Changes any invalid in included files to newer registered version
    Public Sub UpdateSubFileOCXReferences(ByVal path As String)
        Dim folder As String: folder = RemoveFilename(path)
        Dim fn As Long: fn = FreeFile
        Open path For Input As fn
            While Not EOF(fn)
                Dim line As String
                Line Input #fn, line
    
                If LCase(line) Like "form=*.frm" _
                                Or LCase(line) Like "usercontrol=*.ctl" Then
                    Dim file As String: file = folder & Mid(line, InStr(line, "=") + 1)
                    If Dir(file) <> "" Then
                        UpdateFileOCXReferences file
                    End If
                End If
            Wend
        Close fn
    End Sub