FAQ VC++ et MFCConsultez toutes les FAQ
Nombre d'auteurs : 20, nombre de questions : 545, dernière mise à jour : 5 avril 2013 Ajouter une question
Cette faq a été réalisée pour répondre aux questions les plus fréquement posées sur le forum Développement Visual C++
Je tiens à souligner que cette faq ne garantit en aucun cas que les informations qu'elle contient sont correctes ; Les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou si vous souhaitez devenir redacteur, lisez ceci.
Sur ce, je vous souhaite une bonne lecture. Farscape
- Comment renvoyer du binaire dans un flux http depuis une DLL d'extension server (IIS) ISAPI ?
- Comment renvoyer une ressource binaire dans un flux http depuis une DLL d'extension server (IIS) ISAPI ?
- Comment traduire une requête envoyée en séquence Escape dans une DLL d'extension server (IIS) ISAPI ?
- Comment utiliser ADO dans une DLL d'extension server (IIS) ISAPI ?
- Comment ajouter une fonction appelable par http dans une DLL d'extension server ISAPI ?
- Comment récupérer l'adresse IP (et autres infos) du poste client qui fait une requête HTTP sur ma DLL Extension ISAPI ?
- Comment redéfinir la fonction par défaut d'une DLL ISAPI ?
- Comment Débugger une DLL ISAPI ?
En définissant l'opérateur de flux pour un BYTE dans une classe:
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // BinaryHtmlStream.h: interface for the CBinaryHtmlStream class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_BINARYHTMLSTREAM_H__E8E5B559_A8D3_4DEE_B38D_2ABF4D319672__INCLUDED_) #define AFX_BINARYHTMLSTREAM_H__E8E5B559_A8D3_4DEE_B38D_2ABF4D319672__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 class CBinaryHtmlStream : public CHtmlStream { public: // we have a special overload of << to allow for a single byte CBinaryHtmlStream& operator<<(BYTE b) { Write(&b, 1); return *this; } }; #endif // !defined BINHTMSTREAM_H |
En utilisant la classe CBinaryHtmlStream ci-dessus :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | //******************************************************************* // Renvoi une resource du workspace //******************************************************************* void ClsMyServerExtension::SendResource(CHttpServerContext *pCtxt, int ID_RS) { CBinaryHtmlStream* pStream = new CBinaryHtmlStream(); CString ContentSize; CString RSNumb; unsigned int Size = 0; HINSTANCE hIn = NULL; HRSRC tSrc = NULL; HGLOBAL hImage = NULL; BYTE* pImage = NULL; //Attention ajouter le type mime du flux de retour en fonction du type de Resource A modifier AddHeader(pCtxt ,_T("Content-Type: image/jpeg\r\n")); //AddHeader(pCtxt ,_T("Content-Type: application/x-shockwave-flash\r\n"));} RSNumb.Format("#%d",ID_RS); hIn= AfxGetResourceHandle(); //Où BINARY est un groupe de resource comme Dialog, Menu... tSrc = ::FindResource (hIn,RSNumb.GetBuffer(0),"BINARY"); hImage = ::LoadResource(hIn,tSrc); Size = ::SizeofResource(hIn,tSrc); pImage = (BYTE*) ::LockResource(hImage); ContentSize.Format( "Content-length: %d\r\n", Size); AddHeader( pCtxt, _T(ContentSize)); for (int Ind = 0; Ind <Size; Ind++){ *pStream << pImage[Ind]; } *pCtxt << *pStream; delete pStream; //delete pImage; Supprimé à la destruction du Thread(Voire MSDN) } |
La séquence Escape c'est une forme de codage des caractères non alpha-numérique du style "-1" en Séquence Escape sera "%2D1". En gros c'est % + code Hexa du car.
Le problème c'est que si Dans une DLL extension ISAPI vous définissez une fonction comme suite :
Code c++ : | Sélectionner tout |
1 2 3 | ON_PARSE_COMMAND(Reload, ClsMyServerExtension, ITS_PSTR ITS_R4 ) ON_PARSE_COMMAND_PARAMS("String=Str Double=-1.54") |
Vous recevrez dans la DLL comme valeur de Double 25.00 et non -25.12
Pou corriger ce bug de IIS :
Code c++ : | Sélectionner tout |
1 2 3 | ON_PARSE_COMMAND(Reload, ClsMyServerExtension, ITS_PSTR ITS_PSTR ) ON_PARSE_COMMAND_PARAMS("String=Str Double=-1.54") |
L'environnement IIS (ou 2IS) est MultiThread à savoir que chaque requête Http est parsée puis exécutée sur un thread (Attention aux variables globales de la classe car tous les thread vont y accéder).
Ainsi si vous voulez utiliser ADO dans une DLL ISAP il faut effectuer le CoInitialize et CoUninitialize dans chaque Function appelable par IIS :
Imaginons que vous ayez deux fonctions appelables depuis une requête http
Code C++ : | Sélectionner tout |
1 2 3 4 5 | ON_PARSE_COMMAND(GetRaster, ClsMyServerExtension, ITS_PSTR ) ON_PARSE_COMMAND_PARAMS("D=DataBase") ON_PARSE_COMMAND(Reload, ClsMyServerExtension, ITS_PSTR) ON_PARSE_COMMAND_PARAMS("R=r") |
Il faudra faire dans chacune des fonctions qui utilisent ADO :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | //******************************************************************* // Recharge la config //******************************************************************* void ClsMyServerExtension::Reload(CHttpServerContext *pCtxt, LPTSTR R) { HRESULT hres = ::CoInitializeEx(NULL,COINIT_MULTITHREADED ); ... //traitement plus renvoi de texte ou dat dans le flux... ::CoUninitialize(); } |
Pour utiliser le Flag COINIT_MULTITHREADED il faut définir dans le .h de votre extension serveur .
Code C++ : | Sélectionner tout |
1 2 | #define _WIN32_DCOM #include "objbase.h" |
Remarque : vous pouvez mettre simplement ::CoInitialize(NULL) mais si vous avez des retours de HTML avec un code du genre -2147417842 (0x8001010e) vous devrez utiliser le flag COINIT_MULTITHREADED.
Cela peut paraître trivial comme question, mais c'est pas forcément clair lorsque l'on fait un nouveau workspace en choisissant ISAPI extension Server.
En fait on peut avoir si l'on veut deux types de fonctions :
Les fonctions points d'entrée HTTP et les autres à savoir celles qui vont servir aux fonctions points d'entrée.
Pour la clarté il paraît plus simple de faire une ou plusieurs classes qui réalisent les traitement désirés sur les appels et laisser dans la classe générée par Visual Studio que les fonctions point d'entrées...
Après chacun fait comme il veut...
Donc, pour faire une fonction point d'entrée HTTP il faut faire comme suit :
Ajouter une fonction classiquement mais en mettant toujours comme premier paramètre un pointeur sur un CHttpServerContext :
dans le .h
Code c++ : | Sélectionner tout |
1 2 | void GetData(CHttpServerContext *pCtxt, int Integer, LPTSTR String) |
Code c++ : | Sélectionner tout |
1 2 3 4 5 | void CMyServerExtension::GetData(CHttpServerContext *pCtxt, int Integer, LPTSTR String) { ... } |
Code c++ : | Sélectionner tout |
BEGIN_PARSE_MAP(ClsMyServerExtension, CHttpServer)
Si vous n'ajoutez pas votre fonction ici vous ne pourrez jamais l'appeller sur une requette HTTP.
Dans notre cas il faut ajouter :
Code c++ : | Sélectionner tout |
1 2 3 | ON_PARSE_COMMAND(GetData, ClsMyServerExtension, ITS_I4 ITS_PSTR) ON_PARSE_COMMAND_PARAMS("Integer=12 String=MaString") |
Remarque :
Les types définissables pour le Parse_Command sont :
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | //pour les fonctions sans paramètres: #define ITS_EMPTY "\x06" // no parameters //les autres types #define ITS_I2 "\x01" // a 'short' #define ITS_I4 "\x02" // a 'long' #define ITS_R4 "\x03" // a 'float' #define ITS_R8 "\x04" // a 'double' #define ITS_PSTR "\x05" // a 'LPCTSTR' #define ITS_RAW "\x07" // exactly as received |
C'est simple dans la fonction en utilisant le CHttpServerContext :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 | unsigned longSize = 250; LPTSTR ClientIP = (LPTSTR) malloc(Size); pCtxt->GetServerVariable("REMOTE_ADDR", ClientIP, &Size); CStringIpClient = CString(ClientIP, Size); free(ClientIP); |
Les autres paramètres sont (CF MSDN):
Value | Meaning |
---|---|
AUTH_TYPE | Contains the type of authentication used. If the string is empty, then no authentication is used. |
CONTENT_LENGTH | The number of bytes which the script can expect to receive from the client. |
CONTENT_TYPE | The content type of the information supplied in the body of a POST request. |
GATEWAY_INTERFACE | The revision of the CGI specification to which this server complies. The current version is CGI/1.1. |
PATH_INFO | Additional path information, as given by the client. This comprises the trailing part of the URL after the extension DLL (script) name but before the query string (if any). |
PATH_TRANSLATED | This is the value of PATH_INFO, but with any virtual path name expanded into a directory specification. |
QUERY_STRING | The information which follows the ? in the URL which referenced this extension DLL. |
REMOTE_ADDR | The IP address of the client. |
REMOTE_HOST | The hostname of the client. |
REMOTE_USER | This contains the username supplied by the client and authenticated by the server. |
REQUEST_METHOD | The HTTP request method. |
SCRIPT_NAME | The name of the extension DLL that is being executed. |
SERVER_NAME | The server's hostname (or IP address) as it should appear in self-referencing URLs. |
SERVER_PORT | The TCP/IP port on which the request was received. |
SERVER_PROTOCOL | The name and version of the information retrieval protocol relating to this request. Normally HTTP/1.0. |
SERVER_SOFTWARE | The name and version of the web server under which the ISA or server extension DLL program is running. |
ALL_HTTP | All HTTP headers that were not already parsed into one of the above variables. |
HTTP_ACCEPT : Special case HTTP header. Values of the Accept: fields are concatenated, separated by ", ".
For example, if the following lines are part of the HTTP header:
Code : | Sélectionner tout |
1 2 3 | accept: */*; q=0.1 accept: text/html accept: image/jpeg |
Code : | Sélectionner tout |
*/*; q=0.1, text/html, image/jpeg
Attention ceci peut poser des problèmes car sur des requêtes HTTP en Post le client appelle la DLL dans un premier temps et n'envoie les paramètres que dans un second temps , ce qui à pour conséquence de déclencher la fonction par défaut (Constaté avec IE6, j'ai pas d'autre infos sur les autres Browsers).
La fonction par défaut est la fonction appelée quand on tape un requête du type sans paramètres :
Sinon ça se passe dans la section BEGIN_PARSE_MAP, il suffit juste de rempacer le nom de la fonction qui va être appelée par défaut :
Code c++ : | Sélectionner tout |
1 2 3 | ON_PARSE_COMMAND(MaFonctionParDefaut, ClsMyServerExtension, ITS_EMPTY) DEFAULT_PARSE_COMMAND(MaFonctionParDefaut, ClsMyServerExtension) |
Adapté à VC++ depuis : Débogage de DLL ISAPI
Merci à Sylvain James pour les copies d'écran…
C'est assez compliqué et tordu mais c'est possible :
il vous faut le server IIS, et le service de composant COM et COM+
Première chose il ne faut pas avoir XP Home ou alors allez regarder ce lien : Installer IIS sous Windows XP Familial car il n'y a pas le serveur IIS sous XP home édition.
Pour savoir si vous avez IIS installé faite bouton droit "gérer" puis dans "services et applications" vous devez avoir "services Internet (IIS)"
Première étape :
Installer IIS si nécessaire.
dans votre site Web par défaut, créer un répertoire virtuel (Appelons-le DLL) en cochant bien à la fin "Exécuter (par exemple, CGI ou application ISAPI)".
Ensuite clic droit "Propriétés" sur le dossier crée.
Dans "Protection d'application" choisir "élevée (Isolée)"
Deuxième étape : Il faut maintenant ouvrir la gestion des services COM et COM+ :
(je vous conseille de faire un raccourci)
sous XP : "C:\WINDOWS\system32\Com\comexp.msc"
Dans "Services de composants"->"Ordinateurs"->"Poste de travail"->"Applications COM+"
vous devez avoirs plusieurs process dont quelques uns commençant par IIS dont un notamment portant le nom de votre répertoire virtuel. Sur ce dernier Clic droit "Propriétés".
Dans l'onglet "Général" vous avez en bas "ID de L'application :"
suivi du CLSID de votre répertoire Virtuel sélectionnez-le et copiez-le . (Cela ce présente sous la forme : {BFC384AE-C057-4C64-8A04-3FC3EBEB00AD}).
Ensuite dans l'onglet "Identité" vérifiez que "Compte Système" soit bien coché (utilisateur actuellement connecté).
Vous pouvez maintenant fermer le gestionnaire des services COM+.
Troisième et dernière étape :
Ouvrez votre projet dans Visual Studio.
Dans le Menu "Project"->"Settings" (ou ALt+F7)
Dans l'onglet "Debug" :
Dans l'Edit "Executable for debug session" mettre :
(sous XP, pour 2000 c'est C:\WINNT\...)
"C:\WINDOWS\system32\dllhost.exe"
Dans "Working directory" mettez le dossier physique sur lequel pointe votre dossier virtuel.
par exemple "C:\www\MonSite\Binary\DLL\"
Ensuite dans "Program Argument" mettez le CLSID que vous avez copié du gestionnaire de service COM+ comme suit :
"/ProcessID:{BFC384AE-C057-4C64-8A04-3FC3EBEB00AD}"
Enfin (C'est bientôt fini) dans l'onglet "Link" linkez votre exe dans le répertoire physique correspondant au répertoire virtuel :
"C:\www\MonSite\Binary\DLL\MyExtension.dll"
Fermer et faites "File"->"Save Workspace", ça serai bête de paumer les modifications.
Vous Pouvez maintenant lancer la version debug, mettez un point d'arrêt dans la fonction "Default", puis dans votre Browser tapez :
"http://localhost/DLL/MyExtension.dll?" et validez.
Remarque d'usage :
Si vous changez la protection d'application de votre répertoire virtuel, il faudra remettre dans le gestionnaire de services COM+ le compte Système.
Si vous voulez recompiler votre DLL suite à une modification, il vous faudra décharger la DLL de la mémoire afin de pouvoir réécrire sur la DLL sinon vous aurez un message du style "unable to link write error".
Pour décharger la DLL clic droit sur le répertoire virtuel "Propriétés" et il y a un bouton décharger.
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.