【问题标题】:RegOpenKeyEx returning Error 87 aka "INVALID_PARAMETER"RegOpenKeyEx 返回错误 87 aka "INVALID_PARAMETER"
【发布时间】:2012-09-25 09:49:32
【问题描述】:

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

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

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

错误代码:: 87 (INVALID_PARAMETER)

Weird Behaviour:: 在我使用 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 |删除

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

【问题讨论】:

  • 如果使用密钥的真实路径HKLM\Software\Classes\Installer\...会发生什么?
  • @HarryJohnston- 我没试过......让我试试,我会告诉你结果。谢谢你的启发:-)
  • @HarryJohnston- 还是一样 :-( ERROR 87
  • 再次检查输出以查看您是否已经删除了无法打开的密钥(它可能会枚举两次)。列出您要提前删除的分支的内容,并将其与输出进行比较;也许其他一些程序正在同时添加和删除键。确保您使用 Unicode 进行编译。为什么使用两个反斜杠作为路径分隔符?为什么要递归到 K7RT_RcrsvRegDel 而不是 RcrsvRegDel,它们是同一个函数吗?
  • 与其将键名附加在一起形成完整路径,不如调用RcrsvRegDel(hKeySub, szName)进行递归。

标签: c++ windows winapi mfc registry


【解决方案1】:

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

【讨论】:

  • 对不起,我正在更新问题。实际上我也尝试过使用其他标志但没有成功:-(
  • 我的意思是 - 你必须使用 RegDeleteKeyEx(hKey, lpszSub, KEY_ALL_ACCESS |KEY_WOW64_32KEY)
  • 是的,但我的应用程序是 32 位的,我正在尝试从 32 位注册表树中删除密钥,因此不会造成任何问题。除此之外,我正在尝试访问 HKCR。至少它不应该抛出错误@ RegOpenkeyEx。
  • 你没有在听 Serge 告诉你什么。使用KEY_WOW64_32KEY 标志打开的密钥句柄,就像您正在做的那样,不能传递给RegDeleteKey(),而是必须传递给RegDeleteKeyEx()。你不能在非 WOW64 系统上使用KEY_WOW64_32KEY。
【解决方案2】:

你可以这样做。将该标志作为输入参数,并在调用递归函数时为 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 ;
}

【讨论】:

  • 嘿,谢谢 Abhineet。那工作得很好。非常感谢伙计。但是为什么要使用 SetPrivilege 函数呢?
  • 您可以在此处阅读:msdn.microsoft.com/en-us/library/windows/desktop/…。我通常在使用注册表树时使用它。在 msdn 上阅读。
【解决方案3】:

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

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() 或SHDeleteKey()。让他们为你做递归。

【讨论】:

  • 我很欣赏你所付出的努力,上面的代码真的很流畅,但我的问题仍然是打开钥匙。如果问题不那么明显,让我让自己更清楚::
  • 1.为什么即使使用简单的 KEY_READ 或 KEY_ENUMERATE_SUB_KEYS 标志,RegOpenKeyEx 也会因错误 87 而失败。 2. 正如@MSDN 文档所说,“默认情况下,在 WOW64 上运行的 32 位应用程序访问 32 位注册表视图,而 64 位应用程序访问 64 位注册表视图。”,所以,我没有尝试由于我的应用程序是 32 位,因此要访问任何备用注册表,我已经提到该标志是非常谨慎的。 3. 该代码适用于 x86 和 x64 与 VISTA 或 WIN 7,所以我不认为使用 RegDeleteKey 会导致任何问题。
  • 在没有看到调用RcrsvRegDel() 的代码的情况下,很难诊断出RegOpenKeyEx() 失败的原因。很有可能hKey 或lpszSub 确实包含无效值。确保您也没有尝试访问在 WOW64 下虚拟化的密钥,这也可能是一个因素。
  • @user1696837:当您第一次提出错误代码来自 RegOpenKeyEx 调用而不是 RegDeleteKey 调用的问题时,您确实应该提到过。我们一直在浪费时间试图解决您没有解决的问题,而不是您解决的问题。
  • 当RegOpenKeyEx() 失败时,您的printf() 语句输出什么?您是否确认 lpszSub 是相对于 hKey 键的有效字符串路径?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-03
  • 2017-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多