Understanding VerQueryValue - c++

On MSDN I noticed the following for the VerQueryValue function:
lplpBuffer [out]
LPVOID
When this method returns, contains the address of a pointer to the requested version information in the buffer pointed to by pBlock. The memory pointed to by lplpBuffer is freed when the associated pBlock memory is freed._
How does the system know when pBlock is freed since pBlock is allocated by the caller?
I'm using the following code:
UINT reqSize = ::GetSystemDirectoryW(nullptr, 1);
std::vector<wchar_t> winDirectory (reqSize, 0);
UINT retVal = ::GetSystemDirectoryW(&winDirectory[0], reqSize);
std::wstring filePath(winDirectory.begin(), winDirectory.end()-1);
filePath.append(L"\\kernel32.dll");
DWORD bufSize = ::GetFileVersionInfoSizeW(
filePath.c_str(),
nullptr);
std::vector<BYTE> fileInfo (bufSize, 0);
::GetFileVersionInfoW(
filePath.c_str(),
0,
bufSize,
&fileInfo[0]);
UINT size = 0;
VS_FIXEDFILEINFO * ptr = nullptr;
BOOL error = ::VerQueryValueW(
&fileInfo[0],
L"\\",
reinterpret_cast<LPVOID*>(&ptr),
&size);

VerQueryValue returns a pointer to somewhere inside the initial block of memory that you allocate (GetFileVersionInfoSize returns the size of a block that is large enough to contain the whole version resource + any space required for ansi to unicode conversion etc)

At least in some occasions, VerQueryValue performs conversion of the version data (e.g. Unicode to ASCII conversion when Unicode version of GetFileVersionInfo, but ASCII version of VerQueryValue are used). GetFileVersionInfoSize obviously computes the buffer size large enough to hold converted data.

GetFileVersionInfo copies data into the supplied buffer. As the format of this data isn't readily available/documented, you need to use the helper functionVerQueryValue to retrieve pointers to specific entries within the buffer GetFileVersionInfo filled in.
The way MS documented that "The pointer returned by VerQueryValue isn't allocated from anywhere - it's just pointing to somewhere within another buffer" is somewhat confusing.

Related

RegEnumValueA returns 87 ("Invalid Parameter")

I am currently implementing functions and classes from Borland C++ Builder 5 in Visual Studio 2022. One of the classes is used to handle Windows registry IO, and one of its methods is supposed to return a list of values which the current key contains.
I am using Windows' RegEnumValueA function which, after passing correct arguments, always returns 87 – which stands for "Invalid Parameter".
The method looks as follows:
void __fastcall TRegistry::GetValueNames(TStrings* Strings)
{
HKEY hKey = m_CurrentKey;
DWORD dwIndex = 0;
CHAR cValueName[TREG_MAX_VALUES_BUF_SIZE] = {};
LPSTR lpValueName = cValueName;
DWORD dwValueBufSize = TREG_MAX_VALUES_BUF_SIZE;
LPDWORD lpcchValueName = &dwValueBufSize;
LPDWORD lpType = NULL;
BYTE cData[TREG_MAX_VALUES_BUF_SIZE] = {};
LPBYTE lpData = cData;
LPDWORD lpcbData = NULL;
long res = RegEnumValueA(hKey, dwIndex, lpValueName, lpcchValueName, NULL, lpType, lpData, lpcbData);
while (res != ERROR_NO_MORE_ITEMS)
{
if (res != ERROR_SUCCESS)
{
throw(Exception(AnsiString(res)));
}
else
{
++dwIndex;
res = RegEnumValueA(hKey, dwIndex, lpValueName, lpcchValueName, NULL, lpType, lpData, lpcbData);
}
}
}
As you can see, all the parameters are set correctly. My suspicion is that the NULL passed after lpcchValueName is causing this problem, since I've seen some people having the same issue after looking it up. Unfortunately, these were problems from years ago and were related to system-specific issues on e.g. Windows NT. The call to this method looks as follows:
int main()
{
TRegistry* treg = new TRegistry; // Create a TRegistry object
if (treg->OpenKey(AnsiString("TRegistryTest"), false)) // Open the TRegistryTest key
{
if (treg->OpenKey(AnsiString("subkey1"), true)) // Open the subkey1 key
{
TStringList ts;
treg->GetValueNames(&ts); // Write the value names into a TStringList
}
}
delete treg;
}
TStringList is essentially a container which stores AnsiString values, which in turn are basically glorified std::strings.
I expected the RegEnumValueA function to exit with code 0 as long as there are registry values left to read - in this case, there are 4 values in total in TRegistryTest/subkey1.
Changing TREG_MAX_VALUES_BUF_SIZE does not influence the result at all - it's currently set to a value of 200.
Your lpcbData parameter, which you have set to NULL is invalid. This should be the address of a DWORD that specifies the size (in bytes) of the buffer pointed to by the lpData parameter (i.e. the size of the cData array).
From the documentation:
[in, out, optional] lpcbData
A pointer to a variable that specifies the size of the buffer pointed
to by the lpData parameter, in bytes. When the function returns, the
variable receives the number of bytes stored in the buffer.
This parameter can be NULL only if lpData is NULL.
Also, note that, on success, the values in the variables pointed to by that lpcbData argument and by lpcchValueName (i.e. dwValueBufSize) will be modified to contain the actual sizes of the data/value returned. So, you should reset those before each call. For lpcchValueName, you would use a line like dwValueBufSize = TREG_MAX_VALUES_BUF_SIZE;, with similar code for the lpcbData target, depending on what you call that variable. (And I'm not sure it's an especially good idea to use the same size variable for both, as your comment seems to suggest.)
If you look at C++Builder 5's source code for its TRegistry::GetValueNames() method, you would see that there are two big differences between its approach versus your approach:
BCB5 first calls RegQueryInfoKeyA() to retrieve the number of values in the key, and the length of the longest value name in the key. It then allocates a buffer of that length, and then runs a for loop calling RegEnumValueA() to retrieve the name for each index. But it ignores the return value, which means it could fail if the Registry key is modified mid-loop.
Whereas you are (rightly so) calling RegEnumValueA() in a while loop until it reaches the end of the list or fails. But, you are using a fixed-length buffer to receive the names. 200 should be OK in practice for most systems, but you should use a dynamically allocated buffer and pay attention to RegEnumValueA()'s return value so you can know when it tells you that it needs additional buffer space that you can then allocate.
BCB5 sets the lpType, lpData, and lpcbData parameters of RegEnumValueA() to NULL, since it does not need those data.
Whereas you are setting the lpData parameter to the address of a local buffer, which is wrong (as other comments/answers have already pointed out), and unnecessary anyway since all you really want is each value's name and not its content.

Why should I use GetBuffer member of CString instead of SetAt?

I'm currently studying MFC library and I wonder why should I use GetBuffer member which returns pointer to CString object buffer over other member functions which allow to read and change characters in that object?
For example why should I do (code changes first character of CString object):
CString aString(_T("String")); //new CString object
LPTSTR p = aString.GetBuffer(); //create new pointer to aString buffer
_tcsncpy(p, LPCTSTR(_T("a")), 1); //set first character to 'a'
aString.ReleaseBuffer(); //free allocated memory
Instead of:
CString aStr(_T("String")); //new CString object
aStr.SetAt(0, _T('a')); //set character at 0 position to 'a'
I suppose there is a more appropriate application to use GetBuffer() member, but I can't figure out what it can be... This function requires ReleaseBuffer() to free memory, and I may cause memory leaks when ReleaseBuffer() is not called. Is there any advantage of using it?
Don't use GetBuffer unless you have no alternative. Precisely because of (1) the reason you already know, that it must be followed with ReleaseBuffer which you may forget to do, leading to a resource leak. And (2) you might inadvertently make changes to the underlying data rendering it inconsistent in some way. More often than not the functions GetString, SetString, GetAt and SetAt will do what you need and have no disadvantages. Prefer them.
In above example it is preferable to use the SetAt method.
In some cases you need GetBuffer to directly access the buffer, mainly when used with WinAPI functions. For example, to use ::GetWindowText with WinAPI code you need to allocate a buffer as follows:
int len = ::GetWindowTextLength(m_hWnd) + 1;
char *buf = new char[len];
::GetWindowText(m_hWnd, buf, len);
...
delete[] buf;
The same thing can be done in MFC with CWnd::GetWindowText(CString&). But MFC has to use the same basic WinAPI functions, through GetBuffer. MFC's implementation of CWnd::GetWindowText is roughly as follows:
void CWnd::GetWindowText(CString &str)
{
int nLen = ::GetWindowTextLength(m_hWnd);
::GetWindowText(m_hWnd, str.GetBufferSetLength(nLen), nLen+1);
str.ReleaseBuffer();
}

Why do I need to cast the lpBuffer (LPTSTR) parameter in FormatMessage?

In Windows' FormatMessage() function, the parameter:
_Out_ LPTSTR lpBuffer
Is doing my head in. Following along from Hart's Windows System Programming book, I'm declaring an LPTSTR pointer to be used as the lpBuffer (e.g. LPTSTR errortext;), and then calling the FormatMessage() function.
The correct way to pass in this parameter is: (LPTSTR)&errorText
This works fine. But I don't understand why I need to write (LPTSTR). I understand that's typecasting and I read about it but it doesn't make sense to me, because I'm not changing the variable type or anything, I declared it as an LPTSTR and I'm passing its memory address to the function, the function expects an LPTSTR and I passed it an LPTSTR, so why do I need to put (LPTSTR) as part of the lpBuffer parameter?
The parameter lpBuffer of FormatMessage() is documented as follows:
A pointer to a buffer that receives the null-terminated string that
specifies the formatted message. If dwFlags includes
FORMAT_MESSAGE_ALLOCATE_BUFFER, the function allocates a buffer using
the LocalAlloc function, and places the pointer to the buffer at the
address specified in lpBuffer.
So there are 2 different usages of FormatMessage(),
1) Provide your own buffer
const DWORD bufsize = ....;
TCHAR buf[bufsize];
FormatMessage(.... buf, bufsize, ....); // buf is passed as a TCHAR*
2) FormatMessage allocates a buffer for you
const DWORD bufsize = ....;
TCHAR* buf = 0;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | ....,
.... (LPTSTR)&buf, bufsize, ....); // &buf is a TCHAR** so type-cast needed!
....
LocalFree(buf);
In #1, you have to pass the address of the first TCHAR in your buffer, and the function simply fills it the buffer.
In #2, the function needs to tell you where it allocates a new buffer, so you have to tell it where to place that address. You have to pass the address of a pointer variable that receives the address.
In short:
#1 needs a TCHAR* to an existing buffer
#2 needs a TCHAR** that receives a new buffer
That is why the lpBuffer parameter has to be type-casted when using #2.

How do I call the UrlCanonicalize API function correctly?

HRESULT UrlCanonicalize(
_In_ PCTSTR pszUrl,
_Out_ PTSTR pszCanonicalized,
_Inout_ DWORD *pcchCanonicalized,
DWORD dwFlags
);
Example:
LPCTSTR pszURL = URL.c_str();
LPSTR pszOutPut = new CHAR[ strUrl.length ];
DWORD* dwCount = new DWORD[ strUrl.length ];
hRes = UrlCanonicalize( pszURL, pszOutPut,dwCount, URL_ESCAPE_UNSAFE );
Output:
E_INVALIDARG
This API fails and returns E_INVALIDARG every time I try to call it. Please give me a working code snippet to call the UrlCanonicalize function.
If you know the C++ language, the SDK documentation for the function pretty much tells you everything that you need to know:
You pass it a C-style nul-terminated string that contains your URL.
You pass it pointer to a buffer to receive the output string.
You pass it one or more flags that customize the function's behavior.
And finally, it returns to you an HRESULT value, which is an error code. If it succeeds, that value will be S_OK. If it fails, it will be some other error code.
It works like this:
std::wstring originalURL(L"http://www.example.com/hello/cruel/../world/");
// Allocate a buffer of the appropriate length.
// It needs to be at least as long as the input string.
std::wstring canonicalURL(originalURL.length() + 1, L'\0');
DWORD length = originalURL.length() + 1;
// Call the function to modify the string.
HRESULT hr = UrlCanonicalize(originalURL.c_str(), // input string
&canonicalURL[0], // buffer
&length, // pointer to a DWORD that contains the length of the buffer
URL_UNESCAPE | URL_ESCAPE_UNSAFE);
if (SUCCEEDED(hr))
{
// The function succeeded.
// Your canonicalized URL is in the canonicalURL string.
MessageBox(nullptr, canonicalURL.c_str(), L"The URL is:", MB_OK);
}
else
{
// The function failed.
// The hr variable contains the error code.
throw std::runtime_error("The UrlCanonicalize function failed.");
}
If you want to make sure that the buffer is sufficiently long (and avoid having to handle that error), use the constant INTERNET_MAX_URL_LENGTH (declared in WinInet.h) when allocating it:
std::wstring canonicalURL(INTERNET_MAX_URL_LENGTH, L'\0');
DWORD length = INTERNET_MAX_URL_LENGTH;
The code you tried has a couple of problems:
You've incorrectly initialized the dwCount variable. The function wants a pointer, but that doesn't mean you should declare the variable as a pointer. Nor do you want an array; this is a single DWORD value. So you need to declare it as a regular DWORD, and then use the address-of operator (&) to pass the function a pointer to that variable. Right now, you're passing the function garbage, so it's failing.
You're using C-style strings, which you should avoid in C++ code. Use the C++ string class (std::wstring for Windows code), which is exception safe and manages memory for you. As you already know, the c_str() member function gives you easy access to a C-style nul-terminated string like all C APIs want. This works fine, you do not need to use raw character arrays yourself. Avoid new whenever possible.
Potentially, a third problem is that you're trying to use the C++ string type std::string instead of std::wstring. The former is an 8-bit string type and doesn't support Unicode in a Windows environment. You want std::wstring, which is a wide string with Unicode support. It's what all the Windows API functions expect if you have the UNICODE symbol defined for your project (which it is by default).
Here you go:
LPCTSTR pszURL = URL.c_str();
DWORD nOutputLength = strUrl.length * 2 + 32;
LPTSTR pszOutPut = new TCHAR[nOutputLength];
hRes = UrlCanonicalize( pszURL, pszOutPut, &nOutputLength, URL_ESCAPE_UNSAFE);
On the third parameter you provided garbage instead of pointer to initialized value, so you had API failure back. MSDN has it all for you:
A pointer to a value that, on entry, is set to the number of characters in the pszCanonicalized buffer.

RegKeyValue returning nonsense data

char value[255];
DWORD BufferSize = 8192;
RegGetValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"ProductName", RRF_RT_ANY, NULL, &value, &BufferSize);
cout << value;
After RegKeyValue() runs, it appears that value is
value 0x0034f50c "ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ... char[255]
What's going on here?
Note: RegKeyValue() returns 0
There are two issues here.
Make sure the return value of RegGetValue is ERROR_SUCCESS. If it is not, the routine failed. Also, you can check to see what was written into BufferSize, as RegGetValue specifies the number of bytes written.
You're passing in a buffer defined as char value[255];, then specifying it's length as 8192. This can cause a buffer overrun.
You didn't check the return value of RegGetValue. Most likely the call failed and the buffer value was never assigned anything. Always check return values.
From the code we can see, I note that you are lying about the buffer size. You say that it is 8192 bytes. But you only allocated 255 bytes. You are also calling the Unicode version of the API, but passing in a char buffer. If you are expecting string data then you need to supply a buffer of wide characters. The Unicode version of this API will return string data as UTF-16 encoded text.
Once you get all that sorted you next need to check what type is stored in that value. You are passing NULL for the type parameter. Pass a pointer to a variable and find out whether or not a string really is stored
there. You will also need to read how many bytes are read and set the null-terminator in your buffer accordingly.