1

对不起我纯英语。

我有两个进程可以读取和写入数据到相同的值(我的测试就是这样做的)。有时(每十次)读取方法失败,错误为 ERROR_MORE_DATA 并且值为 12。但我从 32 字节的测试中调用读取方法。

偶然我查看了@err,hr in watch (GetLastError()) 并看到了 ERROR_NOT_OWNER 错误代码。我知道第二个进程是阻塞密钥,我必须再试一次。

任何人都可以批准我的结论(MSDN 对此没有说什么)?谁能告诉我其他奇怪的效果?

谢谢你。

更新:我有 UAC 虚拟化。所有更改都存储到 [HKEY_CLASSES_ROOT\VirtualStore\MACHINE\SOFTWARE] 可能是效果虚拟化???

{
...
    char name[32] = "";
    grandchild.OpenValue("name").Read(name, _countof(name));
...
}
bool RegisteryStorageValue::Read(void* Buffer, size_t Size) throw (IOException)
{
    DWORD Value = DWORD(Size);
    DWORD rez = ::RegQueryValueEx(mKey, mName.c_str(), NULL, NULL, (BYTE*)Buffer, &Value);
    if (rez != ERROR_SUCCESS) // here I have 'rez = ERROR_MORE_DATA' and 'Value = 12'
        throw IOException(rez);
    return true;
}
bool RegisteryStorageValue::Write(Type type, const void* Buffer, size_t Size) throw (IOException)
{
    DWORD rez = ::RegSetValueEx(mKey, mName.c_str(), NULL, getRegType(type), (const BYTE*)Buffer, (DWORD)Size);
    if (rez != ERROR_SUCCESS)
        throw IOException(rez);
    return true;
}
4

2 回答 2

1

注册表函数不GetLastError()用于报告错误。它们直接返回错误代码。所以这ERROR_NOT_OWNER是误导,它来自早期的 Win32 API 调用,而不是注册表调用。

没有可能的方法可以传入32to的 Size 值RegQueryValueEx()并返回一个ERROR_MORE_DATA错误,说明数据实际上12是大小。 RegQueryValueEx()不能那样工作。确保您的Size值在进入Read()函数时实际设置为 32,而不是设置为其他值。

更新:但是,可以RegQueryValueEx()报告ERROR_MORE_DATA并返回比您请求的数据大两倍的数据大小,即使RegSetValueEx()实际上并没有传递那么多数据。当我运行您的测试代码时,我RegQueryValueEx()有时(不是每次)能够报告 64 的数据大小,即使请求的是 32。原因是RegSetValueExA(),您的代码实际调用的 为字符串类型(和)执行从 Ansi 到 Unicode 的数据转换,REG_SZ并且您的代码实际调用的 查询原始字节并对字符串执行 Unicode 到 Ansi 的转换类型。因此,虽然您编写的代码可能会保存 32 个值,即 32 个字节,但注册表实际上存储了 32 个REG_MULTI_SZREG_EXPAND_SZRegQueryValueExA()charwchar_t值,因此是 64 个字节(如果您的输入字符串中包含非 ASCII 字符,它会更多)。可能RegQueryValueEx()是按原样返回原始字节而不是转换它们,例如如果RegSetValueEx()先保存原始字节,然后再保存数据类型,但RegQueryValueEx()在保存数据类型之前读取原始字节,因此不会知道数据是需要转换的字符串类型。

无论哪种方式,这是一个线程/进程读取而另一个线程/进程正在写入之间的竞争条件,写入在刷新数据之前在内部缓存数据时出现读取问题等。除非您同步读取和写入,因为 Registry API 不会为您同步。

于 2013-01-23T08:27:40.860 回答
0

我为我的问题写了样本。我在第三次开始时重复了这个问题。

如果样本是复杂的,您可以看到“查询复杂”和“SetComplite”消息

在错误时您应该看到:“错误更多数据:??”

#include <string>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>


bool start(char* path, char* args)
{
    std::string cmd = path;
    cmd.push_back(' ');
    cmd.append(args);

    STARTUPINFO si = {0};
    PROCESS_INFORMATION pi = {0};
    BOOL res = ::CreateProcess(NULL, (LPSTR)cmd.c_str(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
    if (res == FALSE)
        return false;

    ::CloseHandle(pi.hProcess);
    ::CloseHandle(pi.hThread);

    return true;
}

int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hEvent = ::CreateEvent(NULL, TRUE, FALSE, "Local/blah");

    if (argc == 1)
    {
        HKEY hKey;
        if (::RegCreateKey(HKEY_CURRENT_USER, "Software\\TestRegistry", &hKey) != ERROR_SUCCESS)
            return -1;

        char buffer[] = "Hello, Stack!";
        ::RegSetValueEx(hKey, "Value", 0, REG_SZ, (BYTE*)buffer, _countof(buffer));
        ::RegCloseKey(hKey);

        if (start(argv[0], "r") == false ||
            start(argv[0], "w") == false)
            return -2;
        ::Sleep(1000);
        ::SetEvent(hEvent);
    }
    else
    {
        if (argv[1][0] == 'r')
        {
            HKEY hKey;
            if (::RegOpenKey(HKEY_CURRENT_USER, "Software\\TestRegistry", &hKey) != ERROR_SUCCESS)
                return -1;

            char buffer[1024] = {0};
            if (::WaitForSingleObject(hEvent, 10000) == WAIT_TIMEOUT)
                return -3;
            for (size_t index = 0; index < 1000000; ++index)
            {
                DWORD dwType;
                DWORD dwSize = _countof(buffer);
                DWORD result = ::RegQueryValueEx(hKey, "Value", 0, &dwType, (LPBYTE)buffer, &dwSize);
                if (result == ERROR_SUCCESS)
                    continue;
                if (result == ERROR_MORE_DATA)
                {
                    ::printf_s("\nError more data: %d\n", dwSize);
                    return 1;
                }
            }
            ::RegCloseKey(hKey);
            ::printf_s("\nQuery completed\n");
        }
        else
        {
            ::srand(::GetTickCount());
            HKEY hKey;
            if (::RegOpenKey(HKEY_CURRENT_USER, "Software\\TestRegistry", &hKey) != ERROR_SUCCESS)
                return -1;

            const size_t word_size = 32;
            char dict[][word_size] =
            {
                "aaaaaaaa",
                "help me",
                "rape me",
                "in the pines",
                "argh",
            };
            char buffer[1024] = {0};

            if (::WaitForSingleObject(hEvent, 10000) == WAIT_TIMEOUT)
                return -3;
            for (size_t index = 0; index < 1000000; ++index)
            {
                DWORD dwType = REG_SZ;
                DWORD dwSize = word_size;
                DWORD result = ::RegSetValueEx(hKey, "Value", 0, dwType, (LPBYTE)dict[rand() % _countof(dict)], dwSize);
                if (result == ERROR_SUCCESS)
                    continue;
            }
            ::RegCloseKey(hKey);
            ::printf_s("\nSet completed\n");
        }
    }
    return 0;
}
于 2013-01-24T05:36:40.137 回答