Visual dBASE permet de réaliser pratiquement tout ce que vous pouvez imaginer, grâce à la richesse des fonctions et du langage, qui découle de l’héritage considérable apporté par les versions antérieures depuis ses origines, comme premier langage de Bases de données pour PC. L’avènement des dernières versions actuelles sous Windows, et l’introduction du langage de programmation objet comme l’arête dorsale de la gestion des données et de l’interface Homme Machine ont doté le produit des meilleures capacités pour réaliser des applications de Bases de données d’excellente qualité.
Une application développée et conçue grâce à Visual dBASE est avant tout - à ce jour - une application Windows. En d’autres termes, elle doit se plier aux règles et respecter les contraintes imposées par ce système d’exploitation. Afin de garder une certaine homogénéité et garantir une bonne intégration et exécution au sein du système, Visual dBASE doit exploiter au mieux les ressources et les bibliothèques mises à disposition par celui-ci pour bâtir une application. Ces ressources sont accessibles au travers de l'Application programming interface de Windows, appelée plus couramment API Windows.
Visual dBASE, au travers des outils visuels de toute dernière génération mis à disposition pour la construction d’une application, qu’elle soit ou non orientée gestion de données, permet de réaliser avec une extrême simplicité la plupart des opérations complexes requises lors de l’élaboration d’une telle application, tout en offrant un excellent compromis entre la gestion de la complexité de l'API et la richesse des possibilités offertes. Étant avant tout une application Windows, une application construite avec Visual dBASE utilise déjà de nombreuses fonctions offertes par l’API 32 de Windows ; mais l’avantage principal d’un tel outil est qu’il transforme de façon plus abordable un domaine réservé initialement aux seuls spécialistes, et surtout il permet de recentrer l’effort du développement non plus sur la programmation système mais sur les spécificités de l’application.
Toutefois, et pour répondre à des situations particulières, il arrive que certaines caractéristiques ou options ne soient pas directement réalisables ou offertes par l’outil ou le langage Visual dBASE. Dans ce cas, et dans la mesure où ces exigences restent avant tout compatibles de la philosophie générale du système d’exploitation Windows, il faut hélas quitter le sympathique environnement pour s’aventurer dans les arcanes de la programmation Windows, afin d’utiliser directement les fonctions de l’API Windows 32 bits.
Le canevas de cet article est le suivant :
Les concepteurs de Visual dBASE ont introduit dans le produit une ouverture de façon à rendre utilisables les fonctions des bibliothèques 32 bits contenues dans les fichiers DLL. A ce propos, Visual dBASE 7.01 ne peut utiliser que les bibliothèques 32 bits, à l’inverse de son aîné 5.7 qui ne connaît que le monde 16 bits, compatibilité avec Windows 3.1 oblige.
Les fichiers DLL sont des fichiers binaires qui contiennent du code et/ou des ressources (bitmaps, icônes) qui peuvent être partagées de façon simultanée par plusieurs applications. Windows lui-même est bâti autour de ces DLLs, utilisables dans nos propres applications.
Ces fonctions sont dénommées dans Visual dBASE “fonctions externes”. L’utilisation de telles fonctions dans un programme est détaillée dans l’aide en ligne, chercher le mot “extern” ou taper help extern dans la fenêtre de commande.
Nous allons voir comment utiliser de ce type de fonction, et nous orienter spécifiquement sur celles offertes par l’API Windows 32, afin de bien cerner leurs exigences et leurs limites d’emploi. Le but recherché consiste avant tout à acquérir la maîtrise d'une technique qui va permettre d'exploiter et d'utiliser les fonctions de l'API 32.
Ce n'est pas là la seule difficulté à surmonter lorsque l'on s'attaque à l'API 32, car en général, le point délicat consistera à dénicher dans la pléthore de fonctions API disponibles, celle qui permettra d'effectuer l'action désirée.
Dans toutes ses versions, Visual dBASE 7.01 est livré avec un fichier d'aide Windows particulier dénommé “Win 32 Programmer's Reference”. Nous l'appellerons par la suite “Aide sur l'API 32”. On trouvera ce fichier dans le répertoire _DBWINHOME\Help\MSHelp (où le répertoire _DBWINHOME signifie celui dans lequel vous avez installé Visual dBASE).
Nous considérerons tout d'abord comme support, dans cet article, la fonction API 32 dénommée : ShellExecute. Cette fonction permet de lancer depuis Visual dBASE une autre application Windows, sans apparition d'une fenêtre DOS, à la différence de la commande RUN() qui fait partie du langage.
Commencez par rechercher cette fonction dans le fichier d'aide API 32 cité ci-avant. Vous obtiendrez la page suivante :
Voyons à présent en détail les différentes indications portées en rouge :
L’interface de programmation Windows peut sembler obscure au premier abord, surtout lorsqu’on a l’habitude d’utiliser un langage de haut niveau comme Visual dBASE. En effet, elle a été conçue, réalisée en langage C, et était initialement destinée à être utilisée par des programmeurs en C. Par conséquent, la difficulté d’utilisation de cette interface tient essentiellement au fait qu’il faut s’adapter aux particularités de ce langage.
Le but de ce chapitre n'est certainement pas d'apprendre le C, ni encore moins le C++. Il s'agit simplement de connaître les quelques éléments de ce langage qui vont permettre d'utiliser les fonctions de l'API.
Une des différences principales entre le C et Visual dBASE réside dans le typage et la structure des données. Contrairement à Visual dBASE, les données en C sont toujours déclarées avec un type explicite. Le C fait également la distinction entre les variables simples et les pointeurs. Il est important d’en comprendre les différences essentielles :
Pour en revenir au type de données, l’API Windows utilise bien évidemment les types de données natifs du C. Ces types natifs sont en lettres minuscules. Les types dérivés sont en général en majuscule.
Un pointeur peut être déclaré de façon explicite en C, dans ce cas, le nom de la variable est précédé d'un astérisque (*). Dans les types dérivés, l' * est généralement contenue dans le nom du type, comme, par exemple, ceux de Windows, dont le nom de type commence souvent par les lettres LP, soit Long Pointer.
Voici, par exemple, quelques déclarations de variables en C :
char c = 'a'
// Variable caractère, sur 1 octet, initialisée à
la lettre 'a'.
int *k
// Pointeur sur un integer
Exemple de tableau en C :
short tab[2][3]
// Crée un tableau de 2 x 3 éléments, qui sont des
"short".
// tab est en réalité un pointeur sur le premier short
// de la zone mémoire réservée pour le tableau
Exemple de chaînes de caractères en C :
char st[] = "Bonjour!"
// Crée une chaîne, dont la taille mémoire
est
// exactement sa longueur + 1 (à cause du Null final),
// sur laquelle pointe le pointeur st.
// Cette chaîne est considérée comme figée
en mémoire.
char st_tab[256]
// Ici, on réserve un tableau de 256 octets pour y stocker,
// si on le souhaite, des caractères, au maximum 255 +
'\0'
Le tableau ci après donne les types
de base et les pointeurs utilisés dans Windows, qui dérivent
de types C :
Type C natif | Taille mémoire (octets) | Exemple d'autres Types équivalents utilisé dans Windows | Type Visual dBASE | Déclaration de variable dans le prototype de fonction Visual dBASE | Déclaration de pointeur dans le prototype de fonction Visual dBASE |
char | 1 | BYTE | Numeric | CCHAR | |
unsigned char | 1 | UCHAR | Numeric | CUCHAR | |
short | 2 | WORD | Numeric | CSHORT | CPTR SHORT |
unsigned short | 2 | USHORT | Numeric | CUSHORT | CPTR CUSHORT |
int | 4 | DWORD, HWND, BOOL, HDC | Numeric | CINT | CPTR CINT |
UINT | 4 | Numeric | CUINT | CPTR CUINT | |
long | 4 | LPVOID | Numeric | CLONG | CPTR CLONG |
unsigned long | 4 | ULONG | Numeric | CULONG | CPTR CULONG |
float | 4 | Numeric | CFLOAT | CPTR CFLOAT | |
double | 8 | Numeric | CDOUBLE | CPTR CDOUBLE | |
LDOUBLE | 10 | Numeric | CLDOUBLE | CPTR CLDOUBLE | |
LOGICAL | 1 | Logical | CLOGICAL | CPTR CLOGICAL | |
void | N/A | N/A | CVOID |
Quelques précisions sur ce tableau :
Windows utilise dans les déclarations de fonctions de nombreux autres types dérivés des types de base C figurant dans le tableau. Tous ces autres types peuvent être définis dans les déclarations EXTERN à partir par des Types Visual dBASE natifs.
Une seule catégorie n'est pas supportée
par Visual dBASE, il s'agit des fonctions CALLBACK,
que nous n'aborderons pas ici. Brièvement, c'est un équivalent
du type Function Pointer (FP) de Visual dBASE.
Les
chaînes de caractères et les pointeurs C
Après avoir vu les types simples, ce chapitre traite le sujet particulier des chaînes de caractères et des pointeurs en C, et leur utilisation avec Visual dBASE dans les prototypes des fonctions de l'API.
Une chaîne de caractères est comme son nom l’indique une suite de caractères. Ces caractères peuvent être stockés :
Exécutez les quelques lignes de code suivantes pour visualiser comment les chaînes sont stockées dans dBASE. Notez que commence à 0.
s = new String("Bonjour")
for j = 0 to (s.Length*2)-1
?s.getByte(j), chr(s.getByte(j))
next j
Lorsqu'une chaîne de caractères doit être fournie à une fonction de l'API, il faut respecter impérativement le type attendu, byte ou Unicode.
Note: Une indication importante à connaître et qui concerne les chaînes de caractère et le langage C : celui-ci impose que le dernier caractère d’une chaîne soit obligatoirement le caractère chr(0), encore appelé Null char, ou '\0'. Visual dBASE tient compte de cette contrainte lorsqu’il effectue les appels des fonctions externes et qu'il doit passer une chaîne de caractères en argument, mais cette règle doit toujours rester présente à l’esprit, plus particulièrement lorsque des conversions de type byte <-> Unicode interviennent.
Une chaîne de caractères en C consiste toujours en une suite de CHAR ou de WORD (si la chaîne est Unicode), sur laquelle pointe un “pointeur” C de type CHAR ou de WORD. Ce pointeur est lui-même une variable, qui contient une adresse mémoire, l'adresse du premier caractère de la chaîne qu'il pointe. Déclarer une chaîne de caractères en C revient toujours à déclarer un pointeur - c'est à dire une adresse mémoire - sur cette chaîne. La longueur d'une chaîne est fixée implicitement par le premier Null de la chaîne.
Pour utiliser les chaînes, deux prototypes
de paramètres existent dans Visual dBASE, il s'agit des mots clé
CSTRING
et CPTR.
Ils désignent tous deux un pointeur sur une chaîne, mais ils
présentent les différences fondamentales suivantes :
Déclaration CSTRING | Déclaration CPTR |
Conversion
automatique implicite de Unicode vers Byte lors d'un appel à la
fonction externe.
La chaîne peut contenir des caractères Null, mais j'ai rencontré des problèmes avec des chaînes contenant des Null. |
Aucune
conversion lors de l'appel
La chaîne peut contenir des caractères Null. |
Conversion
automatique implicite de Byte vers Unicode si la fonction retourne une
chaîne.
La règle du Null char s'applique à la chaîne retournée, avec la même restriction d'emploi. |
Le type retour de la fonction ne peut pas être CPTR. |
Le
prototype et la déclaration des fonctions de l'API avec Visual dBASE
Revenons sur la fonction ShellExecute que nous avons abordé au chapitre Présentation des fonctions de l'API 32. Nous allons à présent prototyper, cet à dire déclarer cette fonction avant de l'utiliser pour expliciter de quelle façon Visual dBASE doit l'appeler dans un programme.
Voyons d'abord la syntaxe générale d'une déclaration de fonction externe. L'aide en ligne, concernant la rubrique “extern”, propose deux écritures possibles, mais elles peuvent se généraliser à la seconde expression :
Dans l'ordre, nous retrouvons :
Heureusement, le travail est en partie déjà effectué. Le répertoire _DBWINHOME\Include contient un certain nombre de fichiers prototypes, (fichiers portant l’extension .h), contenant l’ensemble des déclarations utilisées avec les fonctions de l’API 32.
Compilons alors le programme constitué de ces deux lignes de code : Une erreur se produit. Elle est due à une déclaration qui pose problème, HWND , figurant dans la fonction. En effet, HWND est un mot clé de Visual dBASE, d’où un conflit.
La meilleure solution est de remplacer la déclaration HWND par HANDLE, qui donne le bon résultat. Cela donne donc :
// Déclaration
du Prototype de la fonction ShellExecute
extern HINSTANCE ShellExecute(HANDLE, LPCSTR,
LPCSTR, LPCSTR, ;
LPCSTR, CINT) shell32 ;
from "ShellExecuteA"
Recompilons. Cette fois, c’est correct ; la fonction est déclarée, et prête à être employée.
Ce problème lié à HWND est le seul que j’ai rencontré à ce jour, tous les autres types des fonctions de win32API.prg que j'ai utilisé jusqu'à présent fonctionnent correctement.
Pour illustrer ce qui a été dit plus haut et concernant le mot clé from dans cette commande, remplacez la déclaration de la fonction par la suivante, qui élimine le mot clé from :
// Déclaration
du Prototype de la fonction ShellExecuteA, sans le mot clé from
extern HINSTANCE ShellExecuteA(HANDLE, LPCSTR,
LPCSTR, LPCSTR, ;
LPCSTR, CINT) shell32
Compilez : c'est OK, il faudra simplement utiliser la fonction en appelant ShellExecuteA(<Paramètres>)au lieu de shellExecute(<Paramètres>).
En résumé, l’étape délicate de la déclaration du prototype de la fonction API s’est donc limitée à
Considérons toujours la même fonction ShellExecute et reprenons la page du fichier d’aide correspondante. Intéressons nous à présent au paramètre nShowCmd. Ce paramètre, qui représente la façon dont la fenêtre du nouveau programme sera ouverte, peut prendre les différentes valeurs indiquées :
Le fichier comporte la section de déclarations
suivante :
. . .
//
// ShowWindow()
Commands
//
#define SW_HIDE
0
#define SW_SHOWNORMAL
1
#define SW_NORMAL
1
#define SW_SHOWMINIMIZED
2
#define SW_SHOWMAXIMIZED
3
#define SW_MAXIMIZE
3
#define SW_SHOWNOACTIVATE
4
#define SW_SHOW
5
#define SW_MINIMIZE
6
#define SW_SHOWMINNOACTIVE 7
#define SW_SHOWNA
8
#define SW_RESTORE
9
#define SW_SHOWDEFAULT
10
#define SW_MAX
10
. . .
Pour notre exemple, une seule ligne de code
en entête du fichier code source est donc nécessaire pour
déclarer l’ensemble de ces constantes :
// Inclure
le fichier Winuser.h
#include <Winuser.h>
Une alternative à l'utilisation des fichiers include pour la déclaration des fonctions et des constantes de l'API consisterait à déclarer directement celles-ci dans le code, au moyen des primitives #define et des types disponibles dans Visual dBASE. Cela est possible, mais plus fastidieux car il faut reprendre toutes les définition de la fonction et des constantes, d'où un risque d'erreur. Les fichiers include de Visual dBASE sont là pour nous servir.
Enfin, pour clore ce chapitre, les puristes
auront pu constater qu’à partir du moment où le fichier Winuser.hest
inclus, la déclaration d'inclusion du fichier Windef.h
devient superflue. En effet, le fichier Winuser.h.
effectue lui-même (pour vous en assurer, regardez les premières
lignes de ce fichier) l'inclusion du fichier Windef.h.
Dans notre cas, la seule inclusion du fichier Winuser.h
est donc suffisante pour déclarer à la fois les types et
les constantes utilisés par ShellExecute.
Exécution
d'une fonction de l'API 32
Voyons à présent comment exécuter une fonction de l'API. Nous allons lancer simplement la calculatrice Windows. Celle-ci se trouve dans le répertoire Windows par défaut, C:\Windows, le nom du fichier exécutable est : Calc.exe
Consultons de nouveau dans l'aide sur la fonction ShellExecute , la section détaillant le contenu des paramètres :
// Inclure
le fichier Winuser.h
#include <Winuser.h>
// Déclaration
du Prototype de la fonction ShellExecute
extern HINSTANCE ShellExecute(HANDLE, LPCSTR,
LPCSTR, LPCSTR, ;
LPCSTR, CINT) shell32 ;
from "ShellExecuteA"
ShellExecute( _app.FrameWin.hwnd, "open", "calc.exe", Null, "C:\Windows", SW_SHOWNORMAL )
Exécutez le programme. La calculatrice Windows s'affiche. Cet exemple a montré l'utilisation de paramètres de différents types, numériques, chaînes de caractères, constantes de l'API 32.
Il reste à présent
un type de paramètre dont nous avons seulement révélé
l'existence, il s'agit des structures C. Elles font l'objet de la fin de
cet article, car leur maniement nécessite d'avoir acquis les premières
notions de base développées jusqu'à présent.
Les
structures C et Visual dBASE
Si le C est resté longtemps une référence dans le monde du développement logiciel avant que les langages objets ne soient introduits, c'est sans doute en partie grâce à la puissance que lui confèrent les structures.
Afin d'illustrer les structures C, nous allons considérer à présent le cas de la fonction API 32 nommée GetVersionEx, fonction qui permet d'obtenir la version du système d'exploitation de l'ordinateur.
Recherchons d'abord l'aide sur cette fonction dans le fichier API :
Cette fonction utilise un seul paramètre dénommé lpVersionInformation, qui est un un pointeur C sur une structure dénommée OSVERSIONINFO. Cliquons sur ce lien OSVERSIONINFO indiqué dans le paramètre. Nous obtenons l'écran suivant :
Voyons à présent en détail les différentes indications portées en rouge :
Structure C | Classes et Objets |
La
structure C est une entité statique.
Il s'agit d'un ensemble de variables ou de pointeurs déclarés, de taille fixe. ils sont placés les uns à la suite des autres en mémoire, dans l'ordre dans lequel ils sont déclarés. Leur emplacement en mémoire ne change pas. L'espace mémoire occupé par une structure C est fixe, et correspond exactement à la somme des occupations mémoires des variables membres qui la constituent. |
Par
opposition, un objet est entièrement dynamique.
Il comprend des éléments (propriétés, méthodes) qui peuvent être modifiés, ajoutés, supprimés, etc... L'occupation mémoire des membres d'un objet n'est pas forcément contiguë, puisque une gestion dynamique de l'espace mémoire est effectuée. La taille d'un objet est variable, et dépend de son contenu à un instant donné. |
Une structure ne peut contenir que des variables ou des pointeurs. | Un objet peut contenir des propriétés (qui sont elles mêmes des variables ou des pointeurs) et des méthodes. |
Pour mieux se représenter d'une structure,
voici l'occupation mémoire de la structure C OSVERSIONINFO
:
Occupation mémoire : Total = 148 octets | Champ de la structure |
Offset : n à n + 3 | dwOSVersionInfoSize |
Offset : n + 4 à n + 7 | dwMajorVersion |
Offset : n + 8 à n + 11 | dwMinorVersion |
Offset : n + 12 à n + 15 | dwBuildNumber |
Offset : n + 16 à n + 19 | dwPlatformId |
Offset : n + 20 à n + 147 | szCSDVersion |
Structures et classes étant différentes par nature, il n'est pas possible d'utiliser directement la seconde pour simuler la première.
Manipuler le contenu d'une structure avec Visual dBASE nécessite l'accès à un bloc de mémoire, représentant le contenu de la structure (les différents membres), dans lequel on intervient directement au niveau des octets.
Fondamentalement, le seul mécanisme offert consiste à considérer le bloc de mémoire comme une chaîne de caractères Visual dBASE, puis, grâce aux méthodes setByte et getByte, à lire et modifier le contenu de la chaîne octet par octet. Même si cette méthode fonctionne, autant dire qu'elle est extrêmement ardue et lourde, et qu'il faut passer un temps certain avant d'arriver au bon résultat.
Heureusement, il existe une autre méthode bien plus efficace.
Même si dans Visual dBASE nous n'avons pas de structures, nous avons un outil beaucoup plus puissant que les structures C : ce sont les objets et les classes.
Nous allons à présent voir comment simuler le comportement d'une structure C, et parvenir, dans un langage de classes comme Visual dBASE, à remplacer les structures par des classes, et obtenir un maniement de ces dernières avec la même souplesse que les objets.
Parmi les outils et les exemples livrés avec Visual dBASE 7.01, figure un ensemble de fichiers qui vont permettre d'atteindre ce but. Les fichiers sont les suivants :
Voyons à présent sur un cas concret ce que cela donne. Nous allons appeler la fonction API 32 GetVersionEx , puis accéder aux membres de la structure OSVERSIONINFO.
Les lignes de code décrites ci-après ne figurent pas forcément dans le même ordre que celui dans lequel elles devraient être exécutées, mais cela aide à la compréhension et aux explications.
Tout d'abord voyons les fichiers Include.
Une rapide recherche sur les constantes et les types API utilisés
avec GetVersionEx
et OSVERSIONINFO
montre qu'il faut inclure les fichiers ci-après.
Le fichier StructAPI.h
doit de plus être inclus car nous utilisons la classe Structure :
// Fichiers Include nécessaires
#include <Windef.h>
#include <Winbase.h>
#include <StructAPI.h>
Ensuite, il faut charger la description de la classe Structure, qui est contenue dans le fichier _DBWINHOME\Samples\Structure.prg:
// Charge la classe Structure
set procedure to '&_dbwinhome.samples\structure.prg'
additive
A présent regardons comment déclarer la classe OSVERSIONINFO correspondant à la structure C. Celle-ci hérite de la classe Structure, définie dans le fichier _DBWINHOME\Samples\Structure.prg que nous venons de charger. Ensuite, la méthode addMember est utilisée pour déclarer les membres de la structure. Cette méthode utilise comme paramètres :
// Cette définition de classe correspond
à la définition de la structure C
// de type _OSVERSIONINFO. La fonction
addMember crée les membres de la structure,
// en utilisant le Type et le Nom du champ.
class _OSVERSIONINFO of Structure
super::addMember( TYPE_DWORD,
"dwOSVersionInfoSize" )
super::addMember( TYPE_DWORD,
"dwMajorVersion" )
super::addMember( TYPE_DWORD,
"dwMinorVersion" )
super::addMember( TYPE_DWORD,
"dwBuildNumber" )
super::addMember( TYPE_DWORD,
"dwPlatformId" )
super::addMember( TYPE_STRING,
"szCSDVersion", 128 )
// Cette ligne permet de renseigner le premier membre de la structure,
qui
// doit, comme précisé
dans l'aide API 32, contenir la taille de la structure.
// la méthode length()
de la classe Structure permet d'obtenir sa taille
// totale exprimée
en octets. Ainsi, lors de la création de l'instance d'objet
// à partir de la
classe _OSVERSIONINFO, ce membre sera automatiquement initialisé.
super::setMember( "dwOSVersionInfoSize",
this.length( ))
endclass
Vous aurez sans doute noté que la dernière ligne de la classe _OSVERSIONINFO appelle la méthode setMember. En effet, la page d'aide sur la structure OSVERSIONINFO indique que le membre dwOSVersionInfoSize doit contenir la taille de la structure. En invoquant la méthode length qui retourne la taille de la structure, ce membre sera renseigné automatiquement.
A présent, l'appel de la fonction GetVersionEx nécessitant un prototype, celui-ci peut être obtenu en recopiant les lignes correspondantes du fichier _DBWINHOME\Include\Win32api.prg :
// Prototype de la fonction GetVersionEx
tel qu'il est libellé dans Win32api.prg
extern BOOL
GetVersionEx( LPSTRUCTURE ) kernel32 ;
from "GetVersionExA"
Quelques variables locales sont utilisées,
notamment OSVERSIONINFO
qui contient l'objet créé à partir de la classe _OSVERSIONINFO
:
local OSVERSIONINFO, dwPlatformId
L'objet OSVERSIONINFO va être maintenant créé comme une instance de la classe _OSVERSIONINFO :
// Crée l'objet structure
OSVERSIONINFO = new _OSVERSIONINFO( )
Maintenant que l'objet structure OSVERSIONINFO est créé, la fonction GetVersionEx peut être appelée afin de renseigner le contenu de l'objet.
NOTEZ que c'est la propriété .value qui est passée comme paramètre à l'appel de la fonction, puisque c'est cette chaîne de caractères qui représente le bloc de mémoire dans lequel les membres de la structure C sont stockés :
// Appelle la fonction GetVersionEx en
passant le paramètre OSVERSIONINFO.value,
// qui repéresente le contenu de
la structure en mémoire
GetVersionEx( OSVERSIONINFO.value )
Le reste du code permet d'afficher les valeurs des membres qui viennent d'être renseignés par GetVersionEx, grâce à la méthode getMember.
Une macro commande, dénommée LOWORD, et déclarée dans le fichier Windef.h, permet de récupérer uniquement le mot 16 bits de poids faible d'un mot de 32 bits. Son équivalent HIWORD pour les 16 bits de poids fort existe également. Vous pouvez consulter cet endroit du fichier Windef.h, il contient des macros utiles pour séparer ou concatener des mots binaires.
// Affiche le contenu des membres de la
structure
? 'Major Version', OSVERSIONINFO.getMember(
'dwMajorVersion' )
? 'Minor Version', OSVERSIONINFO.getMember(
'dwMinorVersion' )
? 'Build Number', LOWORD( OSVERSIONINFO.getMember(
'dwBuildNumber' ))
dwPlatformId = OSVERSIONINFO.getMember( 'dwPlatformId'
)
do case
case dwPlatformId == VER_PLATFORM_WIN32s
? 'Win32s on Win 3.1'
case dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
? 'Win32 on Windows 95'
case dwPlatformId == VER_PLATFORM_WIN32_NT
? 'Win32 on Windows NT'
endcase
Le programme Visual dBASE complet et correspondant
à cet exemple peut être chargé par le lien en bas de
page. Exécutez le. Dans la fenêtre de commande Visual dBASE
s'affiche le numéro de version de Windows, l'indice de génération,
ainsi que la version du système d'exploitation.
Création
d'un exécutable utilisant les fichiers de structure
Il est tout à fait possible d'utiliser la méthode décrite dans le chapitre précédent dans un programme exécutable généré avec Visual dBASE, à condition de suivre les indications suivantes :
Bien qu'elle constitue un excellent point de départ, la classe Structure de Structure.prg souffre de quelques petites lacunes, qui brident dans certains cas son champ d'application.
Pour cette raison, j'ai créé ma propre classe StructureEx, compatible de la classe Structure, et améliorée des points figurant ci-dessous. Cette classe peut remplacer la classe Structure.
Voici en quelques points les amélioration apportées :
En fin de compte, utiliser les appels directs à l'API 32 de Windows depuis Visual dBASE 7.01 n'est pas une tâche aussi ardue, dès lors que l'on s'y prend de façon rationnelle. Il ne s'agit pas là d'une présentation exhaustive du sujet, mais d'une première approche simple pour pouvoir démarrer. Bien entendu, d'autres méthodes sont possibles, chacun est libre d'utiliser sa technique personnelle, mais j'ai pensé que cette démarche, et les quelques notions de langage C auxquelles elle fait appel, méritaient d'être présentées compte tenu de leur simplicité de mise en oeuvre.
Visual dBASE montre une fois de plus que, grâce à son approche objet, il permet de s'adapter à un type de situation pour lequel il n'a pas forcément été prévu.
Il n'en reste pas moins que cette API Windows demeure parfois d'un abord délicat compte tenu de certaines contraintes dues à sa conception initiale.
Maintenant, à vous de jouer !
Nicolas Martin