Why does the RegQueryValueEx() function return ERROR_FILE_NOT_FOUND while trying to read from a registry key?
Asked Answered
S

1

9

System: Windows 7 32bit
Language: C++

I have tried to access register HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 0, key Driver (type REG_SZ) -- no problem.

The same for reading from HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM, all keys (types REG_SZ) got slashes, for example \Device\Serial0.

While reading such keys it always returns 2 (no such file) with following example code:

HKEY hKey = 0;
DWORD dwType = REG_SZ;
char buf[255] = {0};
DWORD dwBufSize = sizeof(buf);

if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS ) 
{
  auto ret = RegQueryValueEx( hKey, TEXT("\Device\Serial0"), 0, &dwType, (LPBYTE)buf, &dwBufSize );
  // ret always == 2 for key with slashes
--- CUT ---

What is the proper way to read key values with slashes in name?


Above has been properly answered by Cody Gray.
Below another issue.

Im getting the same problem when Im using variable instead of a text string.
Iv considered both approaches with single and double slashes:

HKEY hKey = 0;
DWORD keyType = REG_SZ;
TCHAR buf[255] = {0};
DWORD bufSize = sizeof(buf);

QSettings winReg("HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM", QSettings::NativeFormat);
auto comsKey = winReg.allKeys();

FOREACH( auto com, comsKey )
{
  // FOREACH - boost macro
  // comsKey = QList<QString> (list of key names) [from Qt framework]
  // com = QString (single key name) [from Qt framework]
  if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS )
  {
    wchar_t* keyw = new wchar_t();
    //com.replace("/", "\\\\"); <- checked both variants commented and not commented; com == /Device/Serial0 so im converting to \\Device\\Serial0
    int size = com.size();
    mbstowcs( keyw, com.toStdString().data(), size );
    //auto ret = RegQueryValueEx( hKey, TEXT("\\Device\\Serial0"), 0, &keyType, (LPBYTE)buf, &bufSize ); // <- this works!
    auto ret = RegQueryValueExW( hKey, (LPCWSTR)&keyw, 0, &keyType, (LPBYTE)buf, &bufSize ); // <- this one not works!

I have tried all variants with "\Device..", "/Device", "\Device", etc.

Shaun answered 21/12, 2011 at 11:13 Comment(2)
@Werner, no, the RegQueryValueEx function only queries the value of a registry key. Values are the name/data pairs stored within keys. So you can't pass it a nested path of keys as you describe because values don't have paths. Admittedly, the terminology is quite confusing, Raymond Chen attempted to explain it here.Dallas
RegGetValue(), on the other hand, can query a value of a nested subkey.Lakia
D
8

You have to escape the slashes, just like you did in the first line...

if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS ) 
{
  auto ret = RegQueryValueEx( hKey, TEXT("\\Device\\Serial0"), 0, &dwType, (LPBYTE)buf, &dwBufSize );
  // ret always == 2 for key with slashes

If you don't, the RegQueryValueEx function can't find the specified key, and it returns ERROR_FILE_NOT_FOUND (== 2).


But there's another problem. You should be declaring the buffer array as type wchar_t (or TCHAR), rather than char:

TCHAR buf[255] = {0};

Otherwise, the RegQueryValueEx function is going to attempt to fill the array with a Unicode string read from the specified registry key, and you're going to get something unreadable.

Dallas answered 21/12, 2011 at 11:21 Comment(6)
buf should be declared as TCHAR, not as wchar_t. ReqQueryValueEx does not care about how buf is declared, the returned value depends on whether RegQueryValueExA or RegQueryValueExW is called.Bollay
@Werner: Yes, that's technically true. But Windows applications haven't been compiled as ANSI (non-Unicode) for over 10 years. A lot of people don't care to use the macros anymore, and it's hard to blame them.Dallas
Your answer is rather optimized to give the OP a hard time. C++11 syntax, WMI is quite unfriendly in C++, serial ports are not plug-and-play devices.Volution
@Hans: I copied the auto syntax from the original question; I assume he's not using Microsoft's compiler. What would you suggest as a better approach than WMI? I'm almost certain that reading this from the registry is not the right way.Dallas
Reading that registry key to discover COM port names is the prescribed way. The .NET SerialPort.GetPortNames() method uses it for example.Volution
@CodyGray: auto syntax is compatibile with Microsoft Visual Studio 2010 compiler.Shaun

© 2022 - 2024 — McMap. All rights reserved.