[c++] [win32 api] ado pour les nouveaux

Description

Un petit tutorial:

Source / Exemple :


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)

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.