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 theERROR_NOT_OWNERis 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
32toRegQueryValueEx()and get back anERROR_MORE_DATAerror saying the data is actually12in size.RegQueryValueEx()does not work that way. Make sure yourSizevalue is actually set to 32 upon entry to theRead()function and is not set to some other value.Update: it is, however, possible for
RegQueryValueEx()to reportERROR_MORE_DATAand return a data size that is twice as larger as what you requested, even ifRegSetValueEx()is not actually passed that much data. When I ran your test code, I was able to getRegQueryValueEx()to sometimes (not every time) report a data size of 64 even though 32 was being requested. The reason is becauseRegSetValueExA(), which your code is actually calling, performs a data conversion from Ansi to Unicode for string types (REG_SZ,REG_MULTI_SZandREG_EXPAND_SZ), andRegQueryValueExA(), 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 32charvalues, thus 32 bytes, the Registry is actually storing 32wchar_tvalues 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 ifRegSetValueEx()is saving the raw bytes first and then saving the data type afterwards, butRegQueryValueEx()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.