1

私の純粋な英語でごめんなさい。

同じ値でデータの読み取りと書き込みを行うことができる2つのプロセスがあります(私のテストではそれを行います)。時々(10回に1回)readメソッドがエラーERROR_MORE_DATAで失敗し、値は12です。しかし、32バイトのテストからReadメソッドを呼び出します。

偶然、ウォッチ(GetLastError())で@ err、hrを調べて、ERROR_NOT_OWNERエラーコードを確認しました.2番目のプロセスがキーをブロックしていることを理解しているので、再試行する必要があります。

誰かが私の結論を承認できますか(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は誤解を招く可能性があります。これは、レジストリ呼び出しではなく、以前のWin32API呼び出しからのものです。

サイズ値32toを渡して、データが実際にサイズでRegQueryValueEx()あるというエラーを返す方法はありません。 そのようには機能しません。関数への入力時に値が実際に32に設定されており、他の値に設定されていないことを確認してください。ERROR_MORE_DATA12RegQueryValueEx()SizeRead()

更新:ただし、実際にはそれほど多くのデータが渡されない場合でも、要求したデータの2倍のサイズのデータRegQueryValueEx()​​をレポートして返すことができます。テストコードを実行したとき、32が要求されていても、64のデータサイズを報告することがありました(毎回ではありません)。その理由は、コードが実際に呼び出している、が文字列タイプ( 、、および)に対してAnsiからUnicodeへのデータ変換を実行し、コードが実際に呼び出している、が生のバイトを照会し、文字列に対してUnicodeからAnsiへの変換を実行するためです。タイプ。したがって、記述コードが32値、つまり32バイトを保存している場合でも、レジストリは実際には32を保存しています。ERROR_MORE_DATARegSetValueEx()RegQueryValueEx()RegSetValueExA()REG_SZREG_MULTI_SZREG_EXPAND_SZRegQueryValueExA()charwchar_t代わりに値、つまり64バイト(入力文字列に非ASCII文字が含まれている場合はそれ以上になります)。最初に生のバイトを保存してからデータ型を保存するRegQueryValueEx()場合など、生のバイトを変換する代わりにそのまま返す可能性がありますが、データ型が保存される前に生のバイトを読み取るため、そうではありませんデータが変換が必要な文字列型であることを知っています。RegSetValueEx()RegQueryValueEx()

いずれにせよ、これは、別のスレッド/プロセスが書き込みを行っている間の1つのスレッド/プロセスの読み取り間の競合状態、書き込みがデータをフラッシュする前に内部的にデータをキャッシュしている間の読み取りの問題などです。読み取りを同期しない限り、これについては何もできません。レジストリAPIは同期しないため、書き込みます。

于 2013-01-23T08:27:40.860 に答える
0

質問のサンプルを書きます。3回目のスタートで繰り返し発行しました。

サンプルがcompliteの場合、「Querycomplite」および「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 に答える