函数调用CRegKey::QueryStringValue时出错

Error with function call CRegKey::QueryStringValue

本文关键字:出错 QueryStringValue 函数调用 CRegKey      更新时间:2023-10-16

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

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++;
}

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

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

当任何时区显示值的nBytes大小为48时,返回始终error_invalid_data。

为了确认这一点,我已经将regkeyapi调用更改为

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:在一些机器中,上面提到的代码(即第一个代码)一切都很好,而在其他一些机器中则不然,这才是真正奇怪的,第二个代码无处不在,我可以看到代码工作得很好。

代码

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);
}

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

reg中的字符串不能以null结尾。因此,以下验证失败:

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

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