Reputation:
I am implementing a recursive registry delete using RegOpenKeyEx, RegDeleteKey and RegEnumKey.
Problem:: Though the code works perfectly fine for Vista x86/x64 and Win 7 x86/x64 but fails on XP for some keys in HKCR
Problem Area:: HKCR\Installer\Products\SomeKey
Error Code:: 87 (INVALID_PARAMETER)
Weird Behaviour:: Deletes the key the moment I open the key using REGEDIT.
Code::
static BOOL RcrsvRegDel( HKEY hKey, LPTSTR lpszSub )
{
BOOL bRet = TRUE ;
LONG lRet ;
DWORD dwSize = MAX_PATH ;
TCHAR szName[MAX_PATH] ;
TCHAR szFullKey[MAX_PATH * 2] ;
HKEY hKeySub = NULL ;
HRESULT hr = NULL ;
do{
lRet = RegOpenKeyEx( hKey, lpszSub, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &hKeySub ) ;
printf("RegOpenKey:: %S :: lRet = %ld\n", lpszSub, lRet) ;
if( lRet != ERROR_SUCCESS )
{
if( lRet == ERROR_FILE_NOT_FOUND )
{
bRet = TRUE ;
break ;
}
else
{
bRet = FALSE ;
break ;
}
}
while( ERROR_NO_MORE_ITEMS != (lRet = RegEnumKeyEx(hKeySub, 0, szName, &dwSize, NULL, NULL, NULL, NULL)) )
{
bRet = RcrsvRegDel( hKeySub, szName) ;
if( bRet == FALSE )
break ;
}
if( hKeySub != NULL )
{
RegCloseKey(hKeySub) ;
hKeySub = NULL ;
}
lRet = RegDeleteKey( hKey, lpszSub ) ;
printf("RegDelKey:: %S :: lRet = %ld\n", lpszSub, lRet) ;
if( lRet == ERROR_SUCCESS )
{
bRet = TRUE ;
break ;
}
}while(0) ;
return bRet ;
}
Any idea whats goin on?
UPDATE::
I have also tried the samDesired Parameter with following flags
-KEY_READ
-KEY_READ | KEY_WRITE
-KEY_ENUMERATE_SUB_KEYS
-KEY_ENUMERATE_SUB_KEYS | DELETE
Neither of the above flag works :-(
Upvotes: 3
Views: 5640
Reputation: 5389
You can do like this. Take the flag as input parameter and pass one flag for the RegOpenKeyEx and again a set of flags when calling the recursive function. I have tried your code and it is working perfectly now, though it is not sure as to what was it that was causing the problem.
static BOOL RcrsvRegDel( HKEY hKey, LPTSTR lpszSub, DWORD dwOpenFlags )
{
BOOL bRet = TRUE ;
LONG lRet ;
DWORD dwSize = MAX_PATH ;
TCHAR szName[MAX_PATH] ;
HKEY hKeySub = NULL ;
HRESULT hr = NULL ;
HANDLE hProcess = NULL ;
HANDLE hToken = NULL ;
do{
bRet = SetPrivilege( SE_BACKUP_NAME, TRUE ) ;
if( bRet == FALSE )
{
bRet = FALSE ;
break ;
}
lRet = RegOpenKeyEx( hKey, lpszSub, 0, dwOpenFlags, &hKeySub ) ;
if( lRet != ERROR_SUCCESS )
{
bRet = FALSE ;
break ;
}
while( ERROR_NO_MORE_ITEMS != (lRet = RegEnumKeyEx(hKeySub, 0, szName, &dwSize, NULL,
NULL, NULL, NULL)) )
if( !RcrsvRegDel(hKeySub, szName, dwOpenFlags) )
{
bRet = FALSE ;
break ;
}
lRet = RegDeleteKey( hKey, lpszSub ) ;
printf("RegDelKey:: %S :: lRet = %ld\n", lpszSub, lRet) ;
if( lRet != ERROR_SUCCESS )
{
bRet = FALSE ;
break ;
}
if( hKeySub != NULL )
{
RegCloseKey(hKeySub) ;
hKeySub = NULL ;
}
}while(0) ;
return bRet ;
}
static BOOL SetPrivilege( LPCTSTR lpszPrivilege, BOOL bEnablePrivilege )
{
LUID luid ;
BOOL bRet = TRUE ;
HANDLE hToken = NULL ;
HANDLE hProcess = NULL ;
TOKEN_PRIVILEGES tp ;
do{
hProcess = GetCurrentProcess() ;
if( 0 == OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken) )
{
bRet = FALSE ;
break ;
}
if( !LookupPrivilegeValue(NULL, lpszPrivilege, &luid) )
{
bRet = FALSE ;
break ;
}
tp.PrivilegeCount = 1 ;
tp.Privileges[0].Luid = luid ;
if( bEnablePrivilege )
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED ;
else
tp.Privileges[0].Attributes = 0 ;
if( !AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL) )
{
bRet = FALSE ;
break ;
}
if( ERROR_NOT_ALL_ASSIGNED == GetLastError() )
{
bRet = FALSE ;
break ;
}
}while(0) ;
if( hToken != NULL ) CloseHandle( hToken ) ;
return bRet ;
}
Upvotes: 0
Reputation: 596307
You cannot use RegDeleteKey()
to delete a 32-bit key on a 64-bit system. The documentation says as much:
The RegDeleteKey function cannot be used to access an alternate registry view.
You must use RegDeleteKeyEx()
instead.
Try something like this:
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
extern LPFN_ISWOW64PROCESS fnIsWow64Process;
typedef LONG (WINAPI *LPFN_REGDELETEKEYEX)(HKEY, LPCTSTR, REGSAM, DWORD);
extern LPFN_REGDELETEKEYEX fnRegDeleteKeyEx;
.
BOOL WINAPI IsWow64Process_Impl(HANDLE hHandle, PBOOL Wow64Process);
{
*Wow64Process = FALSE;
return TRUE;
}
BOOL WINAPI IsWow64Process_Stub(HANDLE hProcess, PBOOL Wow64Process)
{
fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
if ( NULL == fnIsWow64Process )
fnIsWow64Process = &IsWow64Process_Impl;
return fnIsWow64Process(hProcess, Wow64Process);
}
LONG WINAPI RegDeleteKeyEx_Impl(HKEY hKey, LPCTSTR lpSubKey, REGSAM samDesired, DWORD dwReserved)
{
return RegDeleteKey( hKey, lpSubKey );
}
LONG WINAPI RegDeleteKeyEx_Stub(HKEY hKey, LPCTSTR lpSubKey, REGSAM samDesired, DWORD dwReserved)
{
fnRegDeleteKeyEx = (LPFN_REGDELETEKEYEX) GetProcAddress(GetModuleHandle(TEXT("advapi32")),
#ifdef UNICODE
"RegDeleteKeyExW"
#else
"RegDeleteKeyExA"
#endif
);
if ( NULL == fnRegDeleteKeyEx )
fnRegDeleteKeyEx = &RegDeleteKeyEx_Impl;
return fnRegDeleteKeyEx( hKey, lpSubKey, samDesired, dwReserved );
}
LPFN_ISWOW64PROCESS fnIsWow64Process = &IsWow64Process_Stub;
LPFN_REGDELETEKEYEX fnRegDeleteKeyEx = &RegDeleteKeyEx_Stub;
.
BOOL IsWin64()
{
#if defined(_WIN64)
return FALSE; // 64-bit programs run only on Win64
#elif defined(_WIN32)
// 32-bit programs run on both 32-bit and 64-bit Windows so must sniff
BOOL f64 = FALSE;
return fnIsWow64Process(GetCurrentProcess(), &f64) && f64;
#else
return FALSE; // Win64 does not support Win16
#endif
}
.
static BOOL RcrsvRegDel( HKEY hKey, LPTSTR lpszSub )
{
BOOL bRet = TRUE;
LONG lRet;
DWORD dwSize;
TCHAR szName[MAX_PATH+1];
HKEY hKeySub = NULL;
REGSAM Wow64Flag = (IsWin64()) ? KEY_WOW64_32KEY : 0;
lRet = RegOpenKeyEx( hKey, lpszSub, 0, KEY_ENUMERATE_SUB_KEYS | KEY_SET_VALUE | DELETE | Wow64Flag, &hKeySub ) ;
printf("RegOpenKey:: %S :: lRet = %ld\n", lpszSub, lRet) ;
if( lRet != ERROR_SUCCESS )
{
if ( lRet != ERROR_FILE_NOT_FOUND )
bRet = FALSE;
}
else
{
do
{
dwSize = MAX_PATH;
lRet = RegEnumKeyEx( hKeySub, 0, szName, &dwSize, NULL, NULL, NULL, NULL );
if ( lRet != ERROR_SUCCESS )
{
if ( lRet != ERROR_NO_MORE_ITEMS )
bRet = FALSE;
break;
}
bRet = RcrsvRegDel( hKeySub, szName );
if ( !bRet )
break;
}
while (1);
RegCloseKey(hKeySub);
if ( bRet )
{
if ( Wow64Flag != 0 )
lRet = fnRegDeleteKeyEx( hKey, lpszSub, Wow64Flag, 0 );
else
lRet = RegDeleteKey( hKey, lpszSub );
printf("RegDelKey:: %S :: lRet = %ld\n", lpszSub, lRet) ;
if ( lRet != ERROR_SUCCESS )
bRet = FALSE;
}
}
return bRet;
}
With that said, consider using RegDeleteTree()
or SHDeleteKey()
instead. Let them do the recursion for you.
Upvotes: 0
Reputation: 425
Because you can not use RegDeleteKey with handle was opened with flag KEY_WOW64_32KEY. see http://msdn.microsoft.com/en-us/library/aa384129(v=vs.85).aspx for info. You have to use RegDeleteKeyEx with same keys.
Upvotes: 1