Introduction :
Les boîtes de dialogues communes sont celles qui font partie de Windows,
comme les boîtes de dialogue d'ouverture ou de sauvegarde de fichier,
de choix de polices de caractères, de choix de couleurs...
Dans ce premier exemple nous metterons en oeuvre la boîte de
dialogue d'ouverture de fichiers. Le principe est semblable pour les autres
boîtes de dialogue.
Préparation de l'exemple :
Nous continuons sur la base de l'exemple du
chapitre précédent.
Nous ajoutons une option avec le texte "Ouvrir..." plus
un séparateur au sous-menu. L'option "Ouvrir..." sera identifiée par la constante
IDM_OPEN :
#define IDM_QUIT 1
#define IDM_OPEN 2
hSousMenu = CreateMenu();
AppendMenu(hSousMenu, MF_STRING, IDM_OPEN, "Ouvrir...");
AppendMenu(hSousMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hSousMenu, MF_STRING, IDM_QUIT, "Quitter");
Comme vu au chapitre précédent,
son action sera interceptée dans la procédure de fenêtre avec un message WM_COMMAND :
switch (uMsg)
{
case WM_COMMAND:
if(LOWORD(wParam) == IDM_OPEN)
{
/* Appel de la boîte de dialogue ici. */
La boîte de dialogue commune :
Avant d'appeler une boîte de dialogue commune, nous devont remplir une
structure de données la concernant. Elle sera passée comme paramètre à la fonction
d'appel.
Dans le cas de la boîte de dialogue destinée à l'ouverture de fichiers
la structure se nomme OPENFILENAME :
OPENFILENAME ofn;
CHAR szFile[MAX_PATH]={0};
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFilter =
"Fichier source C\0*.c\0Fichier source CPP\0*.cpp\0";
ofn.nFilterIndex = 1;
ofn.Flags =
OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
Nous déclarons donc en premier lieu une variable du type de cette structure : ofn.
Comme nous allons remplir seulement les champs qui nous intéressent,
nous metterons la totalité de la structure à zéro. Ceci étant effectué en
une seule opération par l'appel de la fonction ZeroMemory.
Ensuite, nous affectons son champ lpstrFile avec l'adresse d'un tableau
de caractères que nous avons préalablement défini,
pour y récupérer le nom et le chemin du fichier. Attention, il doit
contenir une chaine valide avant l'appel de la fonction, car elle l'utilise aussi
pour initialiser le champ d'édition : "Nom du fichier" de la boîte de dialogue.
Le champ lStructSize doit recevoir la taille de la structure.
Le champ hwndOwner le handle de la fenêtre parent.
Le champ nMaxFile la taille du tableau de caractère recevant le nom du fichier.
Le champ lpstrFilter avec l'adresse d'un tableau de caractère
contenant des filtres de fichiers par leur extention.
Les textes des filtres et les filtres étant séparés par des caractères null et le tableau ce terminant
par deux caractères null (ce type de tableau de caractères est assez fréquent dans Windows).
Le champ nFilterIndex avec l'index du filtre que l'on désire afficher dans le
champ d'édition "Fichier de type" à l'ouverture de la boîte de dialogue.
Le champ Flags avec différentes constantes qui influence sur son aspect
ou ses fonctionnalités (voir l'aide API Win32).
Une fois les champs de la structure correctement rempli, nous appelons
la fonction GetOpenFileName avec l'adresse de la structure précédement rempli comme
paramètre. Si elle nous retourne la valeur TRUE, ce qui indique que l'utilisateur
à fermé la boîte de dialogue avec le bouton "Ouvrir", nous pourons récupérer
le nom et chemin du fichier sélectionné dans le buffer szFile afin de charger le fichier.
if (GetOpenFileName(&ofn)==TRUE)
{
HANDLE hf;
DWORD FileSize,nbcharRead ;
CHAR *buffer;
hf = CreateFile(szFile, GENERIC_READ, 0,NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
FileSize = GetFileSize(hf, NULL);
buffer = (PCHAR)LocalAlloc(LMEM_FIXED, FileSize+1);
ReadFile(hf, buffer, FileSize, &nbcharRead, NULL) ;
buffer[FileSize] = 0;
SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)buffer);
LocalFree(buffer);
CloseHandle(hf);
}
Connaissant maintenant le nom et le chemin du fichier,
nous allons l'ouvrir avec la fonction de Windows CreateFile
qui retourne un handle de fichier. Je vous invite à consuler l'aide API Win32 pour
plus de détails sur cette fonction qui offre de nombreuses possibilités.
Nous récupérons la taille du fichier avec la fonction GetFileSize.
Nous créons un buffer de la taille du fichier + 1 octet
avec la fonction de Windows LocalAlloc.
Nous remplissons ce buffer avec le contenu du fichier à l'aide de la fonction ReadFile.
Comme c'est un fichier texte nous ajoutons le zéro terminal au dernier élément du
buffer pour en faire une chaîne de caractères.
Nous la copions dans le champs d'édition multi lignes,
en lui envoyant un message WM_SETTEXT avec l'adresse du buffer comme dernier
paramètre de SendMessage. Pour terminer, nous libérons la mémoire avec
la fonction LocalFree et fermons le fichier avec la fonction CloseHandle.
Code complet :
#include <windows.h>
#define IDM_QUIT 1
#define IDM_OPEN 2
HINSTANCE hinst;
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
HWND hwnd;
MSG msg;
WNDCLASS wc;
HMENU hMenu, hSousMenu;
hinst = hinstance;
wc.style = 0 ;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "MaWinClass";
if(!RegisterClass(&wc)) return FALSE;
hSousMenu = CreateMenu();
AppendMenu(hSousMenu, MF_STRING, IDM_OPEN, "Ouvrir...");
AppendMenu(hSousMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hSousMenu, MF_STRING, IDM_QUIT, "Quitter");
hMenu = CreateMenu();
AppendMenu(hMenu,MF_POPUP,(UINT)hSousMenu,"Fichier");
hwnd = CreateWindow("MaWinClass", "Titre", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 300,
NULL, hMenu, hinstance, NULL);
if (!hwnd) return FALSE;
ShowWindow(hwnd, nCmdShow);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
/******************************************************************************/
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hEdit;
static BOOL EditNotChg = TRUE;
switch (uMsg)
{
case WM_CREATE:
{
HFONT hFont;
hEdit = CreateWindow("edit", "Texte", WS_CHILD | WS_VISIBLE |
ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL,
0, 0, 0, 0, hwnd, NULL, hinst, NULL);
hFont = (HFONT)GetStockObject(ANSI_FIXED_FONT);
SendMessage(hEdit,WM_SETFONT,(UINT)hFont,TRUE);
SendMessage(hEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
MAKELONG(5, 5));
return 0;
}
case WM_CLOSE:
if(EditNotChg ||
MessageBox(hwnd,"Le texte a été modifié.\r\nEtes vous sûr de \
vouloir fermer l'application ?"
,"Question ?",MB_YESNO | MB_ICONQUESTION ) == IDYES)
DestroyWindow(hwnd);
return 0;
case WM_COMMAND:
if(LOWORD(wParam) == IDM_OPEN)
{
OPENFILENAME ofn;
CHAR szFile[MAX_PATH]={0};
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFilter =
"Fichier source C\0*.c\0Fichier source CPP\0*.cpp\0";
ofn.nFilterIndex = 1;
ofn.Flags =
OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
if (GetOpenFileName(&ofn)==TRUE)
{
HANDLE hf;
DWORD FileSize,nbcharRead ;
CHAR *buffer;
hf = CreateFile(szFile, GENERIC_READ, 0,NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
FileSize = GetFileSize(hf, NULL);
buffer = (PCHAR)LocalAlloc(LMEM_FIXED, FileSize+1);
ReadFile(hf, buffer, FileSize, &nbcharRead, NULL) ;
buffer[FileSize] = 0;
SendMessage(hEdit, WM_SETTEXT, 0, (LPARAM)buffer);
LocalFree(buffer);
CloseHandle(hf);
}
}
if(LOWORD(wParam) == IDM_QUIT) PostMessage(hwnd, WM_CLOSE,0,0);
if(HIWORD(wParam) == EN_CHANGE) EditNotChg = FALSE;
return 0;
case WM_SIZE:
MoveWindow(hEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
En annexe voici 3 autres boîtes de dialogue commune :
-
La boîte de dialogue de sauvegarde.
-
La boîte de dialogue de choix de police de caractères.
-
La boîte de dialogue de choix de couleur.
J'ai testé les compilations avec C++ Builder 4 (Win 95), C++ Builder 6 (Win XP), et DevC++ (Win XP).
Remarques :
Compilé avec BCB6, la boîte de dialogue ne s'ouvrait pas si le
programme était exécuté sous une plateforme Win95.
Une erreur CDERR_STRUCTSIZE était retourné.
Aprés une recherche sur le Web, j'ai trouvé que les compilations faite pour Win 2000
pouvait causer ce problème si les fichier header de Windows était recent.
Je n'ai pas eu ce problème avec DevC++ avec une compilation sous Win XP.
La solution pour parrer à ce problème est d'intitaliser
le champs lStructSize de la structure OPENFILENAME avec la constante :
OPENFILENAME_SIZE_VERSION_400.
ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
Voir une compilation conditionnelle :
#ifdef OPENFILENAME_SIZE_VERSION_400
ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
#else
ofn.lStructSize = sizeof(OPENFILENAME);
#endif
A tester selon vos configuration.
A vos PC.
CGi
Avec la contribution de nico-pyright(c) pour la relecture.
|