1. Un début de syntaxe
Une bibliothèque de types permet de décrire linterface de lobjet quevous voulez créer. La description en langage ODL est compilée avec MkTypLib pour générer un fichier TLB. Ce fichier est à inclure dans les références du projet VB.
a. La syntaxe dunfichier ODL
Un fichier ODL a lasyntaxe suivante :
[
uuid(<GUID>),
version(<version>)
]
library <Nom de la bibliothèque>
{
importlib("stdole2.tlb");
[
uuid(<GUID>),
odl
]
interface <Nom delinterface> : stdole.IUnknown {
[<attributs>]<valeur de retour> <nomméthode>(<paramètres>);
}
}
Tout ce qui se trouveentre crochets constitue les attributs de lentité qui suit.
Le premier <GUID>doit être un GUID unique généré avec Guidgen. La version est dela forme Major.Minor.
Le second <GUID>(celui de linterface) doit correspondre au GUID de linterface, si vousimplémenté une interface existante ou un nouveau GUID si votre interfacenexiste pas.
Idéalement le nom delinterface commence par un I. Viennent ensuite, la liste des méthodes quidéfinit lordre dans la vtable.
<attributs> peut comprendre helpstring, vararg,propput, propputref, propget. La valeur de retour peutêtre soit HRESULT, soit nimporte quel type sauf un pointeur et il est préférableque ce ne soit pas une structure.Le nom de la méthode doit être unique dans linterface (sauf pour les propput,propputrefet propget).
<paramètre>à la syntaxe suivante : [<marshaling>]<type dedonnée> <nom de paramètre>.
<marshaling>peut être soit [in], soit [in,out], soit [out,retval] et peut inclure defaultvalue(<valeur>).
b. Intégrer unedescription du contenu
Pour fournir uneaide dans lExplorateurdobjet de VB, vous pouvezrajouter entre nimporte quel [] lattribut helpstring(« Description »)sauf dans les paramètres.
2. Les Alias
Bien que VB ne puissepas définir dalias, il sait très bien les utiliser sauf pour les Enums. Par exemple, on peut définir un alias delong (ou même unsigned long, VB ne le gère pas directement mais peut le gérer àtravers un alias. Pour les opérations, ils sont traités comme des signés). Unalias se définit dans un fichier ODL par :
Typedef [public] <typede base> <nom de lalias>
3. Les constantes
Les constantes sedéfinissent obligatoirement dans un module. Les constantes se déclarent comme suit :
[
dllname(« nimportequoi »)
]
module <nom du module>
{
const <type> <nomconstante> = <valeur> ;
}
« nimporte quoi » cest une chaîne quelconque puisque lattribut dllname est obligatoire pour un module.
<type>et <valeur> ne peuvent être que des type simples : unsigned char, short, long, float (Single enVB), double, LPWSTR, LPSTR, BSTR et cest tout
Les chaînes sontdéfinies comme en C : on peut inclure les séquences déchappement tellesque \n (nouvelle ligne), \t (tabulation), \r (retourà la ligne), \\ (\)
4. Les types de données de stdole pour VB
| Nom en ODL | Nom en VB | Taille en octets |
| unsigned char | Byte | 1 |
| Short | Integer | 2 |
| Long | Long | 4 |
| Float | Single | 4 |
| Double | Double | 8 |
| currency | Currency | 8 |
| DATE | Date | 8 |
| BSTR | String | 4 + 2 * nombre de caractères + 2 |
IDispatch* | Object | 4 |
| boolean | Boolean | 2 |
| VARIANT | Variant | 16 au moins |
| SAFEARRAY(<type>)* | Tableau en paramètres | 4 |
| Struct | Type/End Type | Somme de la taille des members |
| SAFEARRAY(<type>) | Tableau de taille variable | 24 |
| <type> <nom>[<taille>] | Tableau fixe | Sizeof(<type>) * <taille> |
| Enum | Enum | 4 |
| LPSTR | Pas déquivalent | Nombre de caractères + 1 (ANSI) |
| LPWSTR | Pas déquivalent | 2 * Nombre de caractères + 2 (UNICODE) |
5. Les structures
Dans le langage ODL,une structure se définit comme suit :
typedef struct {
<type> <nom> ;
} <nom structure> ;
Dans une structure,on ne peut inclure que les types suivants :
·Les types simples : long, float, DATE,
·Les types plus complexes :
o Les tableaux : SAFEARRAY(<type>)
o Les Variant : VARIANT
o Les chaines : BSTR mais pas LPSTR, LPWSTR
o Les tableaux de taille fixe : <type> <nom>[<taille>]
o Les objets : <interface>*
A noter que lon ne peut pas définir un typedef structqui porte le nom de GUID etsurement dautres.
A noter aussi que lon peut régler lalignement des donnéesafin dobtenir un alignement différents du 4 octets de VB. Sous mktyplib, cela se fait sur laligne de commande /align <valeur>.
6. Les modules : une autre façon de déclarer des APIs
Un module permet aussi de déclarer des fonctions de DLLs.
La syntaxe est la suivante :
[
dllname(« <nom de ladll> »)
]
module <Nomdu module>
{
[entry(<index ou nom>)]<type> <nom de fonction>(<paramètres>) ;
}
<index ou nom> est soit le nom dela fonction, soit sont index. <nom de la dll>est le nom de la dll (avec ou sans chemin).
A noter, une restriction dans les attributs desparamètres : on ne peut pas utiliser retval. Nous sommes donclimité à [in] et [in,out].
7. Ce que VB ne sait pas gérer dans les typelibs
Tout ce qui va êtredéfinit ici doit être remplacépour être utilisé par VB :
· Les paramètres« tableau par valeur ».VB ne sait gérer que les tableaux passés par référence(SAFEARRAY(<type>)* en ODL).
· Les paramètres« structures par valeur ».VB ne sait gérer les structures passés par référence (<structure>*en ODL). Il faut déclarer autant de paramètre de type Long que de champsdans la structure et ainsi remplir la pile avec les champs de la structure
· Les pointeursdans les structures. Il suffit deles remplacer par des long.
· Les types nonsignés. VB ne gère comme type nonsigné que Byte qui est un unsigned char. VB ne sait gérerni char (ne pas confondre avec char*) ni int. Il suffit deremplacer tous les unsigned long ou short par longet short et, char par unsigned char.
· Les chaines decaractères de taille fixe dans une structure. Il faut le remplacer par un tableau de short <nom>[<taille>].
· Les unions.
· Les paramètresde type [out] <type>*.Il peut être remplacé par [in,out]<type>* si lon passe toujoursune variable ou par [in] long si lon est amené à passer un NULL(0). On peut enfin le transformer en [out,retval] si cest le dernierparamètre. Il ne peut y avoir quun seul [out,retval]. Il devientalors la valeur de retour de la fonction. Voir plus loin pour les valeurs de retour.
8. VB-izé une interface
Pour trouver uneinterface déjà définie, vous pouvez utiliser lutilitaire OleView.exeet récupérer son IID (GUID).
- Vérifié que vous Navez PAS les attributs oleautomation et dual dans les attributs des interfaces. Ajoutez lattribut odl.
- Ajouter en tête toutes les fonctions des interfaces dont linterface hérite sauf IUnknown. Linterface doit dériver de IUnknown. Sa déclaration doit être : interface <nom de linterface> : stdole.IUnknown.
- Remplacer tout ce que VB ne supporte pas par les équivalents (voir section « Ce que VB ne sait pas gérer dans les typelibs »)
- Changer tout ce quil faut pour que VB arrête de faire le difficile
9. Les différents type de paramètres pour les fonctions
Tous les types debases : Byte, Integer, Long, Single, Double, Boolean, Currency, Date, Enum sont des types qui peuvent être passédirectement par valeur. Pour ces types, si le paramètre estdéfini :
· [in] <type> , cestun ByVal As <type>
· [in,out] <type>*, cest un ByRef As <type>
<type>est à choisir parmi un nom denum, unsigned char, short,long, float, double, boolean, currency, DATE.
Il ny pas dautrescombinaisons. A noter que pour ces types, on peut définir une valeur pardéfaut, qui rend le paramètre optionnel, avec lattribut defaultvalue(<valeur>).
Les types String (BSTR, LPSTR, LPWSTR), Object (IDispatch*)et autres types objets (toutes les interfaces) sont, par définition,des types pointeurs. Pour ces types, on définit :
- [in] BSTR, [in] LPSTR, [in] LPWSTR, cest un ByVal As String
- [in,out] BSTR*, [in,out] LPSTR*, [in,out] LPWSTR*, cest un ByRef As String
- [in] IDispatch*, cest un ByVal As Object
- [in,out] IDispatch**, cest un ByRef As Object
A noter que ByRef As Object (ou As <interface>) nest nécessaire que lorsque lon compte modifier la référencedobjet, ou en renvoyer une. Pour un simple passage de paramètre à des finsdutilisation, on optera toujours pour un ByVal
Les types tableauxsont eux aussi des pointeurs :
- [in] SAFEARRAY(<type>)* et [in,out] SAFEARRAY(<type>)* sont équivalent puisque lon ne peut pas passer de tableau par valeur.
<type>est nimporte quel type, simple, structure ou tableau.
10. Lesparamètres [out,retval]
Le dernier paramètre de la liste peut être attribué avec [out,retval]sil est du type ByRef cest à dire pointeur (long*, boolean*,
, BSTR*, IDispatch**, <interface>**,
). Il nepeut y en avoir quun seul.
11. LesParamArray : lattribut vararg
Pour déclarer que la liste des paramètres nest pas connue àpartir dun certain paramètre, on utilise ParamArray suivi dunnom de paramètre de type tableau de Variant (sous VB). En langageODL, il faut ajouter vararg dans les attributs de la méthode(et non dans les attributs du paramètre). Il sen suit une définition deméthode comme suit :
[vararg] <type><nom>(<liste de paramètres connus>,SAFEARRAY(VARIANT)*<nom arg>) ;
12. Lespropriétés : les attributs propput, propputref et propget
Pour déclarer une propriété en lecture-écriture, ilfaut deux fonctions : une pour lire et une pour écrire.Nous distinguerons deux cas :
· Les propriétés pour types normaux
· Les propriétés pour types objets
- Les propriétés normales : Property Get / Property Let (propget / propput)
Une propriété de ce type aura deux entrées dans la vtable.En langage ODL, elle auront le prototype suivant :
- Pour la lecture, Property Get :
- [propget] HRESULT <nom propriété>([out,retval] <type>* <nom>) ;
- Pour lécriture, Property Let :
- [propput] HRESULT <nom propriété>([in] <type> <nom>);
- Les propriétés objets : Property Get / Property Set (propget /propputref)
Une propriété de ce type aura deux entrées dans la vtable.En langage ODL, elle auront le prototype suivant :
- Pour la lecture, Property Get :
- [propget] HRESULT <nom propriété>([out,retval] <interface>** <nom>) ;
- Pour lécriture, Property Let :
- [propputref] HRESULT <nom propriété>([in] <interface>* <nom>);
On peut aussi avoir des propriétés en lecture-seule ouécriture-seule en supprimant une des deux fonctions.
Exemples de fichier ODL (extrait, voir source surles propriétés NTFS, Office
) :
[
uuid(b7e2416d-ea73-43f1-a7c6-b47e9a7f3fac),
helpstring("IPropertySet"),
version(1.0)
]
library Properties
{
importlib("stdole2.tlb");
//déclaration forward
interfaceIStream;
interfaceIstorage;
interfaceIEnumSTATSTG;
//Types et enums
typedef [helpstring("Moded'accès")] enum STGM {
[helpstring("Direct")]
STGM_DIRECT = 0x00000000,
[helpstring("AvecAnnulation possible (Transaction)")]
STGM_TRANSACTED = 0x00010000,
[helpstring("Simple")]
STGM_SIMPLE = 0x08000000,
[helpstring("Accèsen lecture")]
STGM_READ = 0x00000000,
[helpstring("Accèsen écriture")]
STGM_WRITE = 0x00000001,
[helpstring("Accèsen lecture-écriture")]
STGM_READWRITE = 0x00000002,
} STGM;
//alias privé
typedef unsigned char BYTE;
//type
typedef [helpstring("Entier64bits")] struct tagULARGE {
LONG lowDWORD;
LONG highDWORD;
} ULARGE;
typedef [helpstring("UniversalUnique IDentifier")] struct tagUUID {
LONG Data1;
SHORT Data2;
SHORT Data3;
BYTE Data4[8];
} UUID;
typedef [helpstring("Structurede statistiques sur l'objet de stockage")] structtagSTATSTG {
[helpstring("Nom")]
LONG pwcsName;
[helpstring("Type")]
STGTY type;
[helpstring("Taille")]
LONG cbSizeLow;
[helpstring("Taille")]
LONG cbSizeHigh;
[helpstring("Datede dernière modification")]
FILETIME mtime;
[helpstring("Date decréation")]
FILETIME ctime;
[helpstring("Date dudernier accès")]
FILETIME atime;
[helpstring("Moded'accès")]
STGM grfMode;
[helpstring("Type de vérouillagesupporté")]
LOCKTYPE grfLocksSupported;
[helpstring("CLSID")]
UUID clsid;
[helpstring("Etat")]
LONG grfStateBits;
LONG reserved;
} STATSTG;
// IEnumSTATSTG
[
odl,
uuid(0000000d-0000-0000-C000-000000000046),
helpstring("Enumère lesinformations statistiques")
]
interface IEnumSTATSTG :stdole.IUnknown {
[helpstring("Renvoiele statistique suivante")]
LONG Next(
[in]LONG celt,
[out]STATSTG *rgelt,
[out,defaultvalue(0)] LONG *pceltFetched);
[helpstring("Passela statistique actuelle")]
HRESULT Skip(
[in]LONG celt);
[helpstring("Réinitialise")]
HRESULT Reset();
[helpstring("Dupliquel'interface")]
HRESULT Clone(
[out,retval] IEnumSTATSTG **ppenum);
}
//IStorage
[
odl,
uuid(0000000b-0000-0000-C000-000000000046),
helpstring("Permet decréer et de gérer les objets de stockage structuré")
]
interfaceIStorage : stdole.IUnknown {
[helpstring("Crée un flux de stockage")]
HRESULT CreateStream(
[in] LPWSTR pwcsName,
[in] STGM grfMode,
[in, defaultvalue(0)]LONG reserved1,
[in, defaultvalue(0)]LONG reserved2,
[out, retval] IStream**ppstm);
[helpstring("Ouvre un flux de stockage")]
HRESULT OpenStream(
[in] LPWSTR pwcsName,
[in] LONG reserved1,
[in] STGM grfMode,
[in, defaultvalue(0)]LONG reserved2,
[out, retval] IStream**ppstm);
[helpstring("Crée unstockage")]
HRESULT CreateStorage(
[in] LPWSTR pwcsName,
[in] STGM grfMode,
[in, defaultvalue(0)]LONG reserved1,
[in, defaultvalue(0)]LONG reserved2,
[out, retval] IStorage**ppstg);
[helpstring("Ouvre unstockage")]
HRESULT OpenStorage(
[in] LPWSTR pwcsName,
[in] LONG pstgPriority,
[in] STGM grfMode,
[in, defaultvalue(0)]LONG snbExclude,
[in, defaultvalue(0)]LONG reserved,
[out, retval] IStorage**ppstg);
[helpstring("Copie le contenu de ce stockage dansun autre")]
HRESULT CopyTo(
[in] LONG ciidExclude,
[in] void*rgiidExclude,
[in] LPWSTR snbExclude,
[in]IStorage *pstgDest);
[helpstring("Déplace le contenu de ce stockagedans un autre")]
HRESULT MoveElementTo(
[in] LPWSTR pwcsName,
[in] IStorage*pstgDest,
[in] LPWSTR*pwcsNewName,
[in] STGMOVE grfFlags);
[helpstring("Enregistre le stockage")]
HRESULT Commit(
[in, defaultvalue(0)] STGC grfCommitFlags);
[helpstring("Annule les actions précedant àl'appel de cette méthode")]
HRESULT Revert();
[helpstring("Enumère les stockages et flux de cestockage")]
HRESULT EnumElements(
[in, defaultvalue(0)]LONG reserved1,
[in, defaultvalue(0)]LONG reserved2,
[in, defaultvalue(0)]LONG reserved3,
[out, retval]IEnumSTATSTG **ppenum);
[helpstring("Supprime un stockage ou flux de cestockage")]
HRESULT DestroyElement(
[in] LPWSTR pwcsName);
[helpstring("Renomme un stockage ou un flux de cestockage")]
HRESULT RenameElement(
[in] LPWSTRpwcsOldName,
[in] LPWSTRpwcsNewName);
[helpstring("Enregistre les dates d'accès")]
HRESULT SetElementTimes(
[in] LPWSTR pwcsName,
[in] FILETIME *pctime,
[in] FILETIME *patime,
[in] FILETIME *pmtime);
[helpstring("Définit la classe destockage")]
HRESULT SetClass(
[in] UUID *clsid);
[helpstring("Définit l'état du stockage")]
HRESULT SetStateBits(
[in] LONG grfStateBits,
[in] LONG grfMask);
[helpstring("Obtient des statistiques sur cestockage")]
HRESULT Stat(
[in,out] STATSTG*pstatstg,
[in, defaultvalue(0)] STATFLAG grfStatFlag);
}
}