9

Windows 的 GetPrivateProfileXXX 函数(用于处理 INI 文件)在处理缓冲区长度方面有一些奇怪的规则。

GetPrivateProfileString 的文档指出:

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

我读了这篇文章,我意识到这种行为使得无法区分代码中的两种场景:

  • 当值字符串的长度正好等于 nSize - 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 个字符,因为在最后两种情况下,结果等于 nSize - 1。

唯一的解决方案是检查 result == nSize - 1 并使用更大的缓冲区调用函数,但在缓冲区大小正好合适的情况下,这是不必要的。

没有更好的方法吗?

4

6 回答 6

4

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

于 2012-05-08T23:39:48.923 回答
3

当我致力于将一些古老的代码带入未来时,我发现了这个关于缓冲和私有配置文件 API 的问题。经过我自己的实验和研究,我可以确认提问者关于无法确定字符串何时恰好为 nSize - 1 或缓冲区太小之间的差异的原始陈述。

有没有更好的办法?Mike 接受的回答说没有根据文档,您应该尝试确保缓冲区足够大。Marc 说要增加缓冲区。Roman 说检查错误代码。一些随机用户说您需要提供一个足够大的缓冲区,并且与 Marc 不同的是,它继续显示一些扩展他的缓冲区的代码。

有没有更好的办法?让我们了解事实!

由于 ProfileString API 的年代久远,因为这个问题的所有标签都不涉及任何特定语言并且为了便于阅读,我决定使用 VB6 来展示我的示例。随意为您自己的目的翻译它们。


GetPrivateProfileString 文档

根据GetPrivateProfileString 文档,提供这些 Private Profile 函数只是为了与基于 Windows 的 16 位应用程序兼容。这是很好的信息,因为它使我们能够了解这些 API 函数可以做什么的限制。

16 位有符号整数的范围为 -32,768 到 32,767,无符号 16 位整数的范围为 0 到 65,535。如果这些函数真的是为在 16 位环境中使用而设计的,那么我们遇到的任何数字很可能都会被限制在这两个限制之一。

该文档指出,返回的每个字符串都将以空字符结尾,并且还说不适合提供的缓冲区的字符串将被截断并以空字符终止。因此,如果一个字符串确实适合缓冲区,则倒数第二个字符以及最后一个字符都将为空。如果只有最后一个字符为空,则提取的字符串与提供的缓冲区的长度完全相同 - 1 或缓冲区不够大以容纳字符串。

在倒数第二个字符不为空的情况下,提取的字符串的长度准确或对于缓冲区来说太大,GetLastError 将返回错误号234 ERROR_MORE_DATA (0xEA),使我们无法区分它们。


GetPrivateProfileString 接受的最大缓冲区大小是多少?

虽然文档没有说明最大缓冲区大小,但我们已经知道这个 API 是为 16 位环境设计的。经过一些实验,我可以得出结论,最大缓冲区大小为65,536. 如果文件中的字符串大于 65,535 个字符,我们会在尝试读取字符串时开始看到一些奇怪的行为。如果文件中的字符串长度为 65,536 个字符,则检索到的字符串长度为 0 个字符。如果文件中的字符串长度为 65,546 个字符,则检索到的字符串长度为 10 个字符,以空字符结尾并从文件中包含的字符串的最开头截断。API 将写入大于 65,535 个字符的字符串,但无法读取大于 65,535 个字符的任何内容。如果缓冲区长度为 65,536 且文件中的字符串长度为 65,535 个字符,则缓冲区将包含文件中的字符串,并且还以单个空字符结尾。

这为我们提供了第一个虽然不是完美的解决方案。如果您想始终确保您的第一个缓冲区足够大,请将该缓冲区设置为 65,536 个字符长。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String) As String
    On Error GoTo iniReadError
    Dim Buffer As String
    Dim Result As Long
    Buffer = String$(65536, vbNullChar)
    Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, 65536, Pathname)
    If Result <> 0 Then
        iniRead = Left$(Buffer, Result)
    Else
        iniRead = Default
    End If
iniReadError:
End Function

现在我们知道了最大缓冲区大小,我们可以使用文件的大小来修改它。如果您的文件长度小于 65,535 个字符,则可能没有理由创建如此大的缓冲区。

在文档的备注部分中,它说初始化文件中的一个部分必须具有以下形式:

[部分]
键=字符串

我们可以假设每个部分都包含两个方括号和一个等号。经过一个小测试,我能够验证 API 是否可以接受节和键之间的任何类型的换行符(vbLf、vbCr 或 vbCrLf / vbNewLine)。这些细节以及节和键名的长度将允许我们缩小最大缓冲区长度,并确保文件大小足以在我们尝试读取文件之前包含一个字符串。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String) As String
    On Error Resume Next
    Dim Buffer_Size As Long
    Err.Clear
    Buffer_Size = FileLen(Pathname)
    On Error GoTo iniReadError
    If Err.Number = 0 Then
        If Buffer_Size > 4 + Len(Section) + Len(Key) Then
            Dim Buffer As String
            Dim Result As Long
            Buffer_Size = Buffer_Size - Len(Section) - Len(Key) - 4
            If Buffer_Size > 65535 Then
                Buffer_Size = 65536
            Else
                Buffer_Size = Buffer_Size + 1
            End If
            Buffer = String$(Buffer_Size, vbNullChar)
            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
            If Result <> 0 Then
                iniRead = Left$(Buffer, Result)
                Exit Function
            End If
        End If
    End If
    iniRead = Default
iniReadError:
End Function

增加缓冲区

现在我们已经非常努力地确保第一个缓冲区足够大,并且我们已经修改了最大缓冲区大小,对我们来说,从较小的缓冲区开始并逐渐增加缓冲区的大小来创建可能仍然更有意义一个足够大的缓冲区,我们可以从文件中提取整个字符串。根据文档,API 会创建 234 错误来告诉我们还有更多可用数据。他们使用这个错误代码告诉我们用更大的缓冲区重试是很有意义的。一遍又一遍地重试的缺点是它的成本更高。文件中的字符串越长,读取它所需的尝试次数越多,花费的时间就越长。64 KB 对于今天的计算机来说并不算多,而且今天的计算机速度非常快,

我已经对 GetPrivateProfileString API 进行了相当多的搜索,我发现通常当没有广泛了解 API 的人尝试创建足够大的缓冲区以满足他们的需求时,他们选择 255 的缓冲区长度。这将允许您可以从文件中读取最多 254 个字符的字符串。我不确定为什么有人开始使用它,但我假设有人在某个地方想象这个 API 使用缓冲区长度限制为 8 位无符号数的字符串。也许这是WIN16的限制。

除非最大缓冲区长度更小,否则我将从 64 字节的低缓冲区开始,然后将数字翻两番,直到最大缓冲区长度或 65,536。将数字加倍也是可以接受的,更大的乘法意味着更少尝试读取更大字符串的文件,而相对而言,一些中等长度的字符串可能有额外的填充。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String) As String
    On Error Resume Next
    Dim Buffer_Max As Long
    Err.Clear
    Buffer_Max = FileLen(Pathname)
    On Error GoTo iniReadError
    If Err.Number = 0 Then
        If Buffer_Max > 4 + Len(Section) + Len(Key) Then
            Dim Buffer As String
            Dim Result As Long
            Dim Buffer_Size As Long
            Buffer_Max = Buffer_Max - Len(Section) - Len(Key) - 4
            If Buffer_Max > 65535 Then
                Buffer_Max = 65536
            Else
                Buffer_Max = Buffer_Max + 1
            End If
            If Buffer_Max < 64 Then
                Buffer_Size = Buffer_Max
            Else
                Buffer_Size = 64
            End If
            Buffer = String$(Buffer_Size, vbNullChar)
            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
            If Result <> 0 Then
                If Buffer_Max > 64 Then
                    Do While Result = Buffer_Size - 1 And Buffer_Size < Buffer_Max
                        Buffer_Size = Buffer_Size * 4
                        If Buffer_Size > Buffer_Max Then
                            Buffer_Size = Buffer_Max
                        End If
                        Buffer = String$(Buffer_Size, vbNullChar)
                        Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                    Loop
                End If
                iniRead = Left$(Buffer, Result)
                Exit Function
            End If
        End If
    End If
    iniRead = Default
iniReadError:
End Function

改进的验证

根据您的实现,改进对路径名、部分和键名的验证可能会阻止您需要准备缓冲区。

根据维基百科的 INI 文件页面,他们说:

在 Windows 实现中,密钥不能包含字符等号 (=) 或分号 (;),因为它们是保留字符。该值可以包含任何字符。

在 Windows 实现中,该部分不能包含字符右括号 ( ] )。

对 GetPrivateProfileString API 的快速测试证明这只是部分正确。只要分号不在开头,我就可以在键名中使用分号。他们没有在文档或维基百科中提及任何其他限制,尽管可能还有更多限制。

查找 GetPrivateProfileString 接受的部分或键名的最大长度的另一个快速测试给了我 65,535 个字符的限制。使用大于 65,535 个字符的字符串的效果与我在测试最大缓冲区长度时的体验相同。另一项测试证明,此 API 将接受一个空白字符串作为部分或键名。根据 API 的功能,这是一个可接受的初始化文件:

[]
=你好世界!

根据维基百科,对空格的解释各不相同。在又一次测试之后,Profile String API 肯定会从部分和键名中去除空格,所以如果我们也这样做可能没问题。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String) As String
    On Error Resume Next
    If Len(Pathname) <> 0 Then
        Key = Trim$(Key)
        If InStr(1, Key, ";") <> 1 Then
            Section = Trim$(Section)
            If Len(Section) > 65535 Then
                Section = RTrim$(Left$(Section, 65535))
            End If
            If InStr(1, Section, "]") = 0 Then
                If Len(Key) > 65535 Then
                    Key = RTrim$(Left$(Key, 65535))
                End If
                If InStr(1, Key, "=") = 0 Then
                    Dim Buffer_Max As Long
                    Err.Clear
                    Buffer_Max = FileLen(Pathname)
                    On Error GoTo iniReadError
                    If Err.Number = 0 Then
                        If Buffer_Max > 4 + Len(Section) + Len(Key) Then
                            Dim Buffer As String
                            Dim Result As Long
                            Dim Buffer_Size As Long
                            Buffer_Max = Buffer_Max - Len(Section) - Len(Key) - 4
                            If Buffer_Max > 65535 Then
                                Buffer_Max = 65536
                            Else
                                Buffer_Max = Buffer_Max + 1
                            End If
                            If Buffer_Max < 64 Then
                                Buffer_Size = Buffer_Max
                            Else
                                Buffer_Size = 64
                            End If
                            Buffer = String$(Buffer_Size, vbNullChar)
                            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                            If Result <> 0 Then
                                If Buffer_Max > 64 Then
                                    Do While Result = Buffer_Size - 1 And Buffer_Size < Buffer_Max
                                        Buffer_Size = Buffer_Size * 4
                                        If Buffer_Size > Buffer_Max Then
                                            Buffer_Size = Buffer_Max
                                        End If
                                        Buffer = String$(Buffer_Size, vbNullChar)
                                        Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                                    Loop
                                End If
                                iniRead = Left$(Buffer, Result)
                                Exit Function
                            End If
                        End If
                    End If
                    iniRead = Default
                End If
            End If
        End If
    End If
iniReadError:
End Function

静态长度缓冲区

有时我们需要存储具有最大长度或静态长度的变量。用户名、电话号码、颜色代码或 IP 地址是您可能希望限制最大缓冲区长度的字符串示例。必要时这样做可以节省您的时间和精力。

在下面的代码示例中,Buffer_Max 将被限制为 Buffer_Limit + 1。如果限制大于 64,我们将从 64 开始并像以前一样扩展缓冲区。小于 64 并且我们只会使用我们的新缓冲区限制读取一次。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String, Optional Buffer_Limit As Long = 65535) As String
    On Error Resume Next
    If Len(Pathname) <> 0 Then
        Key = Trim$(Key)
        If InStr(1, Key, ";") <> 1 Then
            Section = Trim$(Section)
            If Len(Section) > 65535 Then
                Section = RTrim$(Left$(Section, 65535))
            End If
            If InStr(1, Section, "]") = 0 Then
                If Len(Key) > 65535 Then
                    Key = RTrim$(Left$(Key, 65535))
                End If
                If InStr(1, Key, "=") = 0 Then
                    Dim Buffer_Max As Long
                    Err.Clear
                    Buffer_Max = FileLen(Pathname)
                    On Error GoTo iniReadError
                    If Err.Number = 0 Then
                        If Buffer_Max > 4 + Len(Section) + Len(Key) Then
                            Dim Buffer As String
                            Dim Result As Long
                            Dim Buffer_Size As Long
                            Buffer_Max = Buffer_Max - Len(Section) - Len(Key) - 4
                            If Buffer_Limit > 65535 Then
                                Buffer_Limit = 65535
                            End If
                            If Buffer_Max > Buffer_Limit Then
                                Buffer_Max = Buffer_Limit + 1
                            Else
                                Buffer_Max = Buffer_Max + 1
                            End If
                            If Buffer_Max < 64 Then
                                Buffer_Size = Buffer_Max
                            Else
                                Buffer_Size = 64
                            End If
                            Buffer = String$(Buffer_Size, vbNullChar)
                            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                            If Result <> 0 Then
                                If Buffer_Max > 64 Then
                                    Do While Result = Buffer_Size - 1 And Buffer_Size < Buffer_Max
                                        Buffer_Size = Buffer_Size * 4
                                        If Buffer_Size > Buffer_Max Then
                                            Buffer_Size = Buffer_Max
                                        End If
                                        Buffer = String$(Buffer_Size, vbNullChar)
                                        Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                                    Loop
                                End If
                                iniRead = Left$(Buffer, Result)
                                Exit Function
                            End If
                        End If
                    End If
                    iniRead = Default
                End If
            End If
        End If
    End If
iniReadError:
End Function

使用 WritePrivateProfileString

为确保使用 GetPrivateProfileString 读取字符串没有问题,请在使用 WritePrivateProfileString 之前将字符串限制为 65,535 个或更少字符。包含相同的验证也是一个好主意。

Private Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long
Private Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long

Public Function iniRead(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, Optional ByVal Default As String, Optional Buffer_Limit As Long = 65535) As String
    On Error Resume Next
    If Len(Pathname) <> 0 Then
        Key = Trim$(Key)
        If InStr(1, Key, ";") <> 1 Then
            Section = Trim$(Section)
            If Len(Section) > 65535 Then
                Section = RTrim$(Left$(Section, 65535))
            End If
            If InStr(1, Section, "]") = 0 Then
                If Len(Key) > 65535 Then
                    Key = RTrim$(Left$(Key, 65535))
                End If
                If InStr(1, Key, "=") = 0 Then
                    Dim Buffer_Max As Long
                    Err.Clear
                    Buffer_Max = FileLen(Pathname)
                    On Error GoTo iniReadError
                    If Err.Number = 0 Then
                        If Buffer_Max > 4 + Len(Section) + Len(Key) Then
                            Dim Buffer As String
                            Dim Result As Long
                            Dim Buffer_Size As Long
                            Buffer_Max = Buffer_Max - Len(Section) - Len(Key) - 4
                            If Buffer_Limit > 65535 Then
                                Buffer_Limit = 65535
                            End If
                            If Buffer_Max > Buffer_Limit Then
                                Buffer_Max = Buffer_Limit + 1
                            Else
                                Buffer_Max = Buffer_Max + 1
                            End If
                            If Buffer_Max < 64 Then
                                Buffer_Size = Buffer_Max
                            Else
                                Buffer_Size = 64
                            End If
                            Buffer = String$(Buffer_Size, vbNullChar)
                            Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                            If Result <> 0 Then
                                If Buffer_Max > 64 Then
                                    Do While Result = Buffer_Size - 1 And Buffer_Size < Buffer_Max
                                        Buffer_Size = Buffer_Size * 4
                                        If Buffer_Size > Buffer_Max Then
                                            Buffer_Size = Buffer_Max
                                        End If
                                        Buffer = String$(Buffer_Size, vbNullChar)
                                        Result = GetPrivateProfileString(Section, Key, vbNullString, Buffer, Buffer_Size, Pathname)
                                    Loop
                                End If
                                iniRead = Left$(Buffer, Result)
                                Exit Function
                            End If
                        End If
                    End If
                    iniWrite Pathname, Section, Key, Default
                    iniRead = Default
                End If
            End If
        End If
    End If
iniReadError:
End Function

Public Function iniWrite(ByVal Pathname As String, ByVal Section As String, ByVal Key As String, ByVal Value As String) As Boolean
    On Error GoTo iniWriteError
    If Len(Pathname) <> 0 Then
        Key = Trim$(Key)
        If InStr(1, Key, ";") <> 1 Then
            Section = Trim$(Section)
            If Len(Section) > 65535 Then
                Section = RTrim$(Left$(Section, 65535))
            End If
            If InStr(1, Section, "]") = 0 Then
                If Len(Key) > 65535 Then
                    Key = RTrim$(Left$(Key, 65535))
                End If
                If InStr(1, Key, "=") = 0 Then
                    If Len(Value) > 65535 Then Value = Left$(Value, 65535)
                    iniWrite = WritePrivateProfileString(Section, Key, Value, Pathname) <> 0
                End If
            End If
        End If
    End If
iniWriteError:
End Function
于 2019-02-03T19:36:08.477 回答
1

不,不幸的是,没有更好的方法。您必须提供足够大的缓冲区。如果不够,请重新分配缓冲区。我从这里拿了一个代码片段,并适应了你的情况:

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总是合适的。

于 2012-05-08T23:50:25.740 回答
0

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

于 2016-05-13T16:05:29.717 回答
0

GetLastError也许,马上打电话GetPrivateProfileString是一种方法。如果缓冲区足够大并且没有其他错误,GetLastError则返回 0。如果缓冲区太小,则GetLastError返回234 (0xEA) ERROR_MORE_DATA

于 2015-11-10T21:34:02.207 回答
-1

最好的解决方案肯定是 Brogan 的,但是检查文件大小作为缓冲区大小的上限是错误的。尤其是在处理位于 Windows 或系统文件夹中的 INI 文件时,许多映射到注册表中的键被读取和/或写入。映射结构见:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping

有关其工作原理的完整说明,您可以阅读文档的备注部分GetPrivateProfileString

因此,您可以将许多字符串重新映射到足够长的注册表,但磁盘上只有一个小的 INI 文件。在这种情况下,解决方案无法读取。

当不使用所需文件的绝对路径或它不在程序的当前工作目录中时,该解决方案还有另一个小问题,因为GetPrivateProfileStrings在 Windows 目录中搜索初始化文件。此操作不在FileLen函数中,解决方案也不对此进行检查。

最终分配了 64K 的内存并接受了这个限制。

于 2020-02-07T09:45:42.700 回答