Le premier site francophone dédié au développement Pocket PC


Accéder à distance à votre Pocket depuis votre navigateur Web
 
   


Introduction

Dans cet article, nous allons exploiter le serveur web de Windows CE pour intéragir avec votre Pocket PC.

La première question qui vient à l'esprit, quand on entend parler de l'existence d'un serveur web pour Windows CE, est : " Quel est l'intérêt d'avoir un serveur web sur un appareil CE qui est généralement limité en terme de puissance (CPU mémoire ...) ?

Voici quelques arguments en faveur de l'utilisation d'un serveur web sous Windows CE.

Un serveur web proposant du contenu dynamique est un bon intermédiaire pour effectuer de l'accès à distance à des informations détenues par un appareil CE.

Si votre appareil CE ne possède pas d'écran (systême embarqué par exemple), le serveur web vous permet de déporter l'affichage sur un PC au travers d'un navigateur.

Un affichage HTML est indépendant du client. On n'a pas par exemple à se soucier de la résolution de l'affichage, c'est le navigateur qui va prendre en charge l'affichage de la page en fonction des capacités de l'appareil. D'un certain point de vue, un serveur web pourrait vous permettre de développer un applicatif dont l'interface graphique s'adapte au client.

Vous l'aurez compris, un serveur web pour Windows CE présente un intérêt certain.

Installation du serveur Web sur votre appareil Windows CE.

Vous trouverez le fichier d'installation du serveur web, dans le répertoire support du SDK de Pocket PC 20002. Sur ma machine, le répertoire est le suivant : c:\windows ce tools\pocket pc 2002\support\HTTPServer. Vous y trouverez le fichier HTTPServer.PPC2002ARM.CAB.

Pour l'installer, suivez cette procédure :

Copiez le fichier .CAB manuellement dans un répertoire de votre pocket
Sur votre Pocket, lancez l'explorateur de fichier et cliquez sur le fichier .CAB
Lorsque l'installation est terminée, exécutez un reset de l'appareil
Le serveur web sera automatiquement activé au démarrage de l'appareil.

Afin de vérifier son bon fonctionnement, démarrez Pocket Internet Explorer et naviguez à l'adresse suivante : http://localhost/ Si tout s'est bien passé, vous devriez voir un message du style : " the server is correctly installed and running "

Configuration du serveur Web

Le but du présent article n'est pas de vous expliquer en détail la procédure de configuration du serveur web. Je vous conseille de jetter un oeil dans la documentation du MSDN en effectuant une recherche sur le mot-clé " HTTPD ".

Sur votre Pocket PC, vous devriez maintenant avoir un répertoire " \windows\www\wwwPub ". Ce répertoire est le répertoire raçine du serveur web. Pour faire simple, vous installerez le code de cet article dans ce répertoire.

La technologie ISAPI

ISAPI est l'acronyme de Internet Server Application Programming Interface. Le but de ISAPI est de permettre d'augmenter les fonctionnalités du serveur web au moyen de DLLs d'extension. Il existe deux types de DLL ISAPI : les filtres ISAPI et les extensions ISAPI. Celles qui nous intéressent ici sont les DLLs d'extension. Une DLL d'extension ISAPI est une DLL qui peut être appellée directement au travers d'une URL. Par exemple, si je possède une DLL d'extension appellée " webext.dll " et que je l'ai installé dans le répertoire racine du serveur web. Je vais pouvoir l'appeller simplement, à partir de Pocket Internet Explorer, en naviguant à l'URL suivante : http://localhost/webext.dll

Je pourrais même lui passer des informations, un peu à la manière des paramètres d'une ligne de commande.

Exemple : http://localhost/webext.dll?username= ldo ;e-mail=ldocquir@hotmail.com

Un peu de pratique: Web Process Killer (webpkill.dll)

L'exemple que j'ai choisi pour illustrer mon article est une dll qui va vous permettre de lister les processus actifs de votre pocket et de les tuer si le coeur vous en dit. Je vous met en garde directement : vous pourrez tuer n'importe quelle tâche y compris les tâches système, ce qui pourrait rendre le système instable. Pas de panique cependant, un soft reset remttra tout en ordre.

Pour tester cette application web, vous pourrez soit utiliser le Pocket Internet Explorer local ou prendre la main à distance à partir de IE sur votre PC.

Architecture de l'application webpkill

Analyse du flux d'information en prenant le point de vue du serveur web.

- Il reçoit la requête d'un navigateur internet (Pocket IE, IE, Netscape ou autre).

- Si l'URL fait référence à webpkill.dll, il transmet la requête à la webpkill.dll

- Webpkill analyse les paramètres de l'URL et exécute la tâche correspondante. Evidemment la tâche en question devra générer et renvoyer une page HTML au navigateur à l'origine de la requête.

- Le navigateur affiche la page HTML. La boucle est bouclée.

Les fonctionnalités offertes par webpkill.

Webpkill propose deux services : le premier permet de lister les processus actifs tandis que le second permet d'arrêter le processus de votre choix.

Chacune de ces tâches doit être activée au travers d'une URL particulière. J'ai donc défini deux paramètres d'URL :
- ?list déclenchera la tâche liste des processus
- ?kill=process_id déclenchera l'arrêt du processus dont l'identifiant est 'process_id'

Ainsi donc l'URL http://localhost/webpkill?list vous permettra d'afficher la liste des processus actifs dans Pocket IE.

Ossature d'une DLL d'extension ISAPI

Une dll d'extension ISAPI est très simple d'un point de vue structurelle : elle exporte deux fonctions dont une seule est réellement intéressante.

La première fonction à implémenter est GetExtensionVersion. Elle permet au serveur de connaître la version ISAPI de votre DLL. Ci-dessous une implémentation typique de GetExtensionVersion :

BOOL WINAPI GetExtensionVersion (HSE_VERSION_INFO *pVer)
{
  pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
  strcpy(pVer->lpszExtensionDesc,"HTTP Web Process Killer Application");
  return TRUE;
}

La seconde fonction exportée est HttpExtensionProc. Elle constitue le principal point d'entrée pour le serveur web : toutes les requêtes HTTP destinées à votre extension donneront lieu à un appel à cette fonction. L'unique paramètre, un pointeur sur une structure EXTENSION_CONTROL_BLOCK, vous livre l'ensemble des informations.

Voici la définition de cette structure telle qu'elle apparaît dans httpext.h :

//
// structure passed to extension procedure on a new request
//
typedef struct _EXTENSION_CONTROL_BLOCK {

DWORD cbSize; // size of this struct.
DWORD dwVersion; // version info of this spec
HCONN ConnID; // Context number not to be modified!
DWORD dwHttpStatusCode; // HTTP Status code
CHAR lpszLogData[HSE_LOG_BUFFER_LEN];// null terminated log info specific to this Extension DLL

LPSTR lpszMethod; // REQUEST_METHOD
LPSTR lpszQueryString; // QUERY_STRING
LPSTR lpszPathInfo; // PATH_INFO
LPSTR lpszPathTranslated; // PATH_TRANSLATED

DWORD cbTotalBytes; // Total bytes indicated from client
DWORD cbAvailable; // Available number of bytes
LPBYTE lpbData; // pointer to cbAvailable bytes

LPSTR lpszContentType; // Content type of client data

BOOL (WINAPI * GetServerVariable) ( HCONN hConn,
LPSTR lpszVariableName,
LPVOID lpvBuffer,
LPDWORD lpdwSize );

BOOL (WINAPI * WriteClient) ( HCONN ConnID,
LPVOID Buffer,
LPDWORD lpdwBytes,
DWORD dwReserved );

BOOL (WINAPI * ReadClient) ( HCONN ConnID,
LPVOID lpvBuffer,
LPDWORD lpdwSize );

BOOL (WINAPI * ServerSupportFunction)( HCONN hConn,
DWORD dwHSERequest,
LPVOID lpvBuffer,
LPDWORD lpdwSize,
LPDWORD lpdwDataType );

} EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK;

De cette structure, nous allons utiliser principalement 4 membres :

- ConnId est l'identifiant de la connexion du client. Cette valeur sera utilisée dans la plupart des appels ISAPI.

- lpszQueryString qui pointe sur une chaîne de caractères contenant les paramètres de l'URL.

- ServerSupportFunction est un pointeur sur une function qui vous permet d'activer des services du serveur web

- WriteClient est un pointeur sur une fonction qui vous permet de renvoyer des informations au navigateur à l'origine de la requête.

Cette structure contient d'autres informations et fonctions intéressantes. Je vous renvoie vers la documentation ISAPI pour plus de détails.

Déterminer le service demandé par le client.

Les fonctions SendProcessList et KillProcess sont déclenchées par des paramètres de l'URL. Pour déterminer laquelle des deux fonctions il faut appeller, il suffit d'analyser la chaîne des paramètres de l'URL. Cette dernière est pointée par la variable membre lpszQueryString de la structure EXTENSION_CONTROL_BLOCK.

Char szFunction[5];               
strncpy(szFunction,pECB->lpszQueryString,4);
szFunction[4] = 0;
if (_stricmp(szFunction,"list") == 0)
  {
     SendProcessList(pECB);
  }
 else if (_stricmp(szFunction,"kill") == 0)
  {
     KillProcess(pECB);
  }
 else
  {
     SendDefaultResponse(pECB);
  }

Renvoyer une page au client

Il incombe à une DLL ISAPI de renvoyer une réponse HTTP au client. Par réponse HTTP, j'entends non seulement le contenu de la page HTML mais aussi les informations de protocole HTTP (le HTTP Header).

Renvoyer un header HTTP

Rassurez-vous, il n'est pas nécessaire de connaître le protocole HTTP à fond pour s'en sortir. En effet, le serveur web vous fournit une fonction qui génère un HTTP header standard. Un pointeur sur cette fonction est fourni par le membre ServerSupportFunction de la structure EXTENSION_CONTROL_BLOCK.

Le premier paramètre à passer est l'identifiant de connexion (ConnId).

ServerSupportFunction offre un certain nombre de services. A chacun de ces services est associé une constante. Cette constante est passée en second paramètre de l'appel. Dans le cas présent, on utilisera la constante HSE_REQ_SEND_RESPONSE_HEADER pour demander au serveur web de renvoyer un header HTTP standard.

Le troisième paramètre " 200 OK " donne le return code HTTP que vous désirez associer à la requête. 200 OK signifie que la requête est valable et qu'une réponse sera renvoyée. Il existe bien évidemment d'autres return code HTTP qui sont documentés dans la spec du protocole HTTP.

Voici un exemple d'utilisation de ServerSupportFunction :

pECB -> ServerSupportFunction(
  pECB -> ConnID, // id de la connexion
  HSE_REQ_SEND_RESPONSE_HEADER, // générer header
  "200 OK", // code http ok
  &dwLen, 
  (LPDWORD) NULL); // pas de paramètres HTTP que je désire ajouter

Renvoyer le contenu de la page HTML

Pour envoyer le contenu de la page HTML, il faut utiliser une autre fonction de la structure EXTENSION_CONTROL_BLOCK : WriteClient. WriteClient peut être appellée à plusieurs reprises pour envoyer le contenu blocs par blocs.

Voici un exemple d'utilisation de WriteClient

char szBuff[MAX_PAGE_SIZE];
DWORD dwLen;

sprintf(szBuff, "<br><font size=1 color=blue face=\"verdana\">Laurent Docquir</font><br><font size=1 color=red face=\"verdana\">EZOS 2003<br></font></body></html>");

dwLen = strlen ( szBuff );
pECB -> WriteClient (pECB -> ConnID, szBuff, &dwLen, 0);

Dresser une liste des processus avec Toolhelp.

Sous Windows CE il existe un API particulier pour obtenir des informations diverses sur les processus : il s'agit de l'API ToolHelp.

La première opération consiste à sauvegarder une " photo instantanée " du contexte d'exécution de Windows CE. La fonction CreateToolhelp32Snapshot est prévue à cet effet. Elle renvoie un handle sur un snapshot.

La seconde opération consiste à boucler dans cette prise de vue (snapshot) pour en retirer la liste des processus actifs. La fonction Process32First sert à initier la boucle, Process32Next permet de sauter au processus suivant.

Voici le code de la fonction SendProcessList :

char szBuff[MAX_PAGE_SIZE];
DWORD dwLen;
HANDLE hSnap;
PROCESSENTRY32 pe;
BOOL fOk;
char *szServerName = NULL; 
char *szUrl = NULL;
char *szTemp;               
szServerName = GetServerVariable(pECB,"SERVER_NAME");
  szUrl = GetServerVariable(pECB,"URL");
  szTemp = GetLocalIPAddress();
 // Envoi de l'entête de page
 sprintf(szBuff, "<html><title>Web Process Killer 
  par Laurent Docquir (EZOS)</title><body><h1><u>Liste des processus 
  tournant sur %s</u></h1><table border=1>",szServerName); 
 dwLen = strlen(szBuff);
 pECB ->WriteClient(pECB -> ConnID, szBuff, &dwLen, 0);
 // Envoi de la liste des process
 hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
 pe.dwSize = sizeof(PROCESSENTRY32);
 fOk = Process32First(hSnap,&pe);
 while(fOk)
  {
   sprintf(szBuff, "<tr><td><a href=\"http://%s%s?kill=%d\">%S</a></td></tr>", 
     szServerName, 
     szUrl, 
     pe.th32ProcessID, 
     pe.szExeFile);
   dwLen = strlen ( szBuff );
   pECB -> WriteClient (pECB -> ConnID, szBuff, &dwLen, 0);
   pe.dwSize = sizeof(PROCESSENTRY32);
   fOk = Process32Next(hSnap,&pe);
  }
 sprintf ( szBuff, "</table><br>");
 dwLen = strlen ( szBuff );
 pECB -> WriteClient (pECB -> ConnID, szBuff, &dwLen, 0);
 // Nettoyage des resources
 CloseToolhelp32Snapshot(hSnap);
 if (szServerName)
  free(szServerName);
 if (szUrl)
  free(szUrl);

Conclusion

Sous Windows CE, la technologie ISAPI vous permet d'exposer du code C au travers du serveur web. Les intérêts sont multiples :

Tout d'abord, la DLL ISAPI est encore assez simple à écrire. Sa structure n'est pas si complexe pour qui veut bien s'y intéresser.

Il n'y a rien à coder au niveau de l'application client puisque le client est un navigateur.

ISAPI est tout indiqué si vous désirez exécuter une application graphique sur un appareil qui ne possède pas d'écran. Dans ce cas, votre application WCE est la DLL ISAPI et votre client est un navigateur tournant sur une autre machine.

ISAPI permet de développer du code dont l'interface graphique s'adapte au possibilité du navigateur du client.

Le code exemple de cet article peut servir comme une modeste base de départ pour une application plus conséquente. Vous vous rendrez néanmoins très vite compte que le contenu de ce document ne vous montre que la partie visible de l'iceberg.

Sources de cet article (16 ko)


Laurent Docquir

 
       
   
 
   
Copyright 2001-2004 - Tous droits réservés
 
   

iPAQ est un produit de COMPAQ.
Visual Tools est un produit de Microsoft Corporation.
Toutes les autres marques et produits présents dans ces pages sont la propriété exclusive de leurs sociétés respectives.