user1696837
user1696837

Reputation:

RegOpenKeyEx returning Error 87 aka "INVALID_PARAMETER"

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

Answers (3)

Abhineet
Abhineet

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

Remy Lebeau
Remy Lebeau

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

Serge Z
Serge Z

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

Related Questions