2010-09-21 14 views
6

Ho un progetto VB6 che fa riferimento a COMSVCSLib e uno dei metodi effettua le chiamate al SharedPropertyGroupManager.CreatePropertyGroup di COMSVCSLib passando LockMethod e Processo come parametri.Perché le enumerazioni TypeLib non sono esposte come enumerazione in Visual Basic 6.0?

Ripulito il codice VB6:

Dim groupName  As String 
Dim spmMgr   As COMSVCSLib.SharedPropertyGroupManager 
Dim spmGroup  As COMSVCSLib.SharedPropertyGroup 

Dim bGroupExists As Boolean 

Set spmMgr = New COMSVCSLib.SharedPropertyGroupManager 

With spmMgr 
    Set spmGroup = .CreatePropertyGroup(groupName, LockMethod, Process, bGroupExists) 

End With 

Non avendo lavorato con VB6 da diversi anni, in un primo momento ho pensato LockMethod e di processo erano variabili o costanti definite da qualche altra parte all'interno del progetto.

Dopo una piccola ricerca sul Browser degli oggetti ho scoperto che erano entrambi esposti come costanti in COMSVCSLib.

Object Browser

Ma guardando la loro definizione in OLE/COM Object Viewer, che sembrano essere definiti come valori di un'enumerazione:

typedef enum { 
    LockSetGet = 0, 
    LockMethod = 1 
} __MIDL___MIDL_itf_autosvcs_0469_0002; 

Perché non sono IDL/TypeLib enumerazioni da COMSVCSLib essere esposti come enumerazioni a Visual Basic 6.0?

risposta

10

responsabilità: Io non sono un esperto di IDL (Interface Definition Language, che è il linguaggio utilizzato per definire tipi COM) o il compilatore Microsoft IDL (MIDL), ma sono venuto a conclusioni di seguito dopo aver giocato in giro con la libreria dei tipi per scrrun.dll, che ha un problema simile con enum. Alcune di queste informazioni sono state raccolte da un rapido sguardo a questo articolo DevX su IDL e VB6: IDL for VB Tutorial

VB6 si aspetta che l'enum reale di avere un nome, non solo un enum che è typedef 'd a un nome. Il nome __MIDL___MIDL_itf_autosvcs_0469_0002 è un segnaposto, poiché il typelib originale non ha definito il nome enum nello stesso typedef in cui sono definite le costanti enum.

Quando si visualizza la libreria dei tipi nel Visualizzatore OLE, il enum probabilmente assomiglia a questo:

typedef [public] __MIDL___MIDL_itf_autosvcs_0469_0002 LockModes; 

typedef enum { 
    LockSetGet = 0, 
    LockMethod = 1 
} __MIDL___MIDL_itf_autosvcs_0469_0002; 

La prima typedef crea il nome pubblico LockModes come alias per il MIDL___MIDL_itf_autosvcs_0469_0002 nome generato automaticamente che è stato dato a il enum. Quando è stata compilata la libreria di tipi originali, il compilatore midl ha generato il nome lungo e ha creato automaticamente un alias typedef che punta ad esso.

L'IDL originale probabilmente definito l'enumerazione in questo modo:

typedef enum { 
    LockSetGet = 0, 
    LockMethod = 1 
} LockModes; 

Quando il compilatore midl elabora un enum definizione scritta in questo modo, si auto-genera un nome per il enum (dal momento che manca - dovrebbe appare dopo la parola chiave enum). Questo è il nome __MIDL che viene visualizzato quando si visualizza la libreria dei tipi in OLE Viewer. Il compilatore midl genera inoltre automaticamente un secondo typedef che alias il nome typedef al nome generato automaticamente enum.

Il problema è che VB6 non può comprendere enum che vengono creati in questo modo. Si aspetta di tutto per essere in un unico typedef (cioè si dà il nome enum, nonché nominare il typedef):

typedef enum LocksMode { 
    LockSetGet = 0, 
    LockMethod = 1 
} LocksMode; 

IDL ossequi typedef 's allo stesso modo in cui C o C++ fa: si don' Devo dare all'enum stesso un nome, perché lo typedef ha già un nome, ma tu puoi dare all'enumerazione un nome se lo desideri. In altre parole, lo typedef e lo enum sono in realtà due entità separate. VB6 capita di riconoscere il e il enum come due cose distinte, ma vagamente correlate, quindi nel tuo caso vede une vede che questo è un alias di un enum senza nome, e vede anche un typedef per LockModes, che è un alias pubblico per l'altro typedef.

Dal primo typedef è pubblica, si vedrà una voce per LockModes nel Visualizzatore oggetti, sia perché è un alias per un enum, vedrete le costanti enum nel Visualizzatore oggetti pure. Tuttavia, l'enum stesso non ha un nome (quindi ottiene il nome auto-generato funky assegnato ad esso nel browser), e VB6 non può usare l'enumerazione perché il nome generato automaticamente è illegale in VB6 (i nomi con caratteri di sottolineatura doppio vengono automaticamente nascosti in VB6).

Per dimostrare quest'ultimo punto, se si digita questo nel codice VB6, Intellisense funzionerà e sarà la compilazione, ma ovviamente, non è molto ideale:

MsgBox COMSVCSLib.[__MIDL___MIDL_itf_autosvcs_0469_0002].LockMethod 

Il motivo per cui questo codice funziona è perché si è possibile inserire nomi che normalmente causano errori di sintassi (come i nomi che iniziano con caratteri di sottolineatura) tra parentesi per consentire a VB6 di accettare il nome normalmente non valido. Inoltre, il prefisso delle costanti con il nome generato automaticamente funziona con Intellisense perché è il nome effettivo che VB6 associa allo enum (ricorda che l'altro typedef è solo un alias di questo "reale", ma il nome generato automaticamente, e Apparentemente VB6 non può mettere insieme tutti i pezzi per realizzare entrambi i nomi riferiti allo stesso enum).

Piuttosto che digitare il nome ridicolmente lungo come sopra, è possibile anche accedere alle costanti enum inserendo il prefisso con il nome della libreria, ad esempio, COMSVCSLib.LockMethod dovrebbe funzionare. Non mi è chiaro perché funzioni effettivamente, e non sono sicuro di cosa succederebbe se due diverse costanti di tipo enum definissero lo stesso nome.

Infine, si potrebbe risolvere questo problema un modo diverso utilizzando l'IDL dal Visualizzatore OLE per creare un file IDL personalizzato, in cui si sostituiscono le attuali enum typedef con un singolo typedef per ogni enum che dà semplicemente sia la enum e lo typedef lo stesso nome (ovvero typedef enum LockModes { ... } LockModes;), ma dal momento che OLE Viewer non genera necessariamente IDL valido, probabilmente lo si dovrà modificare ulteriormente per farlo compilare. Se riesci a far funzionare tutto questo, puoi fare riferimento alla tua .tlb personalizzata dal progetto VB6 (invece della libreria COMSVCSLib) e gli enum funzioneranno come ti aspetteresti.

Se si vuole seguire questa strada, ci sono altri due strumenti necessari, che dovrebbero già stato installato sul computer di sviluppo (ma potrebbe essere necessario per la ricerca di loro):

  • midl.exe: Questo lo strumento può generare un file typelib (* .tlb) da un file .idl. Così si potrebbe copiare l'IDL dal Visualizzatore OLE in Blocco note, modificare le definizioni enum come descritto sopra, salvarlo come file .idl, e passarlo al midl.exe di fare una nuova libreria dei tipi:

    midl my-custom-typelib.idl

  • regtlib.exe : Questo strumento può registrare un file tLB, che è necessario se si vuole essere in grado di aggiungerlo come un riferimento al progetto VB6:

    regtlib.exe my-custom-typelib.tlb

Tuttavia, la creazione di una libreria dei tipi personalizzata per questo è probabilmente eccessivo e, come già accennato, potrebbe essere difficile ottenere un file IDL compilabile basato sull'output dal Visualizzatore OLE, poiché visualizza IDL con reverse engineering per la libreria dei tipi, non l'IDL originale.

+0

@wqw: Non sono sicuro di tutti i dettagli tecnici - questa risposta è basata su test empirici. Ad esempio, se si esegue l'IDL per scrrun.dll che OLE Viewer genera e lo compila in una nuova libreria di tipi con 'midl.exe', VB6 può vedere l'enum correttamente se si assegna il nome e il typef dell'enumerazione a un nome in l'IDL. Altrimenti, vedrai il nome 'enum' nel Browser degli oggetti, ma IntelliSense non funzionerà correttamente, e se guardi le costanti enum nel Browser degli oggetti, dirà che l'enum è membro di un enum con un'auto -generazione –

+0

Non è nemmeno necessario creare una nuova libreria di tipi per vedere questo: basta aggiungere un riferimento a 'scrrun.dll' in un nuovo progetto VB6, quindi aprire il Visualizzatore oggetti e osservare l'enumerazione' SpecialFolderConst'. Sì, viene visualizzato nel Visualizzatore oggetti e sì le costanti sono elencate per esso, ma se si fa clic sulla costante 'SystemFolder', ad esempio, il Visualizzatore oggetti dice che è un membro di' Scripting .__ MIDL ___ MIDL_itf_scrrun_0001_0000_0002'. Dovrebbe dire che la costante è un membro di 'Scripting.SpecialFolderConst', ma il modo in cui è definita la libreria dei tipi non è compatibile al 100% con VB6. –

+0

Inoltre, sto dicendo di provare a dire che la mia risposta è perfetta (questo è il motivo per cui ho messo un disclaimer lì), ma per quanto posso dire, questa spiegazione si adatta ai test effettivi. Ho creato una nuova libreria dei tipi per sccrun.dll e ho modificato enum typedef per includere i nomi enum oltre ai nomi typedef e quando aggiungo la libreria dei tipi a VB6, l'enum si visualizza correttamente nel Browser degli oggetti, le costanti enum sono elencati come membri dell'enumerazione corretta e IntelliSense funziona correttamente.Se, tuttavia, i dettagli tecnici effettivi sono errati, potresti fornire una risposta con le informazioni corrette? –

1

È esposto come enum. Selezionare LockModes nell'elenco delle classi e dare un'occhiata alla sezione delle informazioni in basso. Vedrai che è un enume. Oppure puoi digitare LockModes. nel tuo codice e otterresti le due opzioni.

Nel visualizzatore oggetti, ogni elemento all'interno di un enum viene identificato come un valore costante ma non è un const standalone. Le versioni standalone sono elencate separatamente quando si seleziona l'elemento <globals> nell'elenco delle classi.

+0

Sì ... Hai ragione sul fatto che sia un enum. Ho finito per vederlo nel browser degli oggetti un po 'prima di vedere la tua risposta. Ho anche provato il prefisso con LockModes e persino __MIDL___MIDL_itf_autosvcs_0469_0002 senza successo. Il codice è conforme come è. Se lo prefisso, non verrà compilato. –

Problemi correlati