2012-05-08 176 views
6

Windows'GetPrivateProfileXXX函数(用于处理INI文件)有一些关于处理缓冲区长度的奇怪规则。GetPrivateProfileString - 缓冲区长度

GetPrivateProfileString的文档状态:

如果[..]提供的目标缓冲区太小,无法容纳请求字符串,字符串被截断,并后跟一个空字符,并且返回值等于nSize减1。

我读到这,我意识到,这种行为使得它不可能两个场景之间的区别在代码:

  • 当值字符串的长度正好等于n大小 - 1
  • 当nSize值(即缓冲区)太小。

我想我会尝试:

我有这样的INI文件:

[Bar] 
foo=123456 

我叫GetPrivateProfileString用这些参数作为测试:

// 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 } 

调用此代码的程序无法确定实际的键值是否确实是5个字符的长度,或甚至6个,如最后两个CAS中的值es结果等于nSize-1。

唯一的解决方案是每当检查结果== nSize-1时,检查函数是否具有较大的缓冲区,但在缓冲区正好是合适的尺码。

没有更好的方法吗?

回答

5

没有更好的方法。试着确保第一个缓冲区足够大。任何解决此问题的方法都必须使用文档中未描述的内容,因此不能保证工作。

1

不,不幸的是,没有更好的方法。你必须提供足够大的缓冲区。如果不够,请重新分配缓冲区。我参加了一个代码片段来自here,并且适合于您的情况:

int nBufferSize = 1000; 
int nRetVal; 
int nCnt = 0; 
BYTE* buffer = (BYTE*)calloc(1, 2); 

do 
{ 
    nCnt++; 
     buffer = (BYTE*) realloc (buffer , nBufferSize * 2 * nCnt); 
     DWORD nRetVal = GetPrivateProfileString(L"Bar", L"foo", NULL,   
      buffer, nBufferSize*nCnt, filename);  
} while((nRetVal == ((nBufferSize*nCnt) - 1)) || 
      (nRetVal == ((nBufferSize*nCnt) - 2))); 

,但在特定情况下,文件名不能有长度超过MAX_PATH越大,所以(MAX_PATH+1)*2永远适合。

+0

这应该是C或C++代码吗? –

0

也许,在GetPrivateProfileString之后立即致电GetLastError是一种方法。如果缓冲区足够大并且没有其他错误,则GetLastError返回0.如果缓冲区太小,则GetLastError返回234 (0xEA) ERROR_MORE_DATA

+0

不幸的是,当INI函数完全填充缓冲区时(即使不截断数据)INI函数总是返回'ERROR_MORE_DATA'。 – efotinis

0

我知道这有点晚,但我想出了一个很棒的解决方案。如果没有剩余的缓冲区空间(返回长度+ 1 =缓冲区长度),则增大缓冲区并再次获取该值。重复该过程,直到剩余缓冲空间。