2012-05-08 7 views
6

Le funzioni GetPrivateProfileXXX di Windows (utilizzate per lavorare con i file INI) hanno alcune strane regole su come gestire le lunghezze del buffer.GetPrivateProfileString - Buffer length

documentazione afferma di GetPrivateProfileString:

Se [..] il buffer di destinazione fornito è troppo piccolo per contenere la stringa di richiesta, la stringa viene troncata e seguita da un carattere null, e il valore di ritorno è pari a nSize meno uno.

I leggere questo e ho capito che questo comportamento rende impossibile distinguere tra due scenari in-codice:

  • Quando la lunghezza della stringa valore è esattamente uguale a nSize - 1.
  • Quando il valore nSize (cioè il buffer) è troppo piccolo.

ho pensato di sperimentare:

Ho questo in un file INI:

[Bar] 
foo=123456 

e ho chiamato GetPrivateProfileString con questi argomenti come un 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 } 

Un programma che chiama questo codice non avrebbe modo di sapere con certezza se il valore della chiave effettiva è effettivamente di 5 caratteri di lunghezza, o anche di 6, come negli ultimi due casi es risultato è uguale a nSize - 1.

L'unica soluzione è controllare ogni risultato == nSize - 1 e richiamare la funzione con un buffer più grande, ma questo non sarebbe necessario nei casi in cui il buffer è esattamente il misura giusta.

Non c'è un modo migliore?

risposta

5

Non esiste un modo migliore. Cerca di assicurarti che il primo buffer sia abbastanza grande. Qualsiasi metodo che risolva questo problema dovrebbe fare uso di qualcosa non descritto nella documentazione e quindi non avrebbe alcuna garanzia di funzionamento.

1

No, sfortunatamente, non c'è un modo migliore. Devi fornire un buffer abbastanza grande. Se non è sufficiente, riallocare il buffer. Ho preso un frammento di codice da here, e adattati al vostro 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))); 

ma, nel caso specifico, un nome di file non può avere una lunghezza maggiore di MAX_PATH, così (MAX_PATH+1)*2 sia sempre in forma.

+0

Si suppone che sia un codice C o C++? –

0

Forse, chiamare GetLastError subito dopo GetPrivateProfileString è un modo per andare. Se il buffer è abbastanza grande e non ci sono altri errori, GetLastError restituisce 0. Se il buffer è troppo piccolo, GetLastError restituisce 234 (0xEA) ERROR_MORE_DATA.

+0

Sfortunatamente, le funzioni INI restituiscono sempre 'ERROR_MORE_DATA' quando riempiono completamente il buffer (anche senza troncare i dati). – efotinis

0

So che è un po 'tardi, ma ho trovato una soluzione eccezionale. Se non è rimasto spazio nel buffer (lunghezza di ritorno + 1 = lunghezza del buffer), aumentare il buffer e recuperare il valore. Ripeti la procedura fino a quando non rimane spazio nel buffer.

Problemi correlati