2012-05-08 9 views
6

Las funciones GetPrivateProfileXXX de Windows (utilizadas para trabajar con archivos INI) tienen algunas reglas extrañas sobre cómo lidiar con las longitudes de búfer.GetPrivateProfileString - Longitud de búfer

estados de documentación de GetPrivateProfileString:

Si [..] el búfer de destino suministrada es demasiado pequeño para contener la cadena solicitada, la cadena se trunca y seguido por un carácter nulo, y el valor de retorno es igual a nTamaño menos uno.

leí esto y me di cuenta que este comportamiento hace que sea imposible diferenciar entre dos escenarios en-código:

  • Cuando la longitud de la cadena de valor es exactamente igual a nTamaño - 1.
  • Cuando el valor nSize (es decir, el buffer) es demasiado pequeño.

pensé que había experimentar:

tengo esto en un archivo INI:

[Bar] 
foo=123456 

Y llamé GetPrivateProfileString con estos argumentos como una prueba:

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

Un programa que invoque este código no tendría forma de saber con certeza si el valor real de la clave es de hecho 5 caracteres de longitud, o incluso 6, como en los últimos dos cas El resultado es igual a nSize - 1.

La única solución es comprobar siempre result == nSize - 1 y recuperar la función con un buffer más grande, pero esto sería innecesario en los casos donde el buffer es exactamente el Talla correcta.

¿No hay una forma mejor?

Respuesta

5

No hay mejor manera. Solo intenta asegurarte de que el primer buffer sea lo suficientemente grande. Cualquier método que resuelva este problema debería hacer uso de algo no descrito en la documentación y, por lo tanto, no tendría garantía de funcionamiento.

1

No, desafortunadamente, no hay una mejor manera. Tienes que proporcionar un buffer lo suficientemente grande. Si no es suficiente, reasigne el búfer. Me tomó un fragmento de código de here, y adaptado a su caso:

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

pero, en su caso específico, un nombre de archivo no puede tener una longitud mayor que MAX_PATH, por lo (MAX_PATH+1)*2 será siempre conveniente.

+0

¿Se supone que es un código C o C++? –

0

Tal vez, llamando al GetLastError justo después de GetPrivateProfileString es un camino por recorrer. Si el búfer es lo suficientemente grande y no hay otros errores, GetLastError devuelve 0. Si el búfer es demasiado pequeño, GetLastError devuelve 234 (0xEA) ERROR_MORE_DATA.

+0

Desafortunadamente, las funciones INI siempre devuelven 'ERROR_MORE_DATA' cuando llenan completamente el búfer (incluso sin truncar los datos). – efotinis

0

Sé que es un poco tarde, pero se me ocurrió una solución increíble. Si no queda espacio en el búfer (longitud de retorno + 1 = longitud del búfer), crezca el búfer y obtenga el valor nuevamente. Repita ese proceso hasta que quede espacio en el búfer.