2012-05-08 32 views
6

Các chức năng GetPrivateProfileXXX của Windows (được sử dụng để làm việc với các tệp INI) có một số quy tắc lạ về xử lý độ dài bộ đệm.GetPrivateProfileString - Chiều dài bộ đệm

bang tài liệu GetPrivateProfileString của:

Nếu [..] bộ đệm nơi cung cấp là quá nhỏ để giữ chuỗi yêu cầu, chuỗi là cắt ngắn và sau đó là một kí tự null, và giá trị trả về bằng nSize trừ một.

Tôi đọc và tôi nhận ra rằng hành vi này làm cho nó không thể phân biệt giữa hai kịch bản trong mã:

  • Khi chiều dài chuỗi giá trị là chính xác bằng nKích cỡ - 1.
  • Khi Giá trị nSize (tức là bộ đệm) quá nhỏ.

tôi nghĩ rằng tôi muốn thử nghiệm:

Tôi có điều này trong một tập tin INI:

[Bar] 
foo=123456 

Và tôi gọi GetPrivateProfileString với những lập luận này như một thử nghiệm:

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

Một chương trình gọi mã này sẽ không có cách nào để biết chắc chắn nếu giá trị khóa thực sự thực sự là 5 ký tự, hoặc thậm chí 6, như trong hai cas cuối cùng Kết quả es bằng nSize - 1.

Giải pháp duy nhất là kiểm tra bất cứ khi nào kết quả == nSize - 1 và gọi hàm với bộ đệm lớn hơn, nhưng điều này không cần thiết trong trường hợp bộ đệm là chính xác đúng kích cỡ.

Không có cách nào tốt hơn?

Trả lời

5

Không có cách nào tốt hơn. Chỉ cần cố gắng đảm bảo bộ đệm đầu tiên đủ lớn. Bất kỳ phương pháp nào giải quyết vấn đề này sẽ phải sử dụng một cái gì đó không được mô tả trong tài liệu và do đó sẽ không có bảo đảm làm việc.

1

Không, thật không may, không có cách nào tốt hơn. Bạn phải cung cấp một bộ đệm đủ lớn. Nếu nó không đủ, hãy tái phân bổ bộ đệm. Tôi lấy một đoạn mã từ here, và phù hợp với trường hợp của bạn:

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

nhưng, trong trường hợp cụ thể của bạn, một tên tập tin có thể không có một chiều dài lớn hơn MAX_PATH, vì vậy (MAX_PATH+1)*2 sẽ luôn phù hợp.

+0

Đó có phải là mã C hoặc C++ không? –

0

Có thể, gọi GetLastError ngay sau GetPrivateProfileString là một cách để thực hiện. Nếu bộ đệm đủ lớn và không có lỗi nào khác, GetLastError trả về 0. Nếu bộ đệm quá nhỏ, GetLastError trả lại 234 (0xEA) ERROR_MORE_DATA.

+0

Thật không may, các hàm INI luôn trả về 'ERROR_MORE_DATA' khi chúng lấp đầy hoàn toàn bộ đệm (ngay cả khi không cắt xén dữ liệu). – efotinis

0

Tôi biết đã muộn một chút, nhưng tôi đã đưa ra một giải pháp tuyệt vời. Nếu không có không gian đệm còn lại (chiều dài trở lại + 1 = chiều dài bộ đệm), sau đó phát triển bộ đệm và nhận lại giá trị. Lặp lại quá trình đó cho đến khi có không gian bộ nhớ còn lại.

Các vấn đề liên quan