Sauvegarde/restauration de la position des icones sur le bureau (win32).

Description

Cet utilitaire permet donc de sauvegarder le nom et la position des icones dans un fichier pour pouvoir les restaurer si besoin (après un plantage ou une réorganisation automatique non désirée, ou bien un changement de résolution.)

Ce programme est basé sur le code donné dans le bouquin de Richter:
http://brunews.free.fr/brunews/download/JR4.zip
http://brunews.free.fr/brunews/download/JR4Sources.zip
Part IV, Chapter 22 : "Injecting a DLL Using Windows Hooks"
Ce code utililise un hook dans une Dll et mon prog ReadProcessMemory et WriteProcessMemory.

Le point sensible est le passage de données entre 2 processus différents (cet utilitaire et le Program Manager).

Source / Exemple :


//***************************************************************************************
// DesktopUtility.cpp :
//
//---------------------------------------------------------------------------------------
// Auteur : Y.M. Morgan.
// Date   : 19/05:2004.
// Projet : "DesktopUtility.exe", utilitaire de sauvegarde et de restauration
//          de la position des icones sur le bureau.
//
//---------------------------------------------------------------------------------------
//
// - Les icones du bureau sont regroupées dans un contrôle ListView. Ce contrôle est le
//   premier "petit-fils" de la fenêtre "ProgMan" (Program manager).
// - Pour récupérer le nom et la position de ces icones il suffit donc d'envoyer le
//   message LV_GETITEMTEXT ou LV_GETITEMPOSITION.
// - Cependant, ces messages nécessitent l'emploi d'un pointeur, et étant donné que cet
//   utilitaire et le contrôle ListView cible ne sont pas dans le même processus, un
//   pointeur dans un des processus n'est pas valide dans l'autre.
// - Pour remédier à ce problème, il faut un moyen d'allouer de la mémoire dans le
//   processus de la ListView et de pouvoir y lire et écrire.
// - Sous Windows 98/ME, la zone au dessus de l'adresse 0x80000000 est partagée par tous
//   les processus, il suffit donc d'y allouer une zone. La fonction CreateFileMapping
//   et MapViewOfFile permet cela.
// - Sous Windows 2000/NT/XP, il suffit d'utiliser la fonction VirtualQueryEx en lui
//   passant un handle du processus cible.
// - Une fois la zone allouée, les fonctions ReadProcessMemory et WriteProcessMemory
//   sont utilisées pour accéder à cette zone.
// - Finalement, les données récupérées sont stockées dans un fichier "*.ini" sous le
//   format : ItemXX="nom de l'icon" x y.
//
//***************************************************************************************

#include <windows.h>
#include <commctrl.h>
#include <shlwapi.h>

#include <stdio.h>
#include <tchar.h>

#include "Resource.h"

//=======================================================================================
// Variables globales.
//=======================================================================================
HINSTANCE	g_hAppInstance		= NULL;	// instance de l'application
HWND		g_hWndMainDialog	= NULL;	// boîte de dialogue principale

//=======================================================================================
// Déclarations des fonctions du module.
//=======================================================================================
static int CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);

static int MsgInitDialog	(HWND, WPARAM, LPARAM);
static int MsgCommand		(WPARAM, LPARAM);

static void CmdBtnSave		();
static void CmdBtnRestore	();

//***************************************************************************************
// WinMain : point d'entrée de l'application.
// entrée : hInstance : instance de l'application.
//          hPrevInstance : instance précédente de l'application (NULL sous Win32).
//          lpCmdLine     : ligne de commande associée au programme.
//          nCmdShow      : indique comment doît être affichée la fenêtre principale.
// retour : code de retour de PostQuitMessage.
//***************************************************************************************
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
				   int nCmdShow)
{
	// sauvegarde instance de l'application, ouverture de la boîte de dialogue
	g_hAppInstance = hInstance;
	DialogBox(g_hAppInstance, MAKEINTRESOURCE(IDD_MAINDIALOG), NULL, DlgProc);
	return 0;
}

//=======================================================================================
// Traitement des messages.
//=======================================================================================

//***************************************************************************************
// DlgProc : procédure de traitement des messages de la boîte de dialogue principale.
// entrée : hDlg   : handle de la boîte de dialogue.
//          uMsg   : message à traiter.
//          wParam : premier paramètre du message.
//          lParam : second paramètre du message.
// retour : dépend du message à traiter.
//***************************************************************************************
int CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	// en fonction du message
	switch(uMsg)
	{
	case WM_INITDIALOG	: return MsgInitDialog	(hDlg, wParam, lParam);
	case WM_COMMAND		: return MsgCommand		(wParam, lParam);
	default : return 0;
	}
}

//***************************************************************************************
// MsgInitDialog : traitement du message WM_INITDIALOG. Initialisation de la boîte de
//                 dialogue.
// entrée : hDlg   : handle de la boîte de dialogue.
//          wParam : premier paramètre du message.
//          lParam : second paramètre du message.
// retour : vrai.
//***************************************************************************************
int MsgInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam)
{
	// sauvegarde handle de la boîte de dialogue
	g_hWndMainDialog = hDlg;

	// affectation icones
	HICON hIcon = LoadIcon(g_hAppInstance, MAKEINTRESOURCE(IDI_APPICON));
	SendMessage(g_hWndMainDialog, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
	SendMessage(g_hWndMainDialog, WM_SETICON, ICON_SMALL, (LPARAM) hIcon);

	// centrage au milieu du bureau
	RECT rcDlg;
	GetWindowRect(g_hWndMainDialog, &rcDlg);
	RECT rcDesktop;
	SystemParametersInfo(SPI_GETWORKAREA, 0, &rcDesktop, 0);
	int x = ((rcDesktop.right-rcDesktop.left)-(rcDlg.right-rcDlg.left))/2;
	int y = ((rcDesktop.bottom-rcDesktop.top)-(rcDlg.bottom-rcDlg.top))/2;
	x += rcDesktop.left;
	y += rcDesktop.top;
	SetWindowPos(g_hWndMainDialog, NULL, x, y, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
	return TRUE;
}

//***************************************************************************************
// MsgCommand : traitement du message WM_COMMAND. Action sur un des contrôles de la
//              boîte de dialogue.
// entrée : wParam : premier paramètre du message.
//          lParam : second paramètre du message.
// retour : vrai si la commande a été traitée, faux sinon.
//***************************************************************************************
int MsgCommand(WPARAM wParam, LPARAM lParam)
{
	// récupération des paramètres
	int nIDCtl = LOWORD(wParam);

	// en fonction de la commande
	switch(nIDCtl)
	{
	case IDC_BTN_SAVE		: CmdBtnSave	();	break;
	case IDC_BTN_RESTORE	: CmdBtnRestore	();	break;

	case IDOK		: EndDialog(g_hWndMainDialog, IDOK);		break;
	case IDCANCEL	: EndDialog(g_hWndMainDialog, IDCANCEL);	break;
	default : return FALSE;
	}

	// la commande a été traitée
	return TRUE;
}

//***************************************************************************************
// CmdBtnSave : action sur le bouton [Sauvegarder], sauvegarde la position des icones
//              sur le bureau.
//***************************************************************************************
void CmdBtnSave()
{
	//-----------------------------------------------------------------------------------
	// récupération plateforme d'exécution
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&osvi);
	if(osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS &&
		osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)
	{
		return;
	}

	//-----------------------------------------------------------------------------------
	// récupération ListView avec les icones du bureau, récupération de son processus
	HWND hWnd = FindWindow(_T("ProgMan"), NULL);
	HWND hListView = GetTopWindow(GetTopWindow(hWnd));
	DWORD dwProcessId;
	GetWindowThreadProcessId(hListView, &dwProcessId);
	DWORD dwAccess = PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE;
	HANDLE hProcess =  OpenProcess(dwAccess, FALSE, dwProcessId);
	if(hProcess == NULL)
		return;

	// allocation d'une chaînes de caractères, d'une stucture LVITEM et d'une structure
	// POINT dans le processus de la listview ou dans la zone partagée (Windows 98)
	DWORD dwSize = sizeof(POINT) + sizeof(LVITEM) + 256*sizeof(TCHAR);
	HANDLE hFileMapping = NULL;
	LPVOID lpData = NULL;

	// Windows 98 : création FileMapping
	if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
	{
		hFileMapping =  CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL,
			PAGE_READWRITE|SEC_COMMIT, 0, dwSize, NULL);
		if(hFileMapping != NULL)
			lpData = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, dwSize);
	}

	// Windows NT : VirtualAllocEx
	if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
	{
		lpData = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
	}

	// en cas d'erreur
	if(lpData == NULL)
	{
		if(hFileMapping != NULL)
			CloseHandle(hFileMapping);
		CloseHandle(hProcess);
		return;
	}

	// affectation des pointeurs
	LPVOID lpPosition	= lpData;
	LPVOID lpItem		= ((LPBYTE) lpData) + sizeof(POINT);
	LPVOID lpText		= ((LPBYTE) lpData) + sizeof(POINT) + sizeof(LVITEM);

	//-----------------------------------------------------------------------------------
	// création nom du fichier d'initialisation
	TCHAR szIniFileName[_MAX_PATH];
	GetModuleFileName(NULL, szIniFileName, _MAX_PATH);
	GetLongPathName(szIniFileName, szIniFileName, _MAX_PATH);
	PathRenameExtension(szIniFileName, _T(".ini"));

	// boucle sur les items de la ListView
	int nItemCount = SendMessage(hListView, LVM_GETITEMCOUNT, 0, 0);
	TCHAR szCount[32];
	wsprintf(szCount, _T("%d"), nItemCount);
	WritePrivateProfileString(_T("Icons"), _T("ItemCount"), szCount, szIniFileName);
	for(int i = 0; i < nItemCount; i++)
	{
		// init structure LVITEM dans une variable locale et recopie dans la zone de
		// mémoire allouée
		LVITEM lvi;
		ZeroMemory(&lvi, sizeof(LVITEM));
		lvi.iItem		= i;
		lvi.iSubItem	= 0;
		lvi.mask		= LVIF_TEXT;
		lvi.pszText		= (LPTSTR) lpText;
		lvi.cchTextMax	= 256;
		WriteProcessMemory(hProcess, lpItem, &lvi, sizeof(LVITEM), NULL);

		// récupération nom et position
		SendMessage(hListView, LVM_GETITEMTEXT, i, (LPARAM) lpItem);
		SendMessage(hListView, LVM_GETITEMPOSITION, i, (LPARAM) lpPosition);

		// recopie dans variables locales
		TCHAR szText[256];
		ReadProcessMemory(hProcess, lpText, szText, 256*sizeof(TCHAR), NULL);
		POINT ptPosition;
		ReadProcessMemory(hProcess, lpPosition, &ptPosition, sizeof(POINT), NULL);

		// ajout de la position et du nom
		TCHAR szKey[256];
		wsprintf(szKey, _T("Item%02d"), i);
		TCHAR szValue[256];
		wsprintf(szValue, _T("\"%s\" %d %d"), szText, ptPosition.x, ptPosition.y);
		WritePrivateProfileString(_T("Icons"), szKey, szValue, szIniFileName);
	}

	//-----------------------------------------------------------------------------------
	// libération mémoire
	if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
	{
		UnmapViewOfFile(lpData);
		CloseHandle(hFileMapping);
	}
	if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
	{
		VirtualFreeEx(hProcess, lpData, 0, MEM_RELEASE);
	}

	// fermeture processus
	CloseHandle(hProcess);
	MessageBox(g_hWndMainDialog, _T("Position des icones sauvegardée"),
				_T("DektopUtility"), MB_ICONINFORMATION);
}

//***************************************************************************************
// CmdBtnRestore : action sur le bouton [Restaurer], resaure la position des icones sur
//                 le bureau.
//***************************************************************************************
void CmdBtnRestore()
{
	//-----------------------------------------------------------------------------------
	// récupération plateforme d'exécution
	OSVERSIONINFO osvi;
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	GetVersionEx(&osvi);
	if(osvi.dwPlatformId!=VER_PLATFORM_WIN32_WINDOWS &&
		osvi.dwPlatformId!=VER_PLATFORM_WIN32_NT)
	{
		return;
	}

	//-----------------------------------------------------------------------------------
	// récupération ListView avec les icones du bureau, récupération de son processus
	HWND hWnd = FindWindow(_T("ProgMan"), NULL);
	HWND hListView = GetTopWindow(GetTopWindow(hWnd));
	DWORD dwProcessId;
	GetWindowThreadProcessId(hListView, &dwProcessId);
	DWORD dwAccess = PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE;
	HANDLE hProcess =  OpenProcess(dwAccess, FALSE, dwProcessId);
	if(hProcess == NULL)
		return;

	// allocation d'une chaînes de caractères, d'une stucture LVFINDINFO dans le
	// processus de la listview ou dans la zone partagée (Windows 98)
	DWORD dwSize = sizeof(LVFINDINFO) + 256*sizeof(TCHAR);
	HANDLE hFileMapping = NULL;
	LPVOID lpData = NULL;

	// Windows 98 : création FileMapping
	if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
	{
		hFileMapping =  CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL,
								PAGE_READWRITE|SEC_COMMIT, 0, dwSize, NULL);
		if(hFileMapping != NULL)
			lpData = MapViewOfFile(hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, dwSize);
	}

	// Windows NT : VirtualAllocEx
	if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
	{
		lpData = VirtualAllocEx(hProcess, NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);
	}

	// en cas d'erreur
	if(lpData == NULL)
	{
		if(hFileMapping != NULL)
			CloseHandle(hFileMapping);
		CloseHandle(hProcess);
		return;
	}

	// affectation des pointeurs
	LPVOID lpItem	= lpData;
	LPVOID lpText	= ((LPBYTE) lpData) + sizeof(LVITEM);

	//-----------------------------------------------------------------------------------
	// création nom du fichier d'initialisation
	TCHAR szIniFileName[_MAX_PATH];
	GetModuleFileName(NULL, szIniFileName, _MAX_PATH);
	GetLongPathName(szIniFileName, szIniFileName, _MAX_PATH);
	PathRenameExtension(szIniFileName, _T(".ini"));

	// si la liste a le style AUTO_ARRANGE, on le vire pendant le positionnement
	DWORD dwStyle = GetWindowLong(hListView, GWL_STYLE);
	if(dwStyle & LVS_AUTOARRANGE) 
		SetWindowLong(hListView, GWL_STYLE, dwStyle & ~LVS_AUTOARRANGE);

	// boucle sur les items sauvegardés
	int nItemCount = GetPrivateProfileInt(_T("Icons"), _T("ItemCount"), 0, szIniFileName);
	for(int i = 0; i < nItemCount; i++)
	{
		// récupération données de l'item
		TCHAR szKey[256];
		wsprintf(szKey, _T("Item%02d"), i);
		TCHAR szValue[256];
		GetPrivateProfileString(_T("Icons"), szKey, _T(""), szValue, 256, szIniFileName);
		
		// récherche nom de l'item entre ""
		TCHAR szText[256];
		if(szValue[0] != '\"')
			continue;
		TCHAR* pEnd = _tcsrchr(szValue, '\"');
		if(pEnd == NULL)
			continue;

  • pEnd = '\0';
_tcscpy(szText, szValue + 1); WriteProcessMemory(hProcess, lpText, szText, 256 * sizeof(TCHAR), NULL); // recherche de l'item dans la ListView LVFINDINFO lvfi; ZeroMemory(&lvfi, sizeof(LVFINDINFO)); lvfi.flags = LVFI_STRING; lvfi.psz = (LPTSTR) lpText; WriteProcessMemory(hProcess, lpItem, &lvfi, sizeof(LVFINDINFO), NULL); int index = SendMessage(hListView, LVM_FINDITEM, -1, (LPARAM) lpItem); if(index == -1) continue; // position TCHAR* pStart = pEnd+1; while(*pStart == ' ') pStart++; int x = _ttoi(pStart); while(*pStart != ' ' && *pStart != '\0') pStart++; while(*pStart == ' ') pStart++; int y = _ttoi(pStart); SendMessage(hListView, LVM_SETITEMPOSITION, index, MAKELPARAM(x, y)); } // on remet l'ancien style SetWindowLong(hListView, GWL_STYLE, dwStyle); //----------------------------------------------------------------------------------- // libération mémoire if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { UnmapViewOfFile(lpData); CloseHandle(hFileMapping); } if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) { VirtualFreeEx(hProcess, lpData, 0, MEM_RELEASE); } // fermeture processus CloseHandle(hProcess); MessageBox(g_hWndMainDialog, _T("Position des icones restaurée"), _T("DektopUtility"), MB_ICONINFORMATION); }

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.