Hi!
This is the First Commandment of portable software, isn't it? Well, may be Second. But any way, at the top of Ten Commandments.
While testing some apps on BetaTesting forum (and my own one, nobody is absolute :)), I noticed that many of them left traces in registry, in very common places like OpenWithList, MRUCache and so on. As for me, I just forgot to call the cleaning procedure after adding some new features to my app.
So I had to write a couple of function to keep the registry clean after program's exit and thought they might be helpful for somebody else. They will just clean the most common places from any record of your program. Here you are:
//I just did not succeed to insert angle brackets for include, //because of HTML, not because I'm geek :). #include windows.h #include shlwapi.h //*********** cleans Software\Microsoft\Windows\ShellNoRoam\MUICache *********** void CleanRegMUICache(const char * lpcProgName){ HKEY hKey; //main key LONG result; //result DWORD index = 0; //index DWORD cb = 512; //buffer size char szValue[512]; //buffer //open main key result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache", 0, KEY_ALL_ACCESS, &hKey); if(result == ERROR_SUCCESS){ //loop through values result = RegEnumValue(hKey, index, szValue, &cb, NULL, NULL, NULL, NULL); while(result == ERROR_SUCCESS){ //if there is our program name in value name - delete this value if(strstr(szValue, lpcProgName)){ RegDeleteValue(hKey, szValue); break; } //increase index index++; //reset size, since it has been changed in previous function call cb = 512; //loop result = RegEnumValue(hKey, index, szValue, &cb, NULL, NULL, NULL, NULL); } //close main key RegCloseKey(hKey); } } //*********** cleans Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU ********** void CleanRegMRU(const char * lpcProgName){ HKEY hKey; //main key LONG result; //result DWORD index = 0; //index DWORD cb = 512, cbValue = 512; //buffers sizes char szValue[512]; //buffer char szBuffer[512]; //buffer //open main key result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU", 0, KEY_ALL_ACCESS, &hKey); if(result == ERROR_SUCCESS){ //loop through values result = RegEnumValue(hKey, index, szValue, &cb, NULL, NULL, NULL, NULL); while(result == ERROR_SUCCESS){ //increase index index++; //get value's data if(RegQueryValueEx(hKey, szValue, NULL, NULL, szBuffer, &cbValue) == ERROR_SUCCESS){ if(strstr(szBuffer, lpcProgName)){ //if value's data contains our program name - delete this value RegDeleteValue(hKey, szValue); //return index back index--; } } //reset sizes, since they are changed in previous functions calls cbValue = 512; cb = 512; //loop result = RegEnumValue(hKey, index, szValue, &cb, NULL, NULL, NULL, NULL); } //close main key RegCloseKey(hKey); } } //*********** cleans Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts *********** void CleanRegOpenWithList(const char * lpcProgName){ HKEY hKey; //main key HKEY hKeyExt; //extention key HKEY hKeyOpen; //extension subkey LONG result, resultExt, resultOpen; //results DWORD index = 0, indexExt, indexOpen; //indexes DWORD cb = 512, cbO = 512; //buffers sizes DWORD cbValueExt = 512, cbValueOpen; //buffers sizes char szValue[512], szValueExt[512]; //buffers char szValueOpen[512], szBuffer[512]; //buffers //open FileExts key result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts", 0, KEY_ALL_ACCESS, &hKey); if(result == ERROR_SUCCESS){ //check each extension result = RegEnumKeyEx(hKey, index, szValue, &cb, NULL, NULL, NULL, NULL); while(result == ERROR_SUCCESS){ //open extension key if(RegOpenKeyEx(hKey, szValue, 0, KEY_ALL_ACCESS, &hKeyExt) == ERROR_SUCCESS){ indexExt = 0; //check each subkey of extension; usually includes OpenWithList and/or OpenWithProgids resultExt = RegEnumKeyEx(hKeyExt, indexExt, szValueExt, &cbValueExt, NULL, NULL, NULL, NULL); while(resultExt == ERROR_SUCCESS){ //increase index indexExt++; //open each subkey if(RegOpenKeyEx(hKeyExt, szValueExt, 0, KEY_ALL_ACCESS, &hKeyOpen) == ERROR_SUCCESS){ indexOpen = 0; //check all subkey values resultOpen = RegEnumValue(hKeyOpen, indexOpen, szValueOpen, &cbValueOpen, NULL, NULL, NULL, NULL); while(resultOpen == ERROR_SUCCESS){ //increase index indexOpen++; //get value's data if(RegQueryValueEx(hKeyOpen, szValueOpen, NULL, NULL, szBuffer, &cbO) == ERROR_SUCCESS){ if(strstr(szBuffer, lpcProgName)){ //if there is our program name in value's data - delete this value RegDeleteValue(hKeyOpen, szValueOpen); //empty buffer szBuffer[0] = '\0'; //return index one position back, in order not to miss the next value indexOpen--; } } //restore default sizes, since they are changed in previous functions calls cbO = 512; cbValueOpen = 512; //loop resultOpen = RegEnumValue(hKeyOpen, indexOpen, szValueOpen, &cbValueOpen, NULL, NULL, NULL, NULL); } //close subkey RegCloseKey(hKeyOpen); } //restore default size, since it is changed in previous functions calls cbValueExt = 512; //loop resultExt = RegEnumKeyEx(hKeyExt, indexExt, szValueExt, &cbValueExt, NULL, NULL, NULL, NULL); } //close extension subkey RegCloseKey(hKeyExt); } //increase index index++; //restore default size, since it is changed in previous functions calls cb = 512; //loop result = RegEnumKeyEx(hKey, index, szValue, &cb, NULL, NULL, NULL, NULL); } //close main key RegCloseKey(hKey); } } //*********** cleans Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSaveMRU *********** void CleanRegOpenSaveMRU(const char * lpcProgName){ HKEY hKey; //main key HKEY hKeyExt; //extention key LONG result, resultExt; //results DWORD index = 0, indexExt = 0; //indexes DWORD cb = 512, cbO = 512; //buffers sizes DWORD cbValueExt = 512; //buffers sizes char szValue[512], szValueExt[512]; //buffers char szBuffer[512]; //buffers //open ComDlg32\OpenSaveMRU key result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\OpenSaveMRU", 0, KEY_ALL_ACCESS, &hKey); if(result == ERROR_SUCCESS){ //check each extension resultExt = RegEnumKeyEx(hKey, indexExt, szValueExt, &cbValueExt, NULL, NULL, NULL, NULL); while(resultExt == ERROR_SUCCESS){ //open extension key if(RegOpenKeyEx(hKey, szValueExt, 0, KEY_ALL_ACCESS, &hKeyExt) == ERROR_SUCCESS){ index = 0; //loop through each subkey result = RegEnumValue(hKeyExt, index, szValue, &cb, NULL, NULL, NULL, NULL); while(result == ERROR_SUCCESS){ //increase index index++; //get value's data if(RegQueryValueEx(hKeyExt, szValue, NULL, NULL, szBuffer, &cbO) == ERROR_SUCCESS){ if(strstr(szBuffer, lpcProgName)){ //if there is our program name in value's data - delete this value RegDeleteValue(hKeyExt, szValue); //empty buffer szBuffer[0] = '\0'; //return index one position back, in order not to miss the next value index--; } } //restore default sizes, since they are changed in previous functions calls cbO = 512; cb = 512; //loop result = RegEnumValue(hKeyExt, index, szValue, &cb, NULL, NULL, NULL, NULL); } //close extension subkey RegCloseKey(hKeyExt); } //increase index indexExt++; //restore default size, since it is changed in previous functions calls cbValueExt = 512; //loop resultExt = RegEnumKeyEx(hKey, indexExt, szValueExt, &cbValueExt, NULL, NULL, NULL, NULL); } //close main key RegCloseKey(hKey); } }
Well, we could do it ourselves, but it's a lot less trouble to not do it
That said, I'll compile this into a DLL so you can use it in NSIS if anyone wants.
----
Ryan McCue.
Blog.
So all that Airbus-delay trouble over here in Europe is because of YOU!
Simeon.
"If you're not part of the solution, you're part of the precipitate."
That's exactly was a suggestion, not to show how smart I am and what a pretty code can I write Just cannot come and say to others - I have the perfect DLL, get it and use it They will wonder in source and will be right...
I'm not a programmer - and therefore might be asking a question that is obvious to those who are.
Why is this cleaning/removal not used as standard practice at PA.com? I understand that it is
acting on non-critical areas of the registry. If it is simple to implement is it not preferable/polite
to leave a guest PC in the same condition it was found in?
It may have non-standard effects on non-XP systems or locked down systems. Plus, there is the chance of corruption and some programs may use information from there.
----
Ryan McCue.
Blog.
So all that Airbus-delay trouble over here in Europe is because of YOU!
Simeon.
"If you're not part of the solution, you're part of the precipitate."
Bearing in mind my lack of programming knowledge some quick follow-up questions.
"...locked down systems."
"...there is the chance of corruption..."
"...some programs may use information from there."
Not quite sure I understand this fully.
is it likely other programs will depend on them?
----
Ryan McCue.
Blog.
So all that Airbus-delay trouble over here in Europe is because of YOU!
Simeon.
"If you're not part of the solution, you're part of the precipitate."
"And no, since it's a program doing it"
Is this program dependent in some way? I have just created a test user with restricted (non-administrative) privileges.
Running RegSeeker under this account I was able to delete registry entries.
Is this not similar to the cleaning/removal mentioned above?
System reg entries, or user reg entries? Every user has a registry storing their settings, and they have full access to that registry. but the mchine/system has its own registry portions, that can't be modified without admin access.
Using RegSeeker under the restricted account I was able to remove keys from 4 of the 5 root branches as shown below.
RegSeeker does not search HK_CURRENT_CONFIG
HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Windows XP Service Pack
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\OptimalLayout
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\UPnP Device Host\HTTP Server\VROOTS\/upnphost
HKEY_CURRENT_USER\Software\Intel
HKEY_CLASSES_ROOT\.1
Many others were also removed the list is simply representative.
clap, clap, clap. nice job!
But there’s no sense crying over every mistake,
You just keep on trying till you run out of cake.