函数调用CRegKey :: QueryStringValue时出错

时间:2013-12-12 20:04:53

标签: c++ visual-c++ registry atl

今天我在查询时区信息时发现了这个奇怪的错误。 读取时区显示名称的代码如下所示

typedef struct {
    LONG Bias;
    LONG StandardBias;
    LONG DaylightBias;
    SYSTEMTIME StandardDate;
    SYSTEMTIME DaylightDate;
} TZI, * PTZI;

CRegKey RegKey;
CString regKey = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones");
int idx = 0;
bool bMoreKeys = true;
bool bSuccess = true;
while (bMoreKeys && bSuccess) {
    CString sSubkeyName;
    DWORD nLength = 200;
    LPTSTR sBuffer = sSubkeyName.GetBufferSetLength(nLength);
    FILETIME ftLastWriteTime;
    bMoreKeys = (RegKey.EnumKey(idx, sBuffer, & nLength, & ftLastWriteTime) == ERROR_SUCCESS);
    sSubkeyName.ReleaseBuffer();
    if (!bMoreKeys) {
        bMoreKeys = false;
        break;
    }
    CString sSubKeyPath = regKey + _T("\\") + sSubkeyName;
    CRegKey subKey;
    if (subKey.Open(HKEY_LOCAL_MACHINE, sSubKeyPath, KEY_READ) != ERROR_SUCCESS) {
        //LOG_ERROR
        bSuccess = false;
        break;
    }
    // Get the display name
    CString sDispName;
    DWORD nDispBufferLength = 1000;
    LPTSTR sDispBuffer = sDispName.GetBufferSetLength(nDispBufferLength);
    if (subKey.QueryStringValue(_T("Display"), sDispBuffer, & nDispBufferLength) != ERROR_SUCCESS) {
        //LOG_ERROR
        bSuccess = false;
        break;
    }
    sDispName.ReleaseBuffer();
    // Get the Bias (for later sorting);
    TZI tzi;
    nLength = sizeof(tzi);
    if (subKey.QueryBinaryValue(_T("TZI"), & tzi, & nLength) != ERROR_SUCCESS && nLength != sizeof(tzi)) {
        //LOG_ERROR
        bSuccess = false;
    }
    (void) subKey.Close();
    idx++;
}

但对于某些时区,例如:argentina,返回值不是error_success。 在进一步调试QueryStringValue时,我发现了这个

if ((nBytes % sizeof(TCHAR) != 0) || (pszValue[nBytes / sizeof(TCHAR) - 1] != 0)) {
    return ERROR_INVALID_DATA;
}

如果任何时区显示值的nBytes大小 48 ,则返回始终 error_invalid_data。

为了确认这一点,我已将regkey api调用改为

DWORD dwType = 0;
ULONG nBytes = 256 * sizeof(TCHAR);
TCHAR displayValue[256];
if (subKey.QueryValue(
    _T("Display"), & dwType, (LPBYTE) displayValue, & nBytes) == 0 && dwType == REG_SZ) {}

我不再得到错误,一切正常。 无法找出导致其发生的任何有效原因。任何人都有更好的解释为什么对于所有48大小的时区我们都会得到无效的数据错误。 提前谢谢。

编辑:

PS:在某些机器中,一切都能正常运行上面提到的代码(即第一个),而在其他一些机器中,它不是真正奇怪的东西,而且在第二个代码到处都可以看到代码工作正常。

2 个答案:

答案 0 :(得分:0)

代码

CRegKey Key;
LONG nA = Key.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\Argentina Standard Time"), KEY_READ);
TCHAR pszValue[24];
ULONG nValueLength = _countof(pszValue);
LONG nB = Key.QueryStringValue(_T("Display"), pszValue, &nValueLength);

给你一个不同的错误,234,ERROR_MORE_DATA“有更多数据可用。”

这是因为值本身并不完全适合提供的缓冲区。

这就是你想要的:

CRegKey Key;
LONG nA = Key.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\Argentina Standard Time"), KEY_READ);
ULONG nValueLength = 0;
LONG nB = Key.QueryStringValue(_T("Display"), NULL, &nValueLength);
CString sValue;
if(nValueLength > 0)
{
    LONG nC = Key.QueryStringValue(_T("Display"), sValue.GetBufferSetLength(nValueLength - 1), &nValueLength);
}

或者,您需要提供足够大的缓冲区,您认为这足够了。

答案 1 :(得分:0)

reg中的字符串可能不会以空值终止。因此,以下验证失败:

if ((nBytes % sizeof(TCHAR) != 0) || (pszValue[nBytes / sizeof(TCHAR) -1] != 0))
{
    return ERROR_INVALID_DATA;
}

请注意,它似乎是CRegKey::QueryStringValue中的错误,RegQueryValueEx允许读取非空终止字符串,并且调用者负责处理此情况。我在代码中遇到了这个问题,不得不用我自己的函数替换对CRegKey::QueryStringValue的调用。