#include "StdAfx.h"
#include "rejestr.h"

CRejestr::CRejestr(HKEY kluczGlowny,REGSAM trybDostepu,bool wyswietlajKomunikatyOBledach)
   :uchwytKlucza(NULL),kluczGlowny(kluczGlowny),trybDostepu(trybDostepu),wyswietlajKomunikatyOBledach(wyswietlajKomunikatyOBledach)
{
}

CRejestr::~CRejestr(void)
{
	if(uchwytKlucza!=NULL) ZamknijKlucz();
}

void CRejestr::WyswietlKomunikatBledu(LONG numerBledu) const
{
	if(!wyswietlajKomunikatyOBledach) return;
	wchar_t* komunikat;
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
				   NULL, numerBledu, 0, (LPWSTR)&komunikat, 0, NULL);	
	MessageBox(NULL,komunikat,L"Błąd podczas operacji na rejestrach",MB_OK | MB_ICONERROR);
	LocalFree(komunikat);
}

#pragma region Metody dotyczace kluczy
bool CRejestr::UtworzKlucz(const wchar_t* klucz)
{
	LONG numerBledu = RegCreateKeyEx(kluczGlowny,klucz,NULL,0,REG_OPTION_NON_VOLATILE,trybDostepu,NULL,&uchwytKlucza,NULL);
	if (numerBledu != ERROR_SUCCESS) WyswietlKomunikatBledu(numerBledu);
	return numerBledu == ERROR_SUCCESS;
}

bool CRejestr::OtworzKlucz(const wchar_t* klucz)
{
	if(uchwytKlucza!=NULL)
	{
		if (wyswietlajKomunikatyOBledach) MessageBox(NULL,L"Przed otwarciem nowego klucza, zamknij klucz otwarty wczesniej",L"Błąd otwarcia klucza",MB_OK);
		return false;
	}
	LONG numerBledu = RegOpenKeyEx(kluczGlowny,klucz,0,trybDostepu,&uchwytKlucza);
	if (numerBledu != ERROR_SUCCESS) WyswietlKomunikatBledu(numerBledu);	
	return numerBledu == ERROR_SUCCESS;
}

bool CRejestr::ZamknijKlucz()
{
	LONG numerBledu = RegCloseKey(uchwytKlucza);
	if (numerBledu != ERROR_SUCCESS) WyswietlKomunikatBledu(numerBledu);	
	else uchwytKlucza = NULL;
	return numerBledu == ERROR_SUCCESS;
}

bool CRejestr::UsunKlucz(const wchar_t* klucz)
{
	LONG numerBledu = RegDeleteKey(kluczGlowny,klucz);	
	if (numerBledu != ERROR_SUCCESS) WyswietlKomunikatBledu(numerBledu);	
	else klucz=NULL;
	return numerBledu == ERROR_SUCCESS;
}

bool CRejestr::CzyKluczIstnieje(const wchar_t* klucz) const
{
	HKEY lokalnyUchwytKlucza;
	bool wynik = RegOpenKeyEx(kluczGlowny,klucz,0,trybDostepu,&lokalnyUchwytKlucza) == ERROR_SUCCESS;
	RegCloseKey(lokalnyUchwytKlucza);
	return wynik;
}

bool CRejestr::OtworzKlucz(const wchar_t* klucz,bool utworzJezeliNieIstnieje)
{
	if(CzyKluczIstnieje(klucz)) return OtworzKlucz(klucz);
	else
	{
		if(!utworzJezeliNieIstnieje) return false;
		else return UtworzKlucz(klucz);
	}
}
#pragma endregion

#pragma region Metody dotyczace wartosci
#include <stdexcept>

bool CRejestr::CzyWartoscIstnieje(const wchar_t* nazwa) const
{
	DWORD rozmiar = 1024;
	unsigned char bufor[1024];
	LONG numerBledu = RegQueryValueEx(uchwytKlucza,nazwa,NULL,NULL,bufor,&rozmiar);
	if (numerBledu != ERROR_SUCCESS && numerBledu != ERROR_FILE_NOT_FOUND) WyswietlKomunikatBledu(numerBledu);	
	return numerBledu == ERROR_SUCCESS;
}

bool CRejestr::UsunWartosc(const wchar_t* nazwa) const
{
	LONG numerBledu = RegDeleteValue(uchwytKlucza,nazwa);
	if (numerBledu != ERROR_SUCCESS) WyswietlKomunikatBledu(numerBledu);	
	return numerBledu == ERROR_SUCCESS;
}

int CRejestr::CzytajInt(const wchar_t* nazwa) const
{
	int wartosc;
	DWORD rozmiar;
	LONG numerBledu = RegQueryValueEx(uchwytKlucza,nazwa,NULL,NULL,(LPBYTE)&wartosc,&rozmiar);
	if (numerBledu != ERROR_SUCCESS) 
	{
		WyswietlKomunikatBledu(numerBledu);
		throw std::exception("Odczyt wartości nie powiódł się");
	}
	return wartosc;
}

bool CRejestr::ZapiszInt(const wchar_t* nazwa,int wartosc) const
{
	LONG numerBledu = RegSetValueEx(uchwytKlucza,nazwa,0,REG_DWORD,(LPBYTE)&wartosc,sizeof(wartosc));
	if (numerBledu != ERROR_SUCCESS) WyswietlKomunikatBledu(numerBledu);	
	return numerBledu == ERROR_SUCCESS;
}

wchar_t* CRejestr::CzytajString(const wchar_t* nazwa,wchar_t* wartosc) const
{   
	DWORD rozmiar = 1024;
	LONG numerBledu = RegQueryValueEx(uchwytKlucza,nazwa,NULL,NULL,(LPBYTE)wartosc,&rozmiar);
	if (numerBledu != ERROR_SUCCESS) 
	{
		WyswietlKomunikatBledu(numerBledu);
		throw std::exception("Odczyt wartości nie powiódł się");
	}
	return wartosc;
}

bool CRejestr::ZapiszString(const wchar_t* nazwa,const wchar_t* wartosc) const
{
	DWORD rozmiar = (wcslen(wartosc)+1)*sizeof(wchar_t);
	LONG numerBledu = RegSetValueEx(uchwytKlucza,nazwa,0,REG_SZ,(LPBYTE)wartosc,rozmiar);
	if (numerBledu != ERROR_SUCCESS) WyswietlKomunikatBledu(numerBledu);	
	return numerBledu == ERROR_SUCCESS;
}
#pragma endregion

#pragma region Przechowywanie położenia i rozmiaru okna
bool CzytajPolozenieIWielkoscOknaZRejestru(HWND uchwytOkna,const wchar_t* klucz)
{
	bool wynik=false;
	int left,top,width,height;
	//wchar_t tytul[1024];

	CRejestr rejestr(HKEY_CURRENT_USER,KEY_READ,true);
	if(!rejestr.CzyKluczIstnieje(klucz)) return false;
	if(rejestr.OtworzKlucz(klucz))
	{		
		try
		{
			left = rejestr.CzytajInt(L"Left");
			top = rejestr.CzytajInt(L"Top");
			width = rejestr.CzytajInt(L"Width");
			height = rejestr.CzytajInt(L"Height");			
			MoveWindow(uchwytOkna,left,top,width,height,TRUE);
			//rejestr.CzytajString(L"Tytul",tytul);
			//SetWindowText(uchwytOkna,tytul);
			wynik=true;	
		}
		catch(...)
		{
			MessageBox(NULL,L"Odczytanie położenia i wartości okna nie powiodło się",L"Błąd podczas odczytu położenia okna z rejestru",MB_OK);
			wynik=false;
		}
		
		rejestr.ZamknijKlucz();
	}
	
	return wynik;
}

void ZapiszPolozenieIWielkoscOknaWRejestrze(HWND uchwytOkna,const wchar_t* klucz)
{
	wchar_t tytul[1024];
	GetWindowText(uchwytOkna,tytul,1024);

	CRejestr rejestr(HKEY_CURRENT_USER,KEY_WRITE,true);
	if(!rejestr.CzyKluczIstnieje(klucz)) rejestr.UtworzKlucz(klucz);
	if(rejestr.OtworzKlucz(klucz))
	{
		CRect rect;
		GetWindowRect(uchwytOkna,&rect);
		rejestr.ZapiszInt(L"Left",rect.left);
		rejestr.ZapiszInt(L"Top",rect.top);
		rejestr.ZapiszInt(L"Width",rect.Width());
		rejestr.ZapiszInt(L"Height",rect.Height());
		//rejestr.ZapiszString(L"Tytul",tytul);
		rejestr.ZamknijKlucz();
	}
}
#pragma endregion

#pragma region Autostart
enum CAutostartCzynnosci {acSprawdz=0,acZapisz=1,acUsun=2};

bool KonfigurujAutostart(HKEY kluczGlowny,const wchar_t* nazwa,const wchar_t* sciezkaPliku,CAutostartCzynnosci czynnosc)
{
	const wchar_t klucz[]=L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
	bool wynik=false;

	CRejestr rejestr(kluczGlowny,(czynnosc==acSprawdz)?KEY_READ:KEY_WRITE);
	if(!rejestr.CzyKluczIstnieje(klucz))
	{
		MessageBox(NULL,L"Klucz nie istnieje",L"Błąd podczas operacji na rejestrach autostartu",MB_ICONERROR);
		return false;
	}
	
	if(rejestr.OtworzKlucz(klucz))
	{
		switch (czynnosc)
		{
			case acSprawdz: wynik = rejestr.CzyWartoscIstnieje(nazwa); break;
			case acZapisz:  wynik = rejestr.ZapiszString(nazwa,sciezkaPliku); break;
			case acUsun:    wynik = rejestr.UsunWartosc(nazwa); break;
		}
		rejestr.ZamknijKlucz();
		//if (czynnosc!=acSprawdz) wynik=true;
	}
	
	return wynik;
}

bool CzyIstniejeZapisAutostart(HKEY kluczGlowny,const wchar_t* nazwa)
{
	return KonfigurujAutostart(kluczGlowny,nazwa,L"",acSprawdz);
}

bool ZapiszAutostart(HKEY kluczGlowny,const wchar_t* nazwa,const wchar_t* sciezkaPliku)
{
	return KonfigurujAutostart(kluczGlowny,nazwa,sciezkaPliku,acZapisz);
}

bool UsunAutostart(HKEY kluczGlowny,const wchar_t* nazwa)
{
	return KonfigurujAutostart(kluczGlowny,nazwa,L"",acUsun);
}
#pragma endregion

#pragma region Dodaj/Usun
enum CDodajUsunCzynnosci {ducSprawdz=0,ducZapisz=1,ducUsun=2};

bool KonfigurujDodajUsun(const wchar_t* nazwaKlucza,CDodajUsunInfo rekord,CDodajUsunCzynnosci czynnosc)
{
	const int rozmiar=1024;
	wchar_t klucz[rozmiar]=L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";

	bool wynik=false;

	CRejestr rejestr(HKEY_LOCAL_MACHINE,KEY_ALL_ACCESS,true);
	if (!rejestr.CzyKluczIstnieje(klucz)) 
	{
		MessageBox(NULL,L"W rejestrze nie ma klucza przechowującego informacje o instalacji aplikacji",L"Błąd",MB_OK | MB_ICONERROR);
		return false;
	}
	
	wcscat_s(klucz,rozmiar,L"\\");
	wcscat_s(klucz,rozmiar,nazwaKlucza);
	bool kluczAplikacjiIstnieje=rejestr.CzyKluczIstnieje(klucz);
	if (czynnosc==ducSprawdz) return kluczAplikacjiIstnieje;

	if (kluczAplikacjiIstnieje)
	{
		switch (czynnosc)
		{
			case ducZapisz: wynik=false; break;
			case ducUsun: wynik=rejestr.UsunKlucz(klucz);	break;
		}		
	}
	else
	{
		switch (czynnosc)
		{
			case ducZapisz: 
				wynik=rejestr.UtworzKlucz(klucz);
				if (wynik)
				{
					//pola wymagane
					if (rekord.DisplayName!=L"") rejestr.ZapiszString(L"DisplayName",rekord.DisplayName);
					else throw std::exception("Pole \"DisplayName\" musi zawierać nazwę aplikacji.");
					if (rekord.UninstallString!=L"") rejestr.ZapiszString(L"UninstallString",rekord.UninstallString);
					else throw std::exception("Pole \"UninstallString\" musi zawierać ścieżkę do pliku instalatora.");
					//pola opcjonalne
					if (rekord.DisplayIcon!=L"") rejestr.ZapiszString(L"DisplayIcon",rekord.DisplayIcon);
					if (rekord.DisplayVersion!=L"") rejestr.ZapiszString(L"DisplayVersion",rekord.DisplayVersion);
					if (rekord.Contact!=L"") rejestr.ZapiszString(L"Contact",rekord.Contact);
					if (rekord.Publisher!=L"") rejestr.ZapiszString(L"Publisher",rekord.Publisher);
					if (rekord.Comments!=L"") rejestr.ZapiszString(L"Comments",rekord.Comments);
					if (rekord.URLUpdateInfo!=L"") rejestr.ZapiszString(L"URLUpdateInfo",rekord.URLUpdateInfo);
					if (rekord.URLInfoAbout!=L"") rejestr.ZapiszString(L"URLInfoAbout",rekord.URLInfoAbout);
					if (rekord.InstallLocation!=L"") rejestr.ZapiszString(L"InstallLocation",rekord.InstallLocation);
					if (rekord.InstallSource!=L"") rejestr.ZapiszString(L"InstallSource",rekord.InstallSource);
					if (rekord.ProductID!=L"") rejestr.ZapiszString(L"ProductID",rekord.ProductID);
					if (rekord.UninstallPath!=L"") rejestr.ZapiszString(L"UninstallPath",rekord.UninstallPath);
					if (rekord.ModifyPath!=L"") rejestr.ZapiszString(L"ModifyPath",rekord.ModifyPath);
					if (rekord.Readme!=L"") rejestr.ZapiszString(L"Readme",rekord.Readme);
					if (rekord.HelpLink!=L"") rejestr.ZapiszString(L"HelpLink",rekord.HelpLink);
					if (rekord.HelpTelephone!=L"") rejestr.ZapiszString(L"HelpTelephone",rekord.HelpTelephone);
					if (rekord.RegCompany!=L"") rejestr.ZapiszString(L"RegCompany",rekord.RegCompany);
					if (rekord.RegOwner!=L"") rejestr.ZapiszString(L"RegOwner",rekord.RegOwner);
					if (rekord.LogFile!=L"") rejestr.ZapiszString(L"LogFile",rekord.LogFile);
					if (rekord.VersionMajor!=-1) rejestr.ZapiszInt(L"VersionMajor",rekord.VersionMajor);
					if (rekord.VersionMinor!=-1) rejestr.ZapiszInt(L"VersionMinor",rekord.VersionMinor);
					if (rekord.NoRemove!=-1) rejestr.ZapiszInt(L"NoRemove",rekord.NoRemove);
					if (rekord.NoRepair!=-1) rejestr.ZapiszInt(L"NoRepair",rekord.NoRepair);
					if (rekord.Language!=-1) rejestr.ZapiszInt(L"Language",rekord.Language);
					rejestr.ZamknijKlucz();
				}
				break;
			case ducUsun: wynik=false; break;
		}
	}
	return wynik;
}

bool CzyIstniejeZapisDodajUsun(const wchar_t* nazwaKlucza)
{
	CDodajUsunInfo rekord;
	return KonfigurujDodajUsun(nazwaKlucza,rekord,ducSprawdz);
}

bool ZapiszDodajUsun(const wchar_t* nazwaKlucza,CDodajUsunInfo rekord)
{
	return KonfigurujDodajUsun(nazwaKlucza,rekord,ducZapisz);
}

bool UsunDodajUsun(const wchar_t* nazwaKlucza)
{
	CDodajUsunInfo rekord;	
	return KonfigurujDodajUsun(nazwaKlucza,rekord,ducUsun);
}
#pragma endregion

#pragma region Katalogi specjalne uzytkownika
wchar_t* PobierzSciezkeDoKataloguSpecjalnego(const wchar_t* nazwa,wchar_t* katalog)
{
	const wchar_t klucz[]=L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders";
	
	CRejestr rejestr(HKEY_CURRENT_USER,KEY_READ,true);
	if (rejestr.OtworzKlucz(klucz))
	{
		if (rejestr.CzyWartoscIstnieje(nazwa)) rejestr.CzytajString(nazwa,katalog);
		else throw std::exception("Wartosc nie istnieje");
		rejestr.ZamknijKlucz();
	}
	else throw std::exception("Klucz nie istnieje lub nie może być otwarty");
	return katalog;
}

wchar_t* PobierzSciezkeDoKataloguMojeDokumenty(wchar_t* katalog)
{
	return PobierzSciezkeDoKataloguSpecjalnego(L"Personal",katalog);
}
#pragma endregion

#pragma region Nowa komenda dla zarejestrowanego pliku
void RozszerzMenuKontekstoweIstniejacegoTypuPliku(const wchar_t* rozszerzenie,const wchar_t* polecenie,const wchar_t* opis)
{
	const int DLG_NAZW=256;
	CRejestr rejestr(HKEY_CLASSES_ROOT,KEY_ALL_ACCESS);

	//Odczytywanie nazwy typu pliku
	wchar_t _rozszerzenie[DLG_NAZW];
	if(rozszerzenie[0]!='.') wcscpy_s(_rozszerzenie,DLG_NAZW,L".");
	wcscat_s(_rozszerzenie,DLG_NAZW,rozszerzenie);
	wchar_t nazwa[DLG_NAZW];
	if (rejestr.OtworzKlucz(_rozszerzenie))
	{
		rejestr.CzytajString(L"",nazwa);
		rejestr.ZamknijKlucz();
	}
	else throw std::exception("Rozszerzenie nie jest zarejestrowane");

	//Czy polecenie jest juz zdefiniowane
	wchar_t klucz[DLG_NAZW];
	wcscpy_s(klucz,DLG_NAZW,nazwa);
	wcscat_s(klucz,DLG_NAZW,L"\\shell\\");
	wcscat_s(klucz,DLG_NAZW,polecenie);
	if (rejestr.CzyKluczIstnieje(klucz)) throw std::exception("Polecenie jest już zdefiniowane");

	//Tworzenie klucza dla polecenia
	if (rejestr.UtworzKlucz(klucz))
	{
		rejestr.ZapiszString(L"",opis);
		rejestr.ZamknijKlucz();

		wcscat_s(klucz,DLG_NAZW,L"\\Command");
		if (rejestr.UtworzKlucz(klucz))
		{
			wchar_t sciezkaPliku[MAX_PATH];
			GetModuleFileName(NULL,sciezkaPliku,DLG_NAZW);
			wchar_t polecenie[DLG_NAZW];
			wcscpy_s(polecenie,DLG_NAZW,L"\"");
			wcscat_s(polecenie,DLG_NAZW,sciezkaPliku);
			wcscat_s(polecenie,DLG_NAZW,L"\" \"%1\"");
			rejestr.ZapiszString(L"",polecenie);
			rejestr.ZamknijKlucz();
		}
		else throw std::exception("Utworzenie podklucza Command nie jest możliwe");
	}
	else throw std::exception("Utworzenie klucza nie jest możliwe");
}
#pragma endregion