Sorry for my pure english.
I have two processes which can Read and Write data to the same value(my tests do it). Sometimes(one per ten times) the read method is fail with error ERROR_MORE_DATA and Value is 12. But I call Read method from the tests with 32 bytes.
By chance I looked to @err,hr in watch (GetLastError()) and saw ERROR_NOT_OWNER error code.I understand that second process is block the key and I must try again.
Can anybody approve my conclusions (MSDN is not say anything about this)? Can anybody will tell me other strange effects?
Thank you.
Update: I have UAC Virtualization. All changes are stored to the [HKEY_CLASSES_ROOT\VirtualStore\MACHINE\SOFTWARE] May be it is effect virtualization???
{
...
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;
}
Registry functions do not use GetLastError()
to report errors. They return error codes directly. So the ERROR_NOT_OWNER
is misleading, it is from an earlier Win32 API call, not the Registry calls.
There is no possible way you can pass in a Size value of 32
to RegQueryValueEx()
and get back an ERROR_MORE_DATA
error saying the data is actually 12
in size. RegQueryValueEx()
does not work that way. Make sure your Size
value is actually set to 32 upon entry to the Read()
function and is not set to some other value.
Update: it is, however, possible for RegQueryValueEx()
to report ERROR_MORE_DATA
and return a data size that is twice as larger as what you requested, even if RegSetValueEx()
is not actually passed that much data. When I ran your test code, I was able to get RegQueryValueEx()
to sometimes (not every time) report a data size of 64 even though 32 was being requested. The reason is because RegSetValueExA()
, which your code is actually calling, performs a data conversion from Ansi to Unicode for string types (REG_SZ
, REG_MULTI_SZ
and REG_EXPAND_SZ
), and RegQueryValueExA()
, which your code is actually calling, queries the raw bytes and performs a Unicode to Ansi conversion for string types. So while your writing code may be saving 32 char
values, thus 32 bytes, the Registry is actually storing 32 wchar_t
values instead, thus 64 bytes (it would be more if your input strings had non-ASCII characters in them). Chances are, RegQueryValueEx()
is returning the raw bytes as-is instead of converting them, such as if RegSetValueEx()
is saving the raw bytes first and then saving the data type afterwards, but RegQueryValueEx()
is reading the raw bytes before the data type has been saved and thus does not know the data is a string type that needs converting.
Either way, this is a race condition between one thread/process reading while another thread/process is writing, issues with reading while the writing is caching data internally before flushing it, etc. Nothing you can do about this unless you synchronize the reads and writes, since the Registry API does not synchronize for you.