3

我正在使用 RegOpenKeyEx、RegDeleteKey 和 RegEnumKey 实现递归注册表删除。

问题::虽然代码在 Vista x86/x64 和 Win 7 x86/x64 上运行得非常好,但在 XP 上对于 HKCR 中的某些键却失败了

问题区域:: HKCR\Installer\Products\SomeKey

错误代码:: 87 (INVALID_PARAMETER)

奇怪的行为::在我使用 REGEDIT 打开密钥的那一刻删除密钥。

代码::

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 ;
}

知道发生了什么吗?

更新::

我还尝试了带有以下标志的 samDesired 参数

-KEY_READ

-KEY_READ | KEY_WRITE

-KEY_ENUMERATE_SUB_KEYS

-KEY_ENUMERATE_SUB_KEYS | 删除

上述标志都不起作用:-(

4

3 回答 3

1

因为您不能使用带有标志 KEY_WOW64_32KEY 的句柄打开的 RegDeleteKey。有关信息,请参阅http://msdn.microsoft.com/en-us/library/aa384129(v=vs.85).aspx。您必须将 RegDeleteKeyEx 与相同的键一起使用。

于 2012-09-25T10:15:17.917 回答
0

您不能用于RegDeleteKey()删除 64 位系统上的 32 位密钥。 文档说了这么多:

RegDeleteKey 函数不能用于访问备用注册表视图。

您必须RegDeleteKeyEx()改用。

尝试这样的事情:

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;
} 

话虽如此,请考虑使用RegDeleteTree()orSHDeleteKey()代替。让他们为你做递归。

于 2012-09-25T19:41:46.930 回答
0

你可以这样做。将该标志作为输入参数,并在调用递归函数时为 RegOpenKeyEx 传递一个标志,并再次传递一组标志。我已经尝试过您的代码,它现在运行良好,但不确定是什么导致了问题。

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 ;
}
于 2012-10-05T06:01:47.850 回答