Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GetPrivateProfileString - Buffer length

Tags:

winapi

ini

Windows' GetPrivateProfileXXX functions (used for working with INI files) have some strange rules about dealing with buffer lengths.

GetPrivateProfileString's documentation states:

If [..] the supplied destination buffer is too small to hold the requested string, the string is truncated and followed by a null character, and the return value is equal to nSize minus one.

I read this and I realised that this behaviour makes it impossible to differentiate between two scenarios in-code:

  • When the value string's length is exactly equal to nSize - 1.
  • When the nSize value (i.e. the buffer) is too small.

I thought I'd experiment:

I have this in an INI file:

[Bar]
foo=123456

And I called GetPrivateProfileString with these arguments as a test:

// Test 1. The buffer is big enough for the string (16 character buffer).
BYTE* buffer1 = (BYTE*)calloc(16, 2); // using 2-byte characters ("Unicode")
DWORD result1 = GetPrivateProfileString(L"Bar", L"foo", NULL, buffer, 16, fileName);

// result1 is 6
// buffer1 is { 49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 0, 0, 0, 0, ... , 0, 0 }

// Test 2. The buffer is exactly sufficient to hold the value and the trailing null (7 characters).
BYTE* buffer2 = (BYTE*)calloc(7, 2);
DWORD result2 = GetPrivateProfileString(L"Bar", L"foo", NULL, buffer, 7, fileName);

// result2 is 6. This is equal to 7-1.
// buffer2 is { 49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 0, 0 }

// Test 3. The buffer is insufficient to hold the value and the trailing null (6 characters).
BYTE* buffer3 = (BYTE*)calloc(6, 2);
DWORD result3 = GetPrivateProfileString(L"Bar", L"foo", NULL, buffer, 6, fileName);

// result3 is 5. This is equal to 6-1.
// buffer3 is { 49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 0, 0 }

A program calling this code would have no way of knowing for sure if the actual key value is indeed 5 characters in length, or even 6, as in the last two cases result is equal to nSize - 1.

The only solution is to check whenever result == nSize - 1 and recall the function with a larger buffer, but this would be unnecessary in the cases where the buffer is of exactly the right size.

Isn't there a better way?

like image 486
Dai Avatar asked May 08 '12 23:05

Dai


1 Answers

There is no better way. Just try to make sure the first buffer is large enough. Any method that solves this problem would have to make use of something not described in the documentation and hence would have no guarantee of working.

like image 183
Mike Kwan Avatar answered Oct 23 '22 17:10

Mike Kwan