Accueil > > > [C++] [WIN32 API] ADO POUR LES NOUVEAUX
[C++] [WIN32 API] ADO POUR LES NOUVEAUX
Information sur la source
Description
Source
- ADO ET WIN32 API
- Un tutorial pour les nouveaux
- Introduction
- Dans ce petit tutorial je vais essayer de vous apprendre à utiliser le ADO pour faire des applications de base de données avec le API win32 et c++.
- Je dois vous dire qu'avec le MFC c'est cent fois plus facile mais pour ceux qui veulent tout le pouvoir en main je recommande l'api.
- J'écris cette article parce que j'ai eu quelques difficultés quand j'avais commencé a apprendre l'ado... il y a des petits trucs très important et c'est même pas documenté sur le Web (enfin je n'ai pas trouvé).
- J'utilise visual c++ mais vous pouvez facilement le convertir pour d'autres environnements de développement.
-
- Entrer dans le monde d'ADO
- On va faire pas à pas une application avec ado... par exemple une application de gestion de bibliothèque (très simple).
-
- Début
- Projet: Appelez votre projet ?biblo?. Créez dans votre projet un fichier appelé ?main.cpp?. Créez votre fichier de ressource et dans votre fichier de ressource créez un dialogue appelé ?IDD_MAIN?.
- Base de donnée: Créez un fichier appelée ?biblo.mdb? avec Access et mettez le dans C:\ .
- Dans ce fichier ajoutez une tableau appelée ?INFOUTI? (informations sur l?utilisateur qui prends des livres) et dans ce tableau mettez les clés ?NUMEROUTI? (numéro qu?on donne a l?utilisateur) et ?NOMUTI? (nom de l?utilisateur).
- Dans votre fichier ajoutez une autre tableau appelée ?INFOLIVRE? (informations sur les livres) et dans ce tableau ?NUMEROLIVRE? (numéro du livre), ?NOMLIVRE? (nom du livre) et ?VAL? (on va l?utiliser pour savoir si le livre est pris ou pas...).
- (N?oubliez pas d?écrire des valeurs bidon dans vos tableaux pour qu?on puisse les utiliser)
- (Toutes les clés doivent être des clés texte, pas nombre ou autre chose)
- -------------------------------------
- Dans le fichier "main.cpp" mettez ça au début de votre fichier et aussi n'oubliez pas de linker comctl32.lib.
-
- [Code]
- //les includes que vous avez besoin pour le projet
- #include <windows.h>
- #include <icrsint.h>
- #include <iostream.h>
- #include <string>
- #include <sstream>
- #include <commctrl.h>
- #include "resource.h"
-
- //pour std
- using std::string;
-
- //sans ça vous ne pouvez pas travailler avec ado sous win32 alors c'est important
- //ici on importe le dll ado. Si le dll d'ado est ailleurs alors changez l'adresse
- //et on aussi renomme EOF et BOF pour des raisons de comptabilités
- #import "c:\Program Files\Fichiers Communs\System\ADO\msado15.dll" \
- no_namespace rename("EOF", "EndOfFile") no_namespace rename("BOF", "BeginOfFile")
-
- #define CREATEiNSTANCE(sp,riid) { HRESULT _hr =sp .CreateInstance( __uuidof( riid ) ); \
- if (FAILED(_hr)) _com_issue_error(_hr); }
-
- //variables q'on va utiliser avec ado
- _RecordsetPtr pSet = NULL; // pointeur pour le recordset
- _ConnectionPtr pDb = NULL; //pointeur pour la base de donnee
- _variant_t vRecsAffected(0L); //une variante 0
- ////////////////////////////////////
-
- //c'est pour initialiser et fermer l'ole
- struct InitOle {
- InitOle() { ::OleInitialize(NULL); }
- ~InitOle() { ::OleUninitialize(); }
- } _init_InitOle_;
- ///////////////////////////////////////
-
- //c'est un macro que j'ai trouve sur le MSDN dans un exemple et ça sert a
- //prendre les valeurs d'un tableau sans vous soucier de les convertir en _bstr_t
- #define RsITEM(rs,x) rs->Fields->Item[_variant_t(x)]->Value
- #define UC (char *)
-
- ////////////////////////////////////////////////
- //variables qu'on va utiliser dans l'application
- ////////////////////////////////////////////////
- int len = 0; //pour prendre les valeurs des édit box
- string querycom; //pour les commands SQL qu'on va faire
- string filtres; //pour les filtres
- int a = 0; //tableau uti ou livre
- int b = 0; //variable qui signal l'utilisation de pDb
- char * numerolivre = new char[1024];
- char * nomuti = new char[1024];
- char * numerouti = new char[1024];
- char * nomlivre = new char[1024];
- /////////////////////////////////////////////////
- [/Code]
- Apres ça créez une dlgproc et winmain de cette manière:
- (je vais mettre des numéros et des \\....... la ou on va mettre des codes)
- [Code]
- BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
- {
- switch(Message)
- {
- //trucs a faire a l'initialisation
- case WM_INITDIALOG:
- {
- //1..............................................
- }
- return TRUE;
- case WM_COMMAND:
- switch(LOWORD(wParam))
- {
- //2......................
- case IDOK:
- {
- EndDialog(hwnd, IDOK);
- //deinitialiser l'ole
- ::CoUninitialize();
- }
- break;
- case IDCANCEL:
- {
- EndDialog(hwnd, IDCANCEL);
- //deinitialiser l'ole
- ::CoUninitialize();
- }
- break;
- }
- break;
- default:
- return FALSE;
- }
- return TRUE;
- }
-
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- INITCOMMONCONTROLSEX InitCtrls;
- InitCtrls.dwICC = ICC_LISTVIEW_CLASSES;
- InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
- BOOL bRet = InitCommonControlsEx(&InitCtrls);
-
-
- DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC)DlgProc,0);
- return 0;
- }
- #undef UC
-
- Se connecter
-
- Maintenant on va remplir le WM_INITDIALOG. C?est là où on a mis //1.....
-
- try
- {
- CREATEiNSTANCE(pDb,Connection);
- //(1)
- pDb->ConnectionString = L"driver={sql server};SERVER=(local);Database=pubs;" L"UID=sa; PWD=;";
- //(2)
- pDb->ConnectionString = L"DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=biblo.mdb;DefaultDir=C:\\";
- //(3)
- pDb->Open( "", "", "", -1 );
- CREATEiNSTANCE(pSet,Recordset)
- //(4)
- pSet->PutRefActiveConnection( pDb );
- //(5)
- pSet->Open("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
- pSet->MoveFirst();
- }
- catch(_com_error &e)
- {
- _bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- }
- [/Code]
- Vous n? êtes pas obligé d?utiliser le ?try{} catch{}? mais si vous le faites vous pouvez facilement avoir les messages d?erreurs en détail.
- A (1) on commence à définir le ?connectionstring? qui sert à ouvrir une connexion avec la base de données. On dit que c?est un serveur local de SQL. Si vous devez utiliser un mot de passe et nom d?utilisateur pour vous connecter à votre base de données vous devez écrire le nom d?utilisateur ?UID? et le mot de passe ?PWD?.
- A (2) on définit la base de données et son adresse.
- A (3) on ouvre la connexion. On ne mets riens parce qu?on a déjà tout défini plus haut...
- A (4) on initialise notre ?Recordset? qu?on va utiliser dans notre application.
- A (5) on définit quels tableaux et quelles colonnes on va utiliser du base de données. Et on aussi définit le type du curseur le lock.
-
- Info: Les curseurs et les locks
- LockTypeEnum:
- 1) adLockBatchOptimistic (valeur 4) : Si vous allez utiliser le mode ?batch update? alors vous devez définir votre lock avec ça.
- 2) adLockOptimistic (valeur 3) : La base de donnée utilise ça quand ?Update? est appelée.
- 3) adLockPessimistic (valeur 2) : La base de donnée met la valeur éditée dans la base de donnée le plus vite possible.
- 4) adLockReadOnly (valeur 1) : La base de donnée ne peut pas être écrit, vous pouvez juste prendre des valeurs et les montrer aux utilisateurs.
- 5) adLockUnspecified (valeur -1) : Aucun lock.
-
- CursorTypeEnum:
- 1) adOpenDynamic (valeur 2): Les valeurs écrites par d?autres utilisateurs (application) sont visible et tous les types de mouvement dans le RecordSet est accorde. (MoveNext, MovePrevious, MoveLast, MoveFirst, Move,...).
- 2) adOpenForwardOnly (valeur 0): C?est la curseur par défaut. Vous ne pouvez pas retourner par exemple du clé 10 à 5 ou 1. (MovePrevious et MoveLast ne marchera pas) (Si vous n?avez pas besoin de retourner en arrière dans votre recordset c?est mieux d?utiliser ça parce que c?est plus vite)
- 3) adOpenKeyset (valeur 1) : C?est comme ?adOpenDynamic? mais avec ça vous ne pouvez pas partager entièrement la base de donnée avec d?autres applications s?ils ont ouvert la base de donnée en même temps que vous. Vous pouvez voir les valeurs écrites par d?autres applications, les valeurs efface seront inaccessible.
- 4) adOpenStatic (valeur 3): Si vous utilisez cette curseur une copie exacte du base de donnée est fait et vous pouvez trouver des valeurs dans la base de donnée. Vous ne pouvez pas voir les additions, effacements fait par d?autres applications sur la base de donnée.
- 5) adOpenUnspecified (valeur -1): On ne spécifie pas la curseur.
-
- (J?ai trouvé ces infos sur MSDN, pour plus d?info ?comme toujours- allez sur http://www.msdn.com )
-
- Si vous compilez votre projet ici ça doit marcher.
-
- Mais comment est-ce qu?on va lire, écrire, effacer, etc. des valeurs?
-
- Ajouter un livre:
- Créez les contrôles suivants sur votre dialogue:
- IDC_NUMEROLIVRE : edit_box
- IDC_NOMLIVRE : edit_box
- IDC_AJOUTERLIVRE : bouton
- IDC_NUMEROUTI : edit_box
- IDC_NOMLIVRE : edit_box
- IDC_AJOUTERUTI : bouton
- Et voilà le code pour ajouter un livre et un utilisateur dans la base de donnée:
- [Code]
- case IDC_AJOUTERLIVRE:
- {
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROLIVRE));
- if(len == 0)
- {
- MessageBox(hwnd,"Le numero du livre n'a pas ete specifié..","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
- break;
- }
- else if(len > 0)
- {
- numerolivre = (char *)GlobalAlloc(GPTR, len + 1);
- GetDlgItemText(hwnd, IDC_NUMEROLIVRE, numerolivre, len + 1);
- //est-ce que le livre avec ce numero se trouve dans la base de donné?
- //filtrons le pour voir s'il se trouve dans la base de donné
- querycom.erase();
- querycom.append("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE");
- try
- {
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- b = 1;
- //filtrer la base de donné
- filtres.erase();
- filtres.append("NUMEROLIVRE LIKE ");
- filtres.append("#");
- filtres.append(numerolivre);
- filtres.append("#");
- pSet->Filter = filtres.c_str();
- }
- catch( _com_error &e )
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- break;
- }
- //on regarde si apres la filtration la base de donnée est
- //a la fin ou autrepart
- if( pSet->EndOfFile != -1)
- {
- //il existe
- //alors on ne va pas r'ajouter
- MessageBox(hwnd,"Un livre avec ce numero exist deja dans la base de donné.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
- //--1--
- //on sort
- break;
- }
- else if( pSet->EndOfFile == -1)
- {
- //il est a la fin alors le numero n'exist pas on va ajouter le livre
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NOMLIVRE));
- if(len == 0)
- {
- MessageBox(hwnd,"Le nom du livre n'a pas ete specifié..","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
- break;
- }
- else if(len > 0)
- {
- nomlivre = (char *)GlobalAlloc(GPTR, len + 1);
- GetDlgItemText(hwnd, IDC_NOMLIVRE, nomlivre, len + 1);
- //nomdelivre pris alors on va ajouter une clé
- try
- {
- querycom.erase();
- querycom.append("INSERT INTO INFOLIVRE (NUMEROLIVRE, NOMLIVRE, VAL) VALUES ");
- b = 1;
- querycom.append("('");
- querycom.append(numerolivre);
- querycom.append("','");
- querycom.append(nomlivre);
- querycom.append("','0')");
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- }
- catch( _com_error &e )
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") +
- _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- break;
- }
- MessageBox(hwnd,"Mission accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
- }
- }
- }
- }
- break;
- [/Code]
- (J?ai coupé ici la code pour ajouter un utilisateur parce que c?est la même. Vous pouvez voir dans le projet que j?ai créé dans le zip pour tout voir.)
-
- Et voila tout ce qu?il faut faire pour ajouter un livre. On a d?abord pris le numéro du livre et on a regardé s?il existait déjà dans la base de donnée parce qu?on ne peut pas mettre deux noms de livre identiques à deux différents livres. Après si le numéro
- est libre on a lu le nom du livre de l?édit box et on a mis les valeurs dans le RecordSet avec la commande SQL ?INSERT INTO?.
-
- Mettre à jour un livre:
- Avec la code dessus on a pu trouver si le numéro existait déjà. On peut échanger la valeur ancien nomlivre avec la nouvelle... Comme ça: (il faut mettre la code a //--1?)
- [Code]
- //il existe deja alors on demande a l'utilisateur si'l veux échanger la valeur
- if( MessageBox(hwnd,"Echanger la valeur ?","ADO WIN32 API", MB_YESNO|MB_ICONINFORMATION) == IDYES)
- {
- //prendre nomlivre de l'édit box
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NOMLIVRE));
- if(len == 0)
- {
- MessageBox(hwnd,"Le nom du livre n'a pas ete specifié..","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
- break;
- }
- else if(len > 0)
- {
- //échanger la valeur
- try
- {
- querycom.erase();
- querycom.append("UPDATE INFOLIVRE SET NOMLIVRE = '");
- querycom.append(nomlivre);
- querycom.append("' WHERE (NUMEROLIVRE = '");
- querycom.append(numerolivre);
- querycom.append("')");
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- b = 1;
- }
- catch( _com_error &e )
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- }
- MessageBox(hwnd,"Mission Accompli","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
- }
- }
- else
- {
- //ne pas echanger
- break;
- }
- [/Code]
- Avec cette code vous pouvez mettre à jour vos clés. On a utilisé la commande SQL « UPDATE tableau SET colonne » pour ça.
-
- Se promener dans un RecordSet:
- Maintenant peut-être que vous vous demandez comment est-ce que je peux me promener dans un recordset ?
- Pour ça on utilise des méthodes comme MoveNext(), MoveFirst(), MoveLast(), MovePrevious() et Move().
- On va créer 2 nouveaux boutons sur notre dialogue le premier appelé IDC_FIN , IDC_DEBUT, IDC_AVANT , IDC_ARRIERE. Voici les codes :
- [Code]
- case IDC_DEBUT:
- {
- pSet->MovePrevious();
- // ---2---
- }
- break;
- case IDC_FIN:
- {
- pSet->MoveLast();
- // ---2---
- }
- break;
- case IDC_AVANT:
- {
- pSet->MoveNext();
- //on regarde si on est à la fin... si c'est le cas on indique a l'utilisateur
- if( pSet->EndOfFile == -1)
- {
- pSet->MoveLast();
- MessageBox(hwnd, "On est a la fin du RecordSet.","ADO WIN32 API", MB_OK | MB_ICONINFORMATION);
- }
- // ---2---
- }
- break;
- case IDC_ARRIERE:
- {
- //MovePrevious c'est pour revenir en arriere
- pSet->MovePrevious();
- //on regarde si on est au debut... si c'est le cas on indique a l'utilisateur
- if( pSet->BeginOfFile == -1)
- {
- pSet->MoveFirst();
- MessageBox(hwnd, "On est au debut du RecordSet.","ADO WIN32 API", MB_OK | MB_ICONINFORMATION);
- }
- // ---2---
- }
- break;
- [/Code]
- Pour IDC_ARRIERE et pour IDC_AVANT on a mit une petite code pour voir si on est à la fin ou au début du recordset, et on force le curseur à rester à la fin ou au début. Si on n?avait pas fait ça, chaque fois qu?on dépasse les limites du recordset, le recordset allait nous envoyer un message d?erreur et ça pourrait causer la fin inattendue de notre application.
-
- Afficher des valeurs :
- Maintenant on va apprendre à prendre des valeurs de notre recordset et l?afficher dans notre boîte de dialogue.
- Au début de cette article j?avais parlé d?un macro que j?avais trouvé dans un exemple sur MSDN :
- #define RsITEM(rs,x) rs->Fields->Item[_variant_t(x)]->Value
- Ça facilite vraiment la tâche de prendre des valeurs de notre recordset. On utilise ce macro (par exemple pour mettre la valeur d?un clé dans un édit box) comme ça:
- SetDlgItemText(hwnd, IDC_EDIT1, UC _bstr_t(RsITEM(pSet,"CLESICI")));
- Et c?est ce qu?on va faire. Sur votre boîte de dialogue créez 5 contrôles édit box le premier appelée IDC_S1 , le deuxième IDC_S2, etc. Et on va aussi mettre 2 boutons (IDC_RECLIVRE, IDC_RECUTI) pour spécifier dans quel tableau on veut se promener. D?abord pour les boutons :
- [Code]
- case IDC_RECLIVRE:
- {
- try{
- if( b == 1)
- {
- //continuer parcequil est deja ferme
- pSet->Open("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
- pSet->MoveFirst();
- b = 0 ;
- }
- else
- {
- //fermer le pset
- pSet->Close();
- pSet->Open("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
- pSet->MoveFirst();
- }
- }
- catch( _com_error &e ){
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- break;
- }
- a = 1;
- }
- break;
- case IDC_RECUTI:
- {
- //on ferme notre recordset et on le reouvre pour la tableau INFOUTI
- try{
- if( b == 1)
- {
- //continuer parcequil est deja ferme
- pSet->Open("SELECT NUMEROUTI, NOMUTI FROM INFOUTI", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
- pSet->MoveFirst();
- b = 0 ;
- }
- else
- {
- //fermer le pset
- pSet->Close();
- pSet->Open("SELECT NUMEROUTI, NOMUTI FROM INFOUTI", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
- pSet->MoveFirst();
- }
- }
- catch( _com_error &e ){
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- break;
- }
- a = 2;
- }
- break;
- [/Code]
- Avec cette code on ferme notre recordset courant et on le réouvre.
- Ce code donnée je voudrais vous avertir de quelque chose. On a utilisé les commandes SQL avec pDb->Execute() pour nos tâche d?écriture dans notre recordset mais il y a un piège. Il me semble que quand vous utilisez le pDb->Execute() votre pointeur de recordset pSet se réinitialise ( en effet il se ferme ). Et à cause de ça vous ne pouvez plus utiliser MoveNext, MoveFirst, etc.
- Oui? c?est bizarre. Alors ne faites jamais ça pour ouvrir un tableau pour afficher les valeurs et pour vous promener dans le tableau (ça vas fermer votre pSet et chaque fois que vous essayez d?utiliser ces méthodes comme MoveFirst() ça va donner des messages d?erreurs) :
- [Code]
- querycom.append("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE");
- try
- {
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- }
- catch( _com_error &e )
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- break;
- }
- pSet->MoveFirst() ;
- [/Code]
- J?avais fait ça quand j?avais commencé à programmer avec ado. Ce piège n?est pas documenté sur MSDN (je l?ai pas vu) ni sur d?autres sites (encore je n?ai pas encore vu).
-
- Avertissement fait on continue? Dans notre code ?Se promener dans un RecordSet? j?avais mis des //---2---. On va remplacer les //---2--- avec ça :
- [Code]
- if(a == 1)
- {
- SetDlgItemText(hwnd, IDC_S1, UC _bstr_t(RsITEM(pSet,"NUMEROLIVRE")));
- SetDlgItemText(hwnd, IDC_S2, UC _bstr_t(RsITEM(pSet,"NOMLIVRE"))); SetDlgItemText(hwnd, IDC_S3, UC _bstr_t(RsITEM(pSet,"VAL")));
- }
- else if( a == 2)
- {
- SetDlgItemText(hwnd, IDC_S1, UC _bstr_t(RsITEM(pSet,"NUMEROUTI")));
- SetDlgItemText(hwnd, IDC_S2, UC _bstr_t(RsITEM(pSet,"NOMUTI")));
- }
- else
- {
- MessageBox(hwnd,"Aucun tableau specifié.","ADO WIN32 API");
- }
- [/Code]
- Avec ce code on met les valeurs dans les clés dans nos édit box.
-
- Effacer des clés :
- Ajoutez 2 boutons sur votre boîte de dialogue ( IDC_EFUTI, IDC_EFLIVRE) . Et après ce code :
- [Code]
- case IDC_EFUTI:
- {
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROUTI));
- if(len == 0)
- {
- MessageBox(hwnd,"Entrez une numero d'utilisateur.","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
- }
- else if(len > 0)
- {
- if( MessageBox(hwnd, "Etes-vous sure de vouloir supprimez l'utilisateur?","ADO WIN32 API", MB_YESNO| MB_ICONEXCLAMATION) == IDYES)
- {
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROUTI));
- if(len > 0)
- {
- numerouti = (LPTSTR)GlobalAlloc(GPTR, len + 1);
- GetDlgItemText(hwnd, IDC_NUMEROUTI, numerouti, len + 1);
- }
- querycom.erase();
- querycom.append("DELETE FROM INFOUTI WHERE (NUMEROUTI ");
- querycom.append("= '");
- querycom.append(numerouti);
- querycom.append("')");
- try
- {
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- b = 1;
- }
- catch( _com_error &e )
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- }
- querycom.erase();
- MessageBox(hwnd,"Mission Accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
- }
- }
- }
- break;
- case IDC_EFLIVRE:
- {
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROLIVRE));
- if(len == 0)
- {
- MessageBox(hwnd,"Entrez un numero de livre.","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
- }
- else if(len > 0)
- {
- if( MessageBox(hwnd, "Etes-vous sure de vouloir supprimez le livre?","ADO WIN32 API", MB_YESNO| MB_ICONEXCLAMATION) == IDYES)
- {
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROLIVRE));
- if(len > 0)
- {
- numerolivre = (LPTSTR)GlobalAlloc(GPTR, len + 1);
- GetDlgItemText(hwnd, IDC_NUMEROLIVRE, numerolivre, len + 1);
- }
- querycom.erase();
- querycom.append("DELETE FROM INFOLIVRE WHERE (NUMEROLIVRE ");
- querycom.append("= '");
- querycom.append(numerolivre);
- querycom.append("')");
- try
- {
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- b = 1;
- }
- catch( _com_error &e )
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- }
- querycom.erase();
- MessageBox(hwnd,"Mission Accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
- }
- }
- }
- break;
- [/Code]
- Et pour effacer une clé on utilise la commande SQL « DELETE FROM tableau WHERE clé » .On n?as pas vérifié si le numéro du livre ou d?utilisateur existe vraiment mais ça doit être évident pour vous de le faire car je l?avais fait plus haut quand on essayait d?ajouter des clés.
-
- Prendre et remettre un livre :
-
- Et maintenant la touche finale. Prendre et remettre des livres. Pour ça on a besoin de deux contrôles d?édit (IDC_PRNUMEROLIVRE, IDC_PRNUMEROUTI) et deux boutons (IDC_REMETTRE, IDC_PRENDRE). Voila:
- [Code]
- case IDC_PRENDRE:
- {
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROLIVRE));
- if(len == 0)
- {
- MessageBox(hwnd,"Entrez un numero de livre.","ADO WIN32 API",MB_OK|MB_ICONEXCLAMATION);
- }
- else if(len > 0)
- {
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROLIVRE));
- if(len > 0)
- {
- numerolivre = (LPTSTR)GlobalAlloc(GPTR, len + 1);
- GetDlgItemText(hwnd, IDC_PRNUMEROLIVRE, numerolivre, len + 1);
- }
- //est-ce que le livre avec ce numero existe vraiment
- querycom.erase();
- querycom.append("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE WHERE NUMEROLIVRE = '");
- querycom.append(numerolivre);
- querycom.append("'");
- try
- {
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- b = 1;
- }
- catch(_com_error &e)
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- }
- _variant_t f1;
- try
- {
- pSet->GetCollect(L"NUMEROLIVRE");
- }
- catch(_com_error)
- {
- //Silya erreur il n'existe pas
- break;
- }
- //pas d'erreur alors il exist
- //on prends la valeur d'utilisateur
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROUTI));
- if(len > 0)
- {
- numerouti = (LPTSTR)GlobalAlloc(GPTR, len + 1);
- GetDlgItemText(hwnd, IDC_PRNUMEROUTI, numerouti, len + 1);
- }
- //on ecris dans la base de donnée
- querycom.erase();
- querycom.append("UPDATE INFOLIVRE SET VAL = '");
- querycom.append(numerouti);
- querycom.append("' WHERE (NUMEROLIVRE = '");
- querycom.append(numerolivre);
- querycom.append("')");
- try
- {
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- b = 1;
- }
- catch(_com_error &e)
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- }
- querycom.erase();
- MessageBox(hwnd,"Mission Accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
- }
- }
- break;
- case IDC_REMETTRE:
- {
- //remettre le livre
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROLIVRE));
- if(len == 0)
- {
- MessageBox(hwnd,"Entrez un numero de livre.","ADO WIN32 API",MB_OK|MB_ICONEXCLAMATION);
- }
- else if(len > 0)
- {
- len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROLIVRE));
- if(len > 0)
- {
- numerolivre = (char *)GlobalAlloc(GPTR, len + 1);
- GetDlgItemText(hwnd, IDC_PRNUMEROLIVRE, numerolivre, len + 1);
- }
- //est-ce que le livre existe dans la base de donnee
- querycom.erase();
- querycom.append("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE WHERE NUMEROLIVRE = '");
- querycom.append(numerolivre);
- querycom.append("'");
- try
- {
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- b = 1;
- }
- catch(_com_error &e)
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- }
- querycom.erase();
- try
- {
- pSet->GetCollect(L"NUMEROLIVRE");
- }
- catch(_com_error)
- {
- //si il ya une erreur ca veux dire quil nexiste pas
- break;
- }
- //le livre existe
- //on ecris dans la base de donnée
- querycom.erase();
- querycom.append("UPDATE INFOLIVRE SET VAL = '0' WHERE (NUMEROLIVRE = '");
- querycom.append(numerolivre);
- querycom.append("')");
- try
- {
- pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
- b = 1;
- }
- catch(_com_error &e)
- {
- bstr_t bstrSource(e.Source());
- _bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
- + _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
- + _bstr_t(e.Description());
- MessageBox(0,bs,bstrSource, MB_OK);
- }
- querycom.erase();
- MessageBox(hwnd,"Mission Accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
- }
- }
- break;
- [/Code]
- On a rien de nouveau ici. On a utilisé la commande SQL « UPDATE » comme on l?avait fait plus haut.
-
- La fin :
-
- Ce n?est pas vraiment une application de gestion de bibliothèque mais c?est un bon commencement.
-
- Le code complet est dans le zip.
-
- Mon article se termine ici. Je vous remercie de l?avoir lu.
ADO ET WIN32 API
Un tutorial pour les nouveaux
Introduction
Dans ce petit tutorial je vais essayer de vous apprendre à utiliser le ADO pour faire des applications de base de données avec le API win32 et c++.
Je dois vous dire qu'avec le MFC c'est cent fois plus facile mais pour ceux qui veulent tout le pouvoir en main je recommande l'api.
J'écris cette article parce que j'ai eu quelques difficultés quand j'avais commencé a apprendre l'ado... il y a des petits trucs très important et c'est même pas documenté sur le Web (enfin je n'ai pas trouvé).
J'utilise visual c++ mais vous pouvez facilement le convertir pour d'autres environnements de développement.
Entrer dans le monde d'ADO
On va faire pas à pas une application avec ado... par exemple une application de gestion de bibliothèque (très simple).
Début
Projet: Appelez votre projet ?biblo?. Créez dans votre projet un fichier appelé ?main.cpp?. Créez votre fichier de ressource et dans votre fichier de ressource créez un dialogue appelé ?IDD_MAIN?.
Base de donnée: Créez un fichier appelée ?biblo.mdb? avec Access et mettez le dans C:\ .
Dans ce fichier ajoutez une tableau appelée ?INFOUTI? (informations sur l?utilisateur qui prends des livres) et dans ce tableau mettez les clés ?NUMEROUTI? (numéro qu?on donne a l?utilisateur) et ?NOMUTI? (nom de l?utilisateur).
Dans votre fichier ajoutez une autre tableau appelée ?INFOLIVRE? (informations sur les livres) et dans ce tableau ?NUMEROLIVRE? (numéro du livre), ?NOMLIVRE? (nom du livre) et ?VAL? (on va l?utiliser pour savoir si le livre est pris ou pas...).
(N?oubliez pas d?écrire des valeurs bidon dans vos tableaux pour qu?on puisse les utiliser)
(Toutes les clés doivent être des clés texte, pas nombre ou autre chose)
-------------------------------------
Dans le fichier "main.cpp" mettez ça au début de votre fichier et aussi n'oubliez pas de linker comctl32.lib.
[Code]
//les includes que vous avez besoin pour le projet
#include <windows.h>
#include <icrsint.h>
#include <iostream.h>
#include <string>
#include <sstream>
#include <commctrl.h>
#include "resource.h"
//pour std
using std::string;
//sans ça vous ne pouvez pas travailler avec ado sous win32 alors c'est important
//ici on importe le dll ado. Si le dll d'ado est ailleurs alors changez l'adresse
//et on aussi renomme EOF et BOF pour des raisons de comptabilités
#import "c:\Program Files\Fichiers Communs\System\ADO\msado15.dll" \
no_namespace rename("EOF", "EndOfFile") no_namespace rename("BOF", "BeginOfFile")
#define CREATEiNSTANCE(sp,riid) { HRESULT _hr =sp .CreateInstance( __uuidof( riid ) ); \
if (FAILED(_hr)) _com_issue_error(_hr); }
//variables q'on va utiliser avec ado
_RecordsetPtr pSet = NULL; // pointeur pour le recordset
_ConnectionPtr pDb = NULL; //pointeur pour la base de donnee
_variant_t vRecsAffected(0L); //une variante 0
////////////////////////////////////
//c'est pour initialiser et fermer l'ole
struct InitOle {
InitOle() { ::OleInitialize(NULL); }
~InitOle() { ::OleUninitialize(); }
} _init_InitOle_;
///////////////////////////////////////
//c'est un macro que j'ai trouve sur le MSDN dans un exemple et ça sert a
//prendre les valeurs d'un tableau sans vous soucier de les convertir en _bstr_t
#define RsITEM(rs,x) rs->Fields->Item[_variant_t(x)]->Value
#define UC (char *)
////////////////////////////////////////////////
//variables qu'on va utiliser dans l'application
////////////////////////////////////////////////
int len = 0; //pour prendre les valeurs des édit box
string querycom; //pour les commands SQL qu'on va faire
string filtres; //pour les filtres
int a = 0; //tableau uti ou livre
int b = 0; //variable qui signal l'utilisation de pDb
char * numerolivre = new char[1024];
char * nomuti = new char[1024];
char * numerouti = new char[1024];
char * nomlivre = new char[1024];
/////////////////////////////////////////////////
[/Code]
Apres ça créez une dlgproc et winmain de cette manière:
(je vais mettre des numéros et des \\....... la ou on va mettre des codes)
[Code]
BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
//trucs a faire a l'initialisation
case WM_INITDIALOG:
{
//1..............................................
}
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
//2......................
case IDOK:
{
EndDialog(hwnd, IDOK);
//deinitialiser l'ole
::CoUninitialize();
}
break;
case IDCANCEL:
{
EndDialog(hwnd, IDCANCEL);
//deinitialiser l'ole
::CoUninitialize();
}
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwICC = ICC_LISTVIEW_CLASSES;
InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
BOOL bRet = InitCommonControlsEx(&InitCtrls);
DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC)DlgProc,0);
return 0;
}
#undef UC
Se connecter
Maintenant on va remplir le WM_INITDIALOG. C?est là où on a mis //1.....
try
{
CREATEiNSTANCE(pDb,Connection);
//(1)
pDb->ConnectionString = L"driver={sql server};SERVER=(local);Database=pubs;" L"UID=sa; PWD=;";
//(2)
pDb->ConnectionString = L"DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=biblo.mdb;DefaultDir=C:\\";
//(3)
pDb->Open( "", "", "", -1 );
CREATEiNSTANCE(pSet,Recordset)
//(4)
pSet->PutRefActiveConnection( pDb );
//(5)
pSet->Open("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
pSet->MoveFirst();
}
catch(_com_error &e)
{
_bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
}
[/Code]
Vous n? êtes pas obligé d?utiliser le ?try{} catch{}? mais si vous le faites vous pouvez facilement avoir les messages d?erreurs en détail.
A (1) on commence à définir le ?connectionstring? qui sert à ouvrir une connexion avec la base de données. On dit que c?est un serveur local de SQL. Si vous devez utiliser un mot de passe et nom d?utilisateur pour vous connecter à votre base de données vous devez écrire le nom d?utilisateur ?UID? et le mot de passe ?PWD?.
A (2) on définit la base de données et son adresse.
A (3) on ouvre la connexion. On ne mets riens parce qu?on a déjà tout défini plus haut...
A (4) on initialise notre ?Recordset? qu?on va utiliser dans notre application.
A (5) on définit quels tableaux et quelles colonnes on va utiliser du base de données. Et on aussi définit le type du curseur le lock.
Info: Les curseurs et les locks
LockTypeEnum:
1) adLockBatchOptimistic (valeur 4) : Si vous allez utiliser le mode ?batch update? alors vous devez définir votre lock avec ça.
2) adLockOptimistic (valeur 3) : La base de donnée utilise ça quand ?Update? est appelée.
3) adLockPessimistic (valeur 2) : La base de donnée met la valeur éditée dans la base de donnée le plus vite possible.
4) adLockReadOnly (valeur 1) : La base de donnée ne peut pas être écrit, vous pouvez juste prendre des valeurs et les montrer aux utilisateurs.
5) adLockUnspecified (valeur -1) : Aucun lock.
CursorTypeEnum:
1) adOpenDynamic (valeur 2): Les valeurs écrites par d?autres utilisateurs (application) sont visible et tous les types de mouvement dans le RecordSet est accorde. (MoveNext, MovePrevious, MoveLast, MoveFirst, Move,...).
2) adOpenForwardOnly (valeur 0): C?est la curseur par défaut. Vous ne pouvez pas retourner par exemple du clé 10 à 5 ou 1. (MovePrevious et MoveLast ne marchera pas) (Si vous n?avez pas besoin de retourner en arrière dans votre recordset c?est mieux d?utiliser ça parce que c?est plus vite)
3) adOpenKeyset (valeur 1) : C?est comme ?adOpenDynamic? mais avec ça vous ne pouvez pas partager entièrement la base de donnée avec d?autres applications s?ils ont ouvert la base de donnée en même temps que vous. Vous pouvez voir les valeurs écrites par d?autres applications, les valeurs efface seront inaccessible.
4) adOpenStatic (valeur 3): Si vous utilisez cette curseur une copie exacte du base de donnée est fait et vous pouvez trouver des valeurs dans la base de donnée. Vous ne pouvez pas voir les additions, effacements fait par d?autres applications sur la base de donnée.
5) adOpenUnspecified (valeur -1): On ne spécifie pas la curseur.
(J?ai trouvé ces infos sur MSDN, pour plus d?info ?comme toujours- allez sur http://www.msdn.com )
Si vous compilez votre projet ici ça doit marcher.
Mais comment est-ce qu?on va lire, écrire, effacer, etc. des valeurs?
Ajouter un livre:
Créez les contrôles suivants sur votre dialogue:
IDC_NUMEROLIVRE : edit_box
IDC_NOMLIVRE : edit_box
IDC_AJOUTERLIVRE : bouton
IDC_NUMEROUTI : edit_box
IDC_NOMLIVRE : edit_box
IDC_AJOUTERUTI : bouton
Et voilà le code pour ajouter un livre et un utilisateur dans la base de donnée:
[Code]
case IDC_AJOUTERLIVRE:
{
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROLIVRE));
if(len == 0)
{
MessageBox(hwnd,"Le numero du livre n'a pas ete specifié..","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
break;
}
else if(len > 0)
{
numerolivre = (char *)GlobalAlloc(GPTR, len + 1);
GetDlgItemText(hwnd, IDC_NUMEROLIVRE, numerolivre, len + 1);
//est-ce que le livre avec ce numero se trouve dans la base de donné?
//filtrons le pour voir s'il se trouve dans la base de donné
querycom.erase();
querycom.append("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE");
try
{
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
b = 1;
//filtrer la base de donné
filtres.erase();
filtres.append("NUMEROLIVRE LIKE ");
filtres.append("#");
filtres.append(numerolivre);
filtres.append("#");
pSet->Filter = filtres.c_str();
}
catch( _com_error &e )
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
break;
}
//on regarde si apres la filtration la base de donnée est
//a la fin ou autrepart
if( pSet->EndOfFile != -1)
{
//il existe
//alors on ne va pas r'ajouter
MessageBox(hwnd,"Un livre avec ce numero exist deja dans la base de donné.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
//--1--
//on sort
break;
}
else if( pSet->EndOfFile == -1)
{
//il est a la fin alors le numero n'exist pas on va ajouter le livre
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NOMLIVRE));
if(len == 0)
{
MessageBox(hwnd,"Le nom du livre n'a pas ete specifié..","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
break;
}
else if(len > 0)
{
nomlivre = (char *)GlobalAlloc(GPTR, len + 1);
GetDlgItemText(hwnd, IDC_NOMLIVRE, nomlivre, len + 1);
//nomdelivre pris alors on va ajouter une clé
try
{
querycom.erase();
querycom.append("INSERT INTO INFOLIVRE (NUMEROLIVRE, NOMLIVRE, VAL) VALUES ");
b = 1;
querycom.append("('");
querycom.append(numerolivre);
querycom.append("','");
querycom.append(nomlivre);
querycom.append("','0')");
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
}
catch( _com_error &e )
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") +
_bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
break;
}
MessageBox(hwnd,"Mission accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
}
}
}
}
break;
[/Code]
(J?ai coupé ici la code pour ajouter un utilisateur parce que c?est la même. Vous pouvez voir dans le projet que j?ai créé dans le zip pour tout voir.)
Et voila tout ce qu?il faut faire pour ajouter un livre. On a d?abord pris le numéro du livre et on a regardé s?il existait déjà dans la base de donnée parce qu?on ne peut pas mettre deux noms de livre identiques à deux différents livres. Après si le numéro
est libre on a lu le nom du livre de l?édit box et on a mis les valeurs dans le RecordSet avec la commande SQL ?INSERT INTO?.
Mettre à jour un livre:
Avec la code dessus on a pu trouver si le numéro existait déjà. On peut échanger la valeur ancien nomlivre avec la nouvelle... Comme ça: (il faut mettre la code a //--1?)
[Code]
//il existe deja alors on demande a l'utilisateur si'l veux échanger la valeur
if( MessageBox(hwnd,"Echanger la valeur ?","ADO WIN32 API", MB_YESNO|MB_ICONINFORMATION) == IDYES)
{
//prendre nomlivre de l'édit box
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NOMLIVRE));
if(len == 0)
{
MessageBox(hwnd,"Le nom du livre n'a pas ete specifié..","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
break;
}
else if(len > 0)
{
//échanger la valeur
try
{
querycom.erase();
querycom.append("UPDATE INFOLIVRE SET NOMLIVRE = '");
querycom.append(nomlivre);
querycom.append("' WHERE (NUMEROLIVRE = '");
querycom.append(numerolivre);
querycom.append("')");
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
b = 1;
}
catch( _com_error &e )
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
}
MessageBox(hwnd,"Mission Accompli","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
}
}
else
{
//ne pas echanger
break;
}
[/Code]
Avec cette code vous pouvez mettre à jour vos clés. On a utilisé la commande SQL « UPDATE tableau SET colonne » pour ça.
Se promener dans un RecordSet:
Maintenant peut-être que vous vous demandez comment est-ce que je peux me promener dans un recordset ?
Pour ça on utilise des méthodes comme MoveNext(), MoveFirst(), MoveLast(), MovePrevious() et Move().
On va créer 2 nouveaux boutons sur notre dialogue le premier appelé IDC_FIN , IDC_DEBUT, IDC_AVANT , IDC_ARRIERE. Voici les codes :
[Code]
case IDC_DEBUT:
{
pSet->MovePrevious();
// ---2---
}
break;
case IDC_FIN:
{
pSet->MoveLast();
// ---2---
}
break;
case IDC_AVANT:
{
pSet->MoveNext();
//on regarde si on est à la fin... si c'est le cas on indique a l'utilisateur
if( pSet->EndOfFile == -1)
{
pSet->MoveLast();
MessageBox(hwnd, "On est a la fin du RecordSet.","ADO WIN32 API", MB_OK | MB_ICONINFORMATION);
}
// ---2---
}
break;
case IDC_ARRIERE:
{
//MovePrevious c'est pour revenir en arriere
pSet->MovePrevious();
//on regarde si on est au debut... si c'est le cas on indique a l'utilisateur
if( pSet->BeginOfFile == -1)
{
pSet->MoveFirst();
MessageBox(hwnd, "On est au debut du RecordSet.","ADO WIN32 API", MB_OK | MB_ICONINFORMATION);
}
// ---2---
}
break;
[/Code]
Pour IDC_ARRIERE et pour IDC_AVANT on a mit une petite code pour voir si on est à la fin ou au début du recordset, et on force le curseur à rester à la fin ou au début. Si on n?avait pas fait ça, chaque fois qu?on dépasse les limites du recordset, le recordset allait nous envoyer un message d?erreur et ça pourrait causer la fin inattendue de notre application.
Afficher des valeurs :
Maintenant on va apprendre à prendre des valeurs de notre recordset et l?afficher dans notre boîte de dialogue.
Au début de cette article j?avais parlé d?un macro que j?avais trouvé dans un exemple sur MSDN :
#define RsITEM(rs,x) rs->Fields->Item[_variant_t(x)]->Value
Ça facilite vraiment la tâche de prendre des valeurs de notre recordset. On utilise ce macro (par exemple pour mettre la valeur d?un clé dans un édit box) comme ça:
SetDlgItemText(hwnd, IDC_EDIT1, UC _bstr_t(RsITEM(pSet,"CLESICI")));
Et c?est ce qu?on va faire. Sur votre boîte de dialogue créez 5 contrôles édit box le premier appelée IDC_S1 , le deuxième IDC_S2, etc. Et on va aussi mettre 2 boutons (IDC_RECLIVRE, IDC_RECUTI) pour spécifier dans quel tableau on veut se promener. D?abord pour les boutons :
[Code]
case IDC_RECLIVRE:
{
try{
if( b == 1)
{
//continuer parcequil est deja ferme
pSet->Open("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
pSet->MoveFirst();
b = 0 ;
}
else
{
//fermer le pset
pSet->Close();
pSet->Open("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
pSet->MoveFirst();
}
}
catch( _com_error &e ){
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
break;
}
a = 1;
}
break;
case IDC_RECUTI:
{
//on ferme notre recordset et on le reouvre pour la tableau INFOUTI
try{
if( b == 1)
{
//continuer parcequil est deja ferme
pSet->Open("SELECT NUMEROUTI, NOMUTI FROM INFOUTI", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
pSet->MoveFirst();
b = 0 ;
}
else
{
//fermer le pset
pSet->Close();
pSet->Open("SELECT NUMEROUTI, NOMUTI FROM INFOUTI", vtMissing, adOpenDynamic,adLockBatchOptimistic, -1);
pSet->MoveFirst();
}
}
catch( _com_error &e ){
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
break;
}
a = 2;
}
break;
[/Code]
Avec cette code on ferme notre recordset courant et on le réouvre.
Ce code donnée je voudrais vous avertir de quelque chose. On a utilisé les commandes SQL avec pDb->Execute() pour nos tâche d?écriture dans notre recordset mais il y a un piège. Il me semble que quand vous utilisez le pDb->Execute() votre pointeur de recordset pSet se réinitialise ( en effet il se ferme ). Et à cause de ça vous ne pouvez plus utiliser MoveNext, MoveFirst, etc.
Oui? c?est bizarre. Alors ne faites jamais ça pour ouvrir un tableau pour afficher les valeurs et pour vous promener dans le tableau (ça vas fermer votre pSet et chaque fois que vous essayez d?utiliser ces méthodes comme MoveFirst() ça va donner des messages d?erreurs) :
[Code]
querycom.append("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE");
try
{
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
}
catch( _com_error &e )
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
break;
}
pSet->MoveFirst() ;
[/Code]
J?avais fait ça quand j?avais commencé à programmer avec ado. Ce piège n?est pas documenté sur MSDN (je l?ai pas vu) ni sur d?autres sites (encore je n?ai pas encore vu).
Avertissement fait on continue? Dans notre code ?Se promener dans un RecordSet? j?avais mis des //---2---. On va remplacer les //---2--- avec ça :
[Code]
if(a == 1)
{
SetDlgItemText(hwnd, IDC_S1, UC _bstr_t(RsITEM(pSet,"NUMEROLIVRE")));
SetDlgItemText(hwnd, IDC_S2, UC _bstr_t(RsITEM(pSet,"NOMLIVRE"))); SetDlgItemText(hwnd, IDC_S3, UC _bstr_t(RsITEM(pSet,"VAL")));
}
else if( a == 2)
{
SetDlgItemText(hwnd, IDC_S1, UC _bstr_t(RsITEM(pSet,"NUMEROUTI")));
SetDlgItemText(hwnd, IDC_S2, UC _bstr_t(RsITEM(pSet,"NOMUTI")));
}
else
{
MessageBox(hwnd,"Aucun tableau specifié.","ADO WIN32 API");
}
[/Code]
Avec ce code on met les valeurs dans les clés dans nos édit box.
Effacer des clés :
Ajoutez 2 boutons sur votre boîte de dialogue ( IDC_EFUTI, IDC_EFLIVRE) . Et après ce code :
[Code]
case IDC_EFUTI:
{
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROUTI));
if(len == 0)
{
MessageBox(hwnd,"Entrez une numero d'utilisateur.","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
}
else if(len > 0)
{
if( MessageBox(hwnd, "Etes-vous sure de vouloir supprimez l'utilisateur?","ADO WIN32 API", MB_YESNO| MB_ICONEXCLAMATION) == IDYES)
{
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROUTI));
if(len > 0)
{
numerouti = (LPTSTR)GlobalAlloc(GPTR, len + 1);
GetDlgItemText(hwnd, IDC_NUMEROUTI, numerouti, len + 1);
}
querycom.erase();
querycom.append("DELETE FROM INFOUTI WHERE (NUMEROUTI ");
querycom.append("= '");
querycom.append(numerouti);
querycom.append("')");
try
{
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
b = 1;
}
catch( _com_error &e )
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
}
querycom.erase();
MessageBox(hwnd,"Mission Accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
}
}
}
break;
case IDC_EFLIVRE:
{
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROLIVRE));
if(len == 0)
{
MessageBox(hwnd,"Entrez un numero de livre.","ADO WIN32 API",MB_OK |MB_ICONEXCLAMATION);
}
else if(len > 0)
{
if( MessageBox(hwnd, "Etes-vous sure de vouloir supprimez le livre?","ADO WIN32 API", MB_YESNO| MB_ICONEXCLAMATION) == IDYES)
{
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_NUMEROLIVRE));
if(len > 0)
{
numerolivre = (LPTSTR)GlobalAlloc(GPTR, len + 1);
GetDlgItemText(hwnd, IDC_NUMEROLIVRE, numerolivre, len + 1);
}
querycom.erase();
querycom.append("DELETE FROM INFOLIVRE WHERE (NUMEROLIVRE ");
querycom.append("= '");
querycom.append(numerolivre);
querycom.append("')");
try
{
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
b = 1;
}
catch( _com_error &e )
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
}
querycom.erase();
MessageBox(hwnd,"Mission Accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
}
}
}
break;
[/Code]
Et pour effacer une clé on utilise la commande SQL « DELETE FROM tableau WHERE clé » .On n?as pas vérifié si le numéro du livre ou d?utilisateur existe vraiment mais ça doit être évident pour vous de le faire car je l?avais fait plus haut quand on essayait d?ajouter des clés.
Prendre et remettre un livre :
Et maintenant la touche finale. Prendre et remettre des livres. Pour ça on a besoin de deux contrôles d?édit (IDC_PRNUMEROLIVRE, IDC_PRNUMEROUTI) et deux boutons (IDC_REMETTRE, IDC_PRENDRE). Voila:
[Code]
case IDC_PRENDRE:
{
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROLIVRE));
if(len == 0)
{
MessageBox(hwnd,"Entrez un numero de livre.","ADO WIN32 API",MB_OK|MB_ICONEXCLAMATION);
}
else if(len > 0)
{
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROLIVRE));
if(len > 0)
{
numerolivre = (LPTSTR)GlobalAlloc(GPTR, len + 1);
GetDlgItemText(hwnd, IDC_PRNUMEROLIVRE, numerolivre, len + 1);
}
//est-ce que le livre avec ce numero existe vraiment
querycom.erase();
querycom.append("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE WHERE NUMEROLIVRE = '");
querycom.append(numerolivre);
querycom.append("'");
try
{
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
b = 1;
}
catch(_com_error &e)
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
}
_variant_t f1;
try
{
pSet->GetCollect(L"NUMEROLIVRE");
}
catch(_com_error)
{
//Silya erreur il n'existe pas
break;
}
//pas d'erreur alors il exist
//on prends la valeur d'utilisateur
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROUTI));
if(len > 0)
{
numerouti = (LPTSTR)GlobalAlloc(GPTR, len + 1);
GetDlgItemText(hwnd, IDC_PRNUMEROUTI, numerouti, len + 1);
}
//on ecris dans la base de donnée
querycom.erase();
querycom.append("UPDATE INFOLIVRE SET VAL = '");
querycom.append(numerouti);
querycom.append("' WHERE (NUMEROLIVRE = '");
querycom.append(numerolivre);
querycom.append("')");
try
{
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
b = 1;
}
catch(_com_error &e)
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
}
querycom.erase();
MessageBox(hwnd,"Mission Accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
}
}
break;
case IDC_REMETTRE:
{
//remettre le livre
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROLIVRE));
if(len == 0)
{
MessageBox(hwnd,"Entrez un numero de livre.","ADO WIN32 API",MB_OK|MB_ICONEXCLAMATION);
}
else if(len > 0)
{
len = GetWindowTextLength(GetDlgItem(hwnd, IDC_PRNUMEROLIVRE));
if(len > 0)
{
numerolivre = (char *)GlobalAlloc(GPTR, len + 1);
GetDlgItemText(hwnd, IDC_PRNUMEROLIVRE, numerolivre, len + 1);
}
//est-ce que le livre existe dans la base de donnee
querycom.erase();
querycom.append("SELECT NUMEROLIVRE, NOMLIVRE, VAL FROM INFOLIVRE WHERE NUMEROLIVRE = '");
querycom.append(numerolivre);
querycom.append("'");
try
{
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
b = 1;
}
catch(_com_error &e)
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
}
querycom.erase();
try
{
pSet->GetCollect(L"NUMEROLIVRE");
}
catch(_com_error)
{
//si il ya une erreur ca veux dire quil nexiste pas
break;
}
//le livre existe
//on ecris dans la base de donnée
querycom.erase();
querycom.append("UPDATE INFOLIVRE SET VAL = '0' WHERE (NUMEROLIVRE = '");
querycom.append(numerolivre);
querycom.append("')");
try
{
pSet = pDb->Execute(querycom.c_str(), &vRecsAffected, adOptionUnspecified);
b = 1;
}
catch(_com_error &e)
{
bstr_t bstrSource(e.Source());
_bstr_t bs = _bstr_t(" Erreur: ") + _bstr_t(e.Error()) + _bstr_t(" Message: ")
+ _bstr_t(e.ErrorMessage()) + _bstr_t("\nErreur:\n")
+ _bstr_t(e.Description());
MessageBox(0,bs,bstrSource, MB_OK);
}
querycom.erase();
MessageBox(hwnd,"Mission Accompli.","ADO WIN32 API",MB_OK|MB_ICONINFORMATION);
}
}
break;
[/Code]
On a rien de nouveau ici. On a utilisé la commande SQL « UPDATE » comme on l?avait fait plus haut.
La fin :
Ce n?est pas vraiment une application de gestion de bibliothèque mais c?est un bon commencement.
Le code complet est dans le zip.
Mon article se termine ici. Je vous remercie de l?avoir lu.
Conclusion
Ecrit par SCO http://www.ecomb.com02.com scolinks@hotmail.com
(P.-S. : C?est mon premier article sur le Web et ça serait bien si vous pouviez m?envoyer des recommandations. Je vous remercie d?avance ! scolinks@hotmail.com)
Historique
- 17 juillet 2004 13:30:05 :
- Correction: TABLEAU changé a INFOLIVRE ( je l'avais oublié )
Sources du même auteur
Sources de la même categorie
Commentaires et avis
Discussions en rapport avec ce code source dans le forum
Cours - Tutorial ADO [ par LordBob ]
Bonjour a tous,voila en fait je chercher un cours / tutorial sur l'utilisation d'ADO uniquement avec les API (sans MFC). S'il vous plait ne me renvoye
Tutoriel C++ [ par Max1me ]
Salut :).Donc je suis à la recherche d'un tutoriel facile en C++. J'en ai suivi qqes-uns mais à chaque fois je bloque (surtout au niveau des pointeurs
Cours ou tutorial svp [ par Fildomen ]
Salutje vous prie de me passer qlq cours ou tutorials sur le c++.net.si vous voulez me les donner directement (fildomen@yahoo.fr) , sinon des liens.Me
ADO [ par callaghan1981 ]
C ets encore moi..je galere bcp..j arrive a comprendre ADO..mais tt vos exemple st en C++..je ne fais malheureusement pas de C++ mais du Cje n arrive
Intégrer de l'assembleur dans du C. [ par alekine ]
Bonjour,voilà déjà quelques minute que je cherche du code et un tutorial sur l'intégration d'asm dans du code C. Que ce soit sur le site ou google, je
probleme de LINK avec ADO [ par callaghan1981 ]
bjrj ai un petit bleme de linksous ADO#include "stdafx.h"#include"ADOLib.h"#include "iostream.h"CWinApp theApp;ADOConnect myConn;int _tmain( int argc
Tutorial [ par bilaloch ]
Salut les c++codeurs,Je voulais demander si quelqu'un aura la mabilité de me faire un tuto en c++ (comment quitter, créer une feuille...) parce que je
Connexion ADO.... [ par Clonk ]
Bonjour,Je développe une appli ou j'utilise une connexion ADO à une base Access.Si sur ma machine, ça marche très bien, il y ades problème chez les au
Warning avec ado [ par Matt67 ]
Bonsoir,J'utilise la dll ADO pour acceder à ma base access mais j'ai le warning suivant quand je compile :warning C4146: unary minus operator applied
WM_PAINT [ par KuidZ ]
Bonjour je viens de me lancer dans le tutoriel de Petzold et je me rends compte que tous les programmes sont redessinés via WM_PAINT ont une légère
|
Derniers Blogs
CSS CONTENT STATE SELECTORS (PERSONNAL DRAFT)CSS CONTENT STATE SELECTORS (PERSONNAL DRAFT) par FREMYCOMPANY
Bonjour à tous, Je viens de publier une proposition comprenant 5 pseudo-classes pour le CSS Working Group ayant trait à l'état de chargement d'un élément (ex: IMG,VIDEO,AUDIO,OBJECT pour l'HTML.). Si le c½ur vous en dit, vous pouvez retrouver cette p...
Cliquez pour lire la suite de l'article par FREMYCOMPANY MBA : POURQUOI FAIRE ET COMMENT LE CHOISIR ?MBA : POURQUOI FAIRE ET COMMENT LE CHOISIR ? par ROMELARD Fabrice
Formation initiale Durant la formation, le découpage classique est le suivant (je donnerai les équivalences Suisse lorsque je les connaîtrais) : Ecole primaire jusqu'au Collège : Formation générale permettant d'obtenir les méthodes...
Cliquez pour lire la suite de l'article par ROMELARD Fabrice Y'A DES ERREURS QUI PEUVENT RENDRE LE DéVELOPPEUR VIOLENTY'A DES ERREURS QUI PEUVENT RENDRE LE DéVELOPPEUR VIOLENT par Aleks
Quand on a ce genre d'erreur sans log :
Et bas on a juste envie de choper le gas de Microsoft qu'a développé ça et lui foutre des baffes de Coboye ! ...
Cliquez pour lire la suite de l'article par Aleks [HYPER-V 3] PRéSENTATION DES COMMANDLETS POWERSHELL[HYPER-V 3] PRéSENTATION DES COMMANDLETS POWERSHELL par Pierrick CATRO-BROUILLET
Avec la sortie prochaine de la Beta Consumer Preview de Windows 8, j'avais envie de revenir sur une des fonctionnalités que j'attends le plus et que, en bon geek que je suis, j'utilise déjà : Hyper-V 3 ainsi son module PowerShell.
Il y a déjà pléthor...
Cliquez pour lire la suite de l'article par Pierrick CATRO-BROUILLET IIS7 - COMPRESSION GZIPIIS7 - COMPRESSION GZIP par cyril
La compression GZIP permet d'améliorer les performances de navigation en compressant ce qu'envoie le serveur à un client. Pour comprendre comment cela fonctionne, regardons ce qu'il se passe au niveau HTTP lorsqu'un client tente d'accéder à une ress...
Cliquez pour lire la suite de l'article par cyril
Forum
ARBRE BINAIREARBRE BINAIRE par pacotheking
Cliquez pour lire la suite par pacotheking
Logiciels
Easy-Planning (1.0.0.1)EASY-PLANNING (1.0.0.1)Basé sur les mêmes principes que MyPlanning, Easy-Planning permet de créer des plannings sous la ... Cliquez pour télécharger Easy-Planning Academy System (17.1.3.0)ACADEMY SYSTEM (17.1.3.0)Logiciel de gestion des établissements.
- élèves/étudiants (inscription, dossier, absence...)
-... Cliquez pour télécharger Academy System COLLECTOR PLUS (3.00B)COLLECTOR PLUS (3.00B)COLLECTOR PLUS version 3.00B est un logiciel utilisant une base de données alimentée par :
- L... Cliquez pour télécharger COLLECTOR PLUS PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V7.4)PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO (V7.4)PONAMEDIA TV DEVIENS HELLLOOO FLASH
LA TV SUR VOTRE ORDINATEUR.
Toute une plateforme Multi... Cliquez pour télécharger PONAMEDIA PREMIUM - HELLLOOO FLASH DEMO LettresFaciles 2011 (8.0.0.1)LETTRESFACILES 2011 (8.0.0.1)LettresFaciles est un logiciel facilitant la création et la rédaction de lettres types.
Son inte... Cliquez pour télécharger LettresFaciles 2011
|