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.