移植Borland C++ Builder 5注册表类至Visual Studio 2022时RegEnumValueA返回87(无效参数)问题求助
Let's break down why you're hitting error 87 and how to fix it:
The Root Cause
Your code is passing a non-NULL lpData pointer (pointing to cData) but a NULL lpcbData parameter. The RegEnumValueA API requires that if you provide a valid buffer via lpData, you must also pass a valid pointer to a DWORD in lpcbData to specify the buffer's size (and receive the actual data size after the call). When these two parameters are mismatched (non-NULL lpData + NULL lpcbData), Windows returns error 87 (invalid parameter).
Since your goal is only to retrieve value names (not their data or types), you don't need to allocate buffers for data at all. Plus, your current code has two other issues that would cause problems even after fixing the error 87:
- You never reset
dwValueBufSizetoTREG_MAX_VALUES_BUF_SIZEbetween API calls. After the first call, this variable gets updated to the length of the retrieved value name, so subsequent calls will use an incorrectly small buffer size. - You don't actually add the retrieved value names to the
TStrings* Stringsparameter—so even if the API calls worked, your output list would be empty.
Corrected Code for GetValueNames
Here's the fixed version of your method:
void __fastcall TRegistry::GetValueNames(TStrings* Strings) { if (!Strings) { throw Exception("Strings parameter cannot be null"); } Strings->Clear(); // Ensure the list is empty before adding new entries HKEY hKey = m_CurrentKey; DWORD dwIndex = 0; CHAR cValueName[TREG_MAX_VALUES_BUF_SIZE] = {}; DWORD dwValueBufSize = 0; long res = ERROR_SUCCESS; do { // Reset buffer size and clear the name buffer for each iteration dwValueBufSize = TREG_MAX_VALUES_BUF_SIZE; memset(cValueName, 0, sizeof(cValueName)); // Only request the value name—pass NULL for type, data, and data size parameters res = RegEnumValueA( hKey, dwIndex, cValueName, &dwValueBufSize, NULL, // Reserved, must be NULL NULL, // We don't need the value type NULL, // We don't need the value data NULL // No data buffer, so no size pointer needed ); if (res == ERROR_SUCCESS) { // Convert the retrieved ANSI name to AnsiString and add to the list Strings->Add(AnsiString(cValueName)); dwIndex++; } else if (res != ERROR_NO_MORE_ITEMS) { // Throw an exception for any error other than "no more items" throw Exception(AnsiString("RegEnumValueA failed with error code: ") + AnsiString(res)); } } while (res != ERROR_NO_MORE_ITEMS); }
Key Changes Made
- Fixed parameter mismatch: Set
lpDataandlpcbDatatoNULLsince we don't need value data. This eliminates the invalid parameter error. - Reset buffer state: For each iteration, we reset
dwValueBufSizeto the full buffer size and clear the name buffer to avoid leftover data from previous calls. - Populate the output list: Added
Strings->Add(AnsiString(cValueName))to actually store the retrieved value names in the providedTStringscontainer. - Added null check: Added a guard clause to ensure the
Stringsparameter isn't null, preventing crashes. - Improved loop structure: Switched to a
do-whileloop to make the flow more readable—we always attempt the first enumeration before checking the result.
Additional Notes
- Ensure
TREG_MAX_VALUES_BUF_SIZEis large enough to handle the longest value name in your registry key (including the null terminator). 200 is reasonable for most cases, but if you encounterERROR_MORE_DATA, you may need to increase it or implement dynamic buffer allocation. - Verify that
m_CurrentKeyis a valid, open HKEY handle (yourOpenKeycalls seem correct, but it's worth double-checking if you still run into issues).
内容的提问来源于stack exchange,提问作者Jakub Cieślak

