Como faço para atualizar programaticamente referências OCX em projetos VB6?

StackOverflow https://stackoverflow.com/questions/620535

  •  05-07-2019
  •  | 
  •  

Pergunta

I periodicamente quebrar a compatibilidade binária e necessidade de recompilar uma aplicação vb6 toda composta de várias dezenas de ActiveX DLLs e OCXs no total. Eu escrevi um script para automatizar esse processo, mas eu encontrei um problema.

Quando um OCX é recompilado com compatibilidade de projeto sua versão é incrementado, e projetos que fazem referência a OCX não vai recompilar até que sua referência é atualizado para a nova versão. Esta é marcada automaticamente quando o projeto é aberto normalmente, eo usuário é solicitado a atualizar a referência, mas eu preciso fazê-lo em um script.

Como posso fazê-lo?

Foi útil?

Solução

Eu acho que você teria que editar os arquivos de projeto (.vbp), arquivos de formulário (.frm) e os arquivos de controle (.ctl) que fazem referência ao DLLs e OCXs e incrementar o número da versão do typelib.

Você iria encontrar mais recente número da versão typelib para o controle / DLL no registro.

Esta poderia ser uma dor, dependendo de quantos arquivos você tem.

Um hack seria abrir projeto principal com VB6 usando as teclas de programa e enviar para confirmar as referências Update e salve o projeto.

Good Luck

Outras dicas

Meu projeto, mantido ao longo de uma década, consiste de uma hierarquia de duas dezenas de ActiveX DLLs e uma meia dúzia de controles. Compilado com um sistema de script também.

Eu não recomendo fazer o que você está fazendo.

O que fazemos é a seguinte

  1. Faça nossas alterações, incluindo adições e teste no IDE.
  2. Nós compilar a partir da parte inferior da hierarquia ao topo
  3. nós copiar os arquivos recém cumprido a um diretório de revisão, por exemplo, 601, em seguida, 602 etc etc
  4. criamos o setup.exe
  5. Quando a instalação for finalizado copiamos sobre o diretório revisão em nossa diretor compatibilidade. Nota nós Nunca apontar para o binário compilado no diretório do projeto. sempre um diretório compability que tem tudo as DLLs.

A razão isto funciona é que se você olhar para a fonte IDL usando a ferramenta OLE Ver você vai achar que qualquer controle ou DLLs referenciado é adicionado à interface através de um #include. Se você apontar para o binário no diretório do projeto, em seguida, a inclusão é captado a partir do registro que pode levar a um monte de strangness e compatibilidade.

No entanto, se a DLL referenciado está presente no diretório que binário existe enquanto está sendo usado para compatibilidade binária, VB6 irá usar que em vez do que quer que no registro.

Agora, há um problema que você vai ter em uma base freqüente. Considere esta hierarquia

  • MyUtilityDLL
  • MyObjectDLL
  • MyUIDLL
  • MyEXE

Se você adicionar uma propriedade ou método de uma classe em MyUtilityDLL MyUIDLL não pode compilar dando um erro de incompatibilidade binário se você tiver sorte ou um erro estranho como [inref]. Em qualquer caso, a solução é compilar MyUtilityDLL e logo em seguida copiar MyUtilityDLL no diretório compatibilidade. Em seguida, o resto da compilação automatizado irá funcionar bem.

Você pode querer incluir este passo na compilação automatizada.

Note que em muitos casos os projectos vai funcionar bem no IDE. Para se agora você está ciente disto, você poderia estar puxando seu cabelo para fora.

Estamos fazendo coisas semelhantes, ou seja, manipulando as referências aos OCXs usado diretamente em arquivos VB6 .vbp, no nosso Referências VB6 projeto ferramenta de atualização de (download aqui ) . Geralmente é usado para atualizar as referências quando o ActiveX usado mudar seus números de versão, CLSIDs, etc.

enter descrição da imagem aqui

As ferramentas é open-source para que todos que está interessado em este problema pode emprestar nossos trechos de código VB para implementar tarefas como estes.

Nossa ferramenta é escrito em Visual Basic 6 e usos Tlbinf32.dll (o TypeLib Informação DLL) que lhe permite extrair programaticamente informações de bibliotecas de tipos.

Auto-resposta: Eu escrevi algum código VB6 para fazer a atualização programaticamente. Não é extensivamente testado, há provavelmente alguns erros aqui e ali para casos de canto, mas eu usá-lo com sucesso.

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top