CodeS-SourceS
Rechercher un code, un tuto, une réponse

Les appels d?apis en vb.net et conversion de code vb6 vers vb.net

Août 2017


<meta http-equiv= "CONTENT-TYPE" content="text/html; charset=utf-8"><title>Les appels d’APIs</title><meta name="GENERATOR" content="OpenOffice.org 2.0 (Linux)"><meta name="AUTHOR" content="Free"><meta name="CREATED" content="20051228;20440000"><meta name="CHANGED" content="20060226;18024400"> <style> <!-- @page { size: 21cm 29.7cm; margin: 2cm } P { margin-bottom: 0cm } P.western { so-language: en-GB; font-weight: bold } P.cjk { font-weight: bold } P.ctl { font-weight: bold } H1 { margin-top: 0cm; margin-bottom: 0cm } H1.western { font-family: "Times New Roman", serif; font-size: 12pt; so-language: en-GB; font-style: italic; font-weight: medium } H1.cjk { font-family: "Lucida Sans Unicode"; font-size: 12pt; font-style: italic; font-weight: medium } H1.ctl { font-family: "Tahoma"; font-size: 12pt; font-style: italic; font-weight: medium } H2 { margin-top: 0cm; margin-bottom: 0cm } H2.western { font-family: "Times New Roman", serif; font-size: 12pt; so-language: en-GB } H2.cjk { font-family: "Lucida Sans Unicode"; font-size: 12pt } H2.ctl { font-family: "Tahoma"; font-size: 12pt } H3 { margin-left: 2.5cm; margin-top: 0cm; margin-bottom: 0cm } H3.western { font-family: "Times New Roman", serif; font-size: 12pt } H3.cjk { font-family: "Lucida Sans Unicode"; font-size: 12pt } H3.ctl { font-family: "Tahoma"; font-size: 12pt } A:link { color: #0000ff } --> </style>Quand on commence àfaire de la programmation proche du système, donc avancée,on a souvent besoin d’API : fonctions proposées par lesystème d’exploitation. Ces fonctions sont stockéesdans de bibliothèque de liens : les DLLs.


Il en existe troiscatégories principales :
  • User32.dll : toutes le fonctions en rapport avec les fenêtres
  • Gdi32.dll : tout ce qui est en rapport avec les images
  • Kernel32.dll : tout ce qui a rapport avec les mécanismes internes : informations système, système de fichier, mutes, sémaphores.


====


Les déclarationsd’APIs se font comme suit :

{Private|Public}Declare [{Ansi|Unicode} * {Function|Sub} nom_fonction [Alias“vrai_nom_fonction“] Lib “nom_dll.dll“ (Param1 As Type1,Param2 As Type2,… ParamN As TypeN) [As TypeRetour]

{Private|Public} :portée de la déclaration (privée oupublique)

{Ansi|Unicode} :indique si les chaines sont traitées comme ANSI (1 octet) ouUNICODE (2 octets)

{Function|Sub} :fonction ou procédure, une API Windows est rarement uneprocédure (sauf CopyMemory)

[Alias“vrai_nom_fonction“ * : permet de renommer la fonction sisont vrai nom est, par exemple, trop long ou trop compliqué ( _fct@8 ) ou pour importer des fonctions exportées par Index (dans cecas l’alias sera # index ).

Penser à regarder si uneclasse faisant la même chose que l’API n’existerait pas…

Les paramètres


Il existe deux typesde paramètres : les paramètres par valeur et lesparamètres par référence (pointeur).

Un paramètrepar référence indique que l’on passe l’adresse dela variable à la fonction pour pouvoir modifier la variable àl’intérieur. Le nom d’un tel paramètre est précédéde ByRef.

Un paramètrepar valeur indique que l’on passe le contenu de la variable àla fonction. On ne peut donc pas modifier la variable àl’intérieur de la fonction. Le nom d’un tel paramètreest précédé de ByVal ou rien (ByVal par défaut).

Le type de retour


Si c’est une Sub,alors il n’y a pas de type de retour.

Sinon, c’est presquetoujours un Integer. Tout type de retour de plus de 4 octetsdevrait être passé par référence enparamètre.

Et si ma fonction n’est pas dansune liste


Alors la c’est unpeut plus compliqué. Mais si vous êtes là, c’estque vous avez le prototype C de votre fonction.

Pour que VB puisse utiliser unefonction C comme une API, il faut :
  • Que la convention d’appel soit STDCALL (par défaut cdecl en C)
  • Qu’elle soit exportée avec un extern « C » ou un def file


=======L‘attribut MarshalAs===

Cette attribut seplace avant le paramètre : <MarshalAs(…)>{ByRef|ByVal} nom As Type.

Par exemple :

PublicSub M1 (<MarshalAs(UnmanagedType.LPWStr)> msg As String)

On peut aussil’appliquer à un member de structure :

Par exemple :

<MarshalAs(UnmanagedType.LPWStr)> Public msg As String

Pour utilisercorrectement l’attribut MarshalAs, il faut ajouter la clause, endébut de classe :

ImportSystem.Runtime.InteropServices

== =Les types standards===

Voici un tableau detypes courants et de leurs traductions VB6 :


|-| Structure
|-| Tableau C
|-| SAFEARRAY(type)*
|-| Currency de COM
|-| Type param[taille *
|-| char param[taille *
|-| Hxxx
-Type en CType en VB
CharByVal Byte (mais considéré non signé)
ShortByVal Short
IntByVal Integer
LongByVal Integer
unsigned charByVal Byte
unsigned shortByVal Short (mais considéré signé)
unsigned intByVal Integer (mais considéré signé)
unsigned longByVal Integer (mais considéré signé)
BOOLByVal <MarshalAs(UnmanagedType.Bool)> param As Boolean
bool(<MarshalAs(UnmanagedType.I1)> param As Boolean
FloatByVal Single
DoubleByVal Double
ULONGLONG, LONGLONGByVal Long
char*ByVal <MarshalAs(UnmanagedType.LPStr) param As String
Short*ByRef Short
int*ByRef Integer
long*ByRef Integer
unsigned char*ByRef Byte
unsigned short*ByRef Integer (mais considéré signé)
unsigned int*ByRef Long (mais considéré signé)
unsigned long*ByRef Long (mais considéré signé)
BOOL*ByRef <MarshalAs(UnmanagedType.Bool)> param As Boolean
float*ByRef Single
double*ByRef Double
ULONGLONG*, LONGLONG*ByRef Long
ByVal <MarshalAs(UnmanagedType.BStr)>param As String
ByRef <MarshalAs(UnmanagedType.BStr)>param As String
ByVal <MarshalAs(UnmanagedType.LPTStr)>param As String
IUnknown*ByVal <MarshalAs(UnmanagedType.IUnknown)> param As Object
IUnknown**ByRef <MarshalAs(UnmanagedType.IUnknown)> param As Object
Interface* Interface}
Interface** Interface}
ByVal Structure
Structure*ByRef Structure (avec Attributs éventuellement pour les tableaux)
Voir plus bas == ByRef <MarshalAs(UnmanagedType.SafeArray,SafeArraySubType:=Type) param As Type ==
<MarshalAs(UnmanagedType.Currency)> param As Decimal == <MarshalAs(UnmanagedType.LPArray, SizeConst=taille)> param() As Type ==
== <MarshalAs(UnmanagedType.LPArray, SizeConst=taille)> param() As String ==
Integer (représente un handle)


==Pour les autres types, il estnécessaire de rajouter des attributs aux paramètres========Le type Any de VB6==<MarshalAs(UnmanagedType.AsAny)> param As Object

Mais il estpréférable de déclarer plusieurs fonctionsDeclare avec les différents types possibles pour le paramètre.

Les types pointeurs


Il existe un typepointeur en VB.Net : System.IntPtr.

Note : Lesfonctions VarPtr, ObjPtr et StrPtr n’existent plus et jedéconseille d'essayer de les réécrire car lesversions possibles ne marchent pas aussi bien.

Voir Travailleravec les pointeurs

== Les types Structures=====Attribut StructLayout===On peut changer letype de chaînes de caractères, l’alignement et lataille de la structure. :
<StructLayout(LayoutKind.Sequential,CharSet :charset ,Pack :alignement,Size:= taille )>

Private Structure nom

….

End Structure

charset (facultatif): CharSet.Unicode ou CharSet.Ansi

alignement (facultatif): aligner tous les 1, 2, 4, 8, 16, 32, 64 ou 128 octets

taille (trèsfacultatif): taille absolue de la structure en octet

Note sur le contenudes structures :
  • Les chaînes de taille fixe dans les structures (CHAR/WCHAR/TCHAR nom[taille * ) se traduisent en <MarshalAs(UnmanagedType.ByValTStr, SizeConst: =taille)>param() As String


Letype de charset (char/ANSI ou wchar/UNICODE) est défini dansl’attribut StructLayout de la structure.
  • Les chaines char*, WCHAR*, TCHAR* sont remplacées par <MarshalAs(UnmanagedType.LPStr)>membre As String, <MarshalAs(UnmanagedType.LPWStr)>membre As String et <MarshalAs(UnmanagedType.LPTStr)>membre As String.
  • Les types pointeurs sont System.IntPtr. Voir classe Marshal plus bas
  • Les tableaux de taille fixe type nom[taille * se traduisent par <MarshalAs(UnmanagedType.ByValArray, SizeConst:= taille )>param() As Type
  • Pour les autres types :


-Type CType VB
char/BYTEByte (interprété non signé)
short/USHORT/WORDShort
int, long/DWORD/ULONGInteger
ULONGLONG
Long
FloatSingle
doubleDouble
BOOL/BOOLEANInteger
boolByte


==Passer un tableau type C : de typesimples ou de structures==Pour passer un tableaude type C, on a UNE SEULE solution :
  • <MarshalAs(UnmanagedType.LPArray)>ByRef Type_des_cases_du_tableau : dans ce cas, on passe la première case du tableau (alloué), en général, il y a un paramètre pour donner la taille du tableau que l’on passe


Parexemple :

Dimt(10) As Long
Res Fct(t(0),10) =Passer un tampon chaîne type C==Pour passer un bufferchaîne C : char/wchar* buffer (int taille, suit engénéral), on utilise un ByVal String. Il fautimpérativement remplir la chaîne avec des caractèresavant de la passer à la fonction.

Parexemple :

Dim sas New String(20)

res =Fct(s,20)

On peut aussi utiliserla classe StringBuilder de la même façon.

= =Les pointeurs de fonctions de rappel(callback)==On peut utiliser letype « Delegate ». Pour cela :
  • On écrit le prototype Delegate de la fonction callback : {Private|Public|Protected} Delegate Function nom Delegate(params) As retour
  • Ecrire la déclaration de la fonction qui prend en paramètre le pointeur de fonction avec comme type pour ce paramètre pointeur de fonction nomDelegate.
  • Créer une fonctions ayant le même prototype que le delegate sans Delegate :


{Private|Public|Protected}Function nom(params) As retour

...

EndFunction
  • Lors de l'appel de la fonction déclarée, passer au paramètre pointeur de fonction : AddressOf nom


Note: nomDelegate n'a rien d'obligatoire : vous pouvez donner unautre nom au type delegate. Vous pouvez aussi avoir plusieursfonctions du même prototype que le delegate.

== Travail avec les pointeurs :l’objet Marshal===== Le type IntPtr===
Un IntPtr se construitavec un Integer ou avec un Long. On peut le convertir en Integer etLong. Pour initialiser le pointeur à NULL, on écrit : ptr IntPtr.Zero. == Lecture et écriture direct dans lesdonnées d’un pointeur===

Type peutprendre différentes valeurs : Byte, Int16, Int32, Int64et IntPtr.

Pour lire directementen mémoire, on utilise les fonctions Marshal.ReadType.Il en existe deux (en réalité trois) versions :

Marshal.ReadType(ByVal pointeur As IntPtr) As Type

Marshal.ReadType(ByValpointeur As IntPtr, ByVal offsetAs Integer) As Type

Lapremière version renvoie la donnée pointée parpointeur. On l’utilise pour les données seules.

Laseconde version renvoie la donnée pointée parpointeur[offset * . On l’utilise pour lesdonnées type tableau C.

Exemple :

Dim ptr As IntPtr =‘adresse trouvée quelque part…

Dimb As Byte = Marshal.ReadByte(ptr)

Pour écriredirectement en mémoire, on utilise les fonctionsMarshal.Write Type . Il en existe deux (en réalitétrois) versions :

Marshal.WriteType(ByVal pointeur As IntPtr, ByVal valeur AsType) As Type

Marshal.WriteType(ByValpointeur As IntPtr, ByVal offsetAs Integer, ByVal valeur As Type)As Type

Lapremière version écrit valeur dans la zonepointée par pointeur. On l’utilise pour les donnéesseules.

Laseconde version écrit valeur dans la zone pointéepar pointeur[offset * . On l’utilise pour lesdonnées type tableau C.

Exemple :

Dim ptr As IntPtr =‘adresse trouvée quelque part…
Dimb As Byte Marshal.WriteByte(ptr,19) Copier les donnéesd'un pointeur vers un objet VB=====Pour les types simples et les tableaux detypes simples===

La fonction Copypermet de copier des tableaux
  • d’un pointeur vers un tableau VB


OverloadsPublic Shared Sub Copy(ByVal zone_source As IntPtr,ByVal tableau_destination() As Type,ByVal index_début_copie As Integer, ByValnb_case_copie As Integer)
  • d’un tableau VB vers un pointeur


OverloadsPublic Shared Sub Copy(ByVal tableau_source() As Type,ByVal index_début_copie As Integer, ByValdestination As IntPtr, ByVal nb_case_copieAs Integer)

== ==Pourla fonction Copy, Type peut prendre les valeurs suivantes : Byte, Char, Double,Short, Integer, Long, Single.

== =Les chaînes de caractères===

Les fonctionsPtrToStringAnsi, PtrToStringBSTR, PtrToStringUni permettent de copierune chaîne de caractères respectivement : ANSI (1octet), BSTR (2 octets), UNICODE (2 octets).

Il existe deuxversions de ces fonctions :
  • prenant en paramètre un pointeur de type IntPtr et renvoyant un objet String contenant la chaîne entière
  • prenant en paramètre un pointeur de type IntPtr et le nombre de caractère à copier (Integer) et renvoyant un objet String contenant la chaîne copiée

Les structures


La fonctionPtrToStructure permet de copier une structure unique. Il en existedeux versions :
  • Sub PtrToStructure(ByVal ptr As IntPtr, ByVal structure As Object)


Cetteversion permet de copier une structure pointée par ptrdans un objet structure existant

Exemple :

Dim ptrAs IntPtr = ‘une adresse quelconque

Dims As New MaStructure

= =PtrToStructure(ptr,s)==

FunctionPtrToStructure(ByVal ptr As IntPtr, ByValstructureType As Type) As Object

Cetteversion alloue un nouvel objet structure de type structureTypeà partir des données ptr.

Exemple :

Dim ptrAs IntPtr = ‘une adresse quelconque
Dims As MaStructure CType(Marshal.PtrToStructure(ptr,GetType( MaStructure )), MaStructure) =Les tableaux de structures===
On peut faire uneboucle en incrémentant le pointeur de la taille d'unestructure : ptr New IntPtr(ptr.ToInt32 + taille). Transformer un objet VB enpointeur===== VarPtr,StrPtr et ObjPtr : GCHandle===

Note : ces fonctions sont àutiliser en dernier recourt : penser aux fonctions de l'objet Marshalavant de faire un CopyMemory VarPtr. L'objet Marshal donne du codeplus sûr.

VarPtr : déconseillée

La classeGCHandle permet de réécrire ces fonctions trèsutiles de VB6.

PublicFunction VarPtr(ByVal obj As Object) As IntPtr

Dim g AsGCHandle = GCHandle.Alloc(obj,GCHandleType.Pinned)

Dim ptrAs IntPtr = g.AddrOfPinnedObject()

g.Free()

Returnptr

EndFunction

Unefois que l’on a le pointeur vers la variable destination etle pointeur source (ou inversement), on peut faire une copiede mémoire avec CopyMemory comme avec VB6.

ATTENTION : tous les types (etsurtout les structures avec ByvalArray) ne sont pas Pinnable. Il sepeut donc que cette fonction échoue.

Pouravoir les mêmes fonctionnalités :

Dim ptrAs IntPtr = Marshal.AllocHGlobal(taille)

'onappelle la fonction avec un paramètre Byval IntPtr
Dimattr As type CType(Marshal.PtrToStructure(ptr, GetType( type )),type) FreeHGlobal(ptr)==

On peutaussi convertir un GCHandle (créé avec GCHandle.Alloc)en IntPtr et inversement avec GCHandle.op_Explicit.

StrPtr

Note :il est préférable d'utiliser les attributs deparamètres, Ansi ou Unicode avec le Declare et Byval String.

Il existe les fonctions StringToHGlobalAnsi etStringToHGlobalUni. Elles permettent respectivement de renvoyerun pointeur vers une chaîne ANSI et UNICODE en mémoire.Elle prennent en paramètre un objet de type String :

Function StringToHGlobalType(ByVal chaine As String) As IntPtr

Il est nécessaire de libérer la zone pointée(précédente) par le pointeur renvoyé afin de nepas faire de fuite mémoire :

Sub FreeHGlobal(ByVal pointeur_vers_chaine As IntPtr)

ObjPtr

En avez vous vraiment besoin....

Les« autres » méthodes de l’objet Marshal


-Marshaling avancéGetManagedThunkForUnmanagedMethodPtr, GetUnmanagedThunkForManagedMethodPtr, NumParamBytes
Fonction de bibliothèque COMBindToMoniker, GetActiveObject
Utilitaires COMChangeWrapperHandleStrength, CreateWrapperOfType, GetComObjectData, GetComSlotForMethodInfo, GetEndComSlot, GetMethodInfoForComSlot, GetStartComSlot, ReleaseComObject, SetComObjectData
Transformation des donnéesManagées en non managées : Copy, GetComInterfaceForObject, GetIDispatchForObject, GetIUnknownForObject, StringToBSTR, StringToCoTaskMemAnsi, StringToCoTaskMemAuto, StringToCoTaskMemUni, StringToHGlobalAnsi, StringToHGlobalAuto, StringToHGlobalUni, StructureToPtr, UnsafeAddrOfPinnedArrayElement

Non managées en managées : Copy, GetObjectForIUnknown, GetObjectForNativeVariant, GetObjectsForNativeVariants, GetTypedObjectForIUnknown, GetTypeForITypeInfo, PtrToStringAnsi, PtrToStringAuto, PtrToStringBSTR, PtrToStringUni

Propriétés : SystemDefaultCharSize, SystemMaxDBCSCharSize
Lecture et écriture directesReadByte, ReadInt16, ReadInt32, ReadInt64, ReadIntPtr, WriteByte, WriteInt16, WriteInt32, WriteInt64, WriteIntPtr
Gestion des erreursCOM : GetHRForException, ThrowExceptionForHR

Win32 : GetLastWin32Error, GetExceptionCode, GetExceptionPointers

Les deux : GetHRForLastWin32Error
Utilitaires d'hébergementGetThreadFromFiberCookie
IunknownAddRef, QueryInterface, Release
Gestion de la mémoireCOM : AllocCoTaskMem, ReAllocCoTaskMem, FreeCoTaskMem, FreeBSTR

Win32 : AllocHGlobal, ReAllocHGlobal, FreeHGlobal

Les deux : DestroyStructure
Utilitaires d'appel de plate-formePrelink, PrelinkAll, GetHINSTANCE
Examen de la structureOffsetOf, SizeOf
Informations de typeGenerateGuidForType, GenerateProgIdForType, GetTypeInfoName, GetTypeLibGuid, GetTypeLibGuidForAssembly, GetTypeLibLcid, GetTypeLibName, IsComObject, IsTypeVisibleFromCom


Adresse d'origine

A voir également

Publié par ShareVB.
Ce document intitulé «  Les appels d?apis en vb.net et conversion de code vb6 vers vb.net  » issu de CodeS-SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Les appels d'apis en vb6
Le subclassing en vb6 et vb.net