9

WindowsのGetPrivateProfileXXX関数(INIファイルの操作に使用)には、バッファー長の処理に関していくつかの奇妙な規則があります。

GetPrivateProfileStringのドキュメントには次のように記載されています。

[..]提供された宛先バッファが小さすぎて要求された文字列を保持できない場合、文字列は切り捨てられ、その後にヌル文字が続き、戻り値はnSizeから1を引いた値になります。

これを読んで、この動作により、コード内の2つのシナリオを区別できないことに気付きました。

  • 値の文字列の長さが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文字であるかどうかを確実に知る方法がありません。これは、最後の2つの場合の結果がnSize-1に等しいためです。

唯一の解決策は、result == nSize --1の場合は常にチェックし、より大きなバッファーで関数を呼び出すことですが、バッファーが正確に正しいサイズである場合、これは不要です。

もっと良い方法はありませんか?

4

6 に答える 6

4

これ以上の方法はありません。最初のバッファが十分に大きいことを確認してください。この問題を解決する方法は、ドキュメントに記載されていないものを使用する必要があるため、機能する保証はありません。

于 2012-05-08T23:39:48.923 に答える
3

アンティークコードの一部を将来に持ち込む作業をしているときに、バッファリングとプライベートプロファイルAPIに関するこの質問を見つけました。私自身の実験と調査の結果、文字列が正確にnSize -1の場合と、バッファが小さすぎる場合の違いを判断できないという、質問者の元のステートメントを確認できます。

もっと良い方法はありますか?マイクからの受け入れられた答えは、ドキュメントによるとありません、そしてあなたはただバッファが十分に大きいことを確認することを試みるべきであると言います。マークはバッファを増やすように言います。ローマンはチェックエラーコードを言います。一部のランダムなユーザーは、十分な大きさのバッファーを提供する必要があると言い、Marcとは異なり、自分のバッファーを拡張するコードを表示します。

もっと良い方法はありますか?事実を知りましょう!

ProfileString APIが古くなったため、この質問のタグは特定の言語に関係せず、読みやすくするために、VB6を使用して例を示すことにしました。あなた自身の目的のためにそれらを自由に翻訳してください。


GetPrivateProfileStringドキュメント

GetPrivateProfileStringのドキュメントによると、これらのプライベートプロファイル関数は、16ビットのWindowsベースのアプリケーションとの互換性のためにのみ提供されています。これらのAPI関数で実行できることの制限を理解できるため、これはすばらしい情報です。

16ビットの符号付き整数の範囲は-32,768〜32,767で、符号なしの16ビット整数の範囲は0〜65,535です。これらの関数が本当に16ビット環境で使用するために作成されている場合、遭遇する数値はこれら2つの制限のいずれかに制限される可能性が高くなります。

ドキュメントには、返されるすべての文字列はヌル文字で終わると記載されており、提供されたバッファに収まらない文字列は切り捨てられ、ヌル文字で終了するとも記載されています。したがって、文字列がバッファに収まる場合、最後から2番目の文字は最後の文字と同様にnullになります。最後の文字だけがnullの場合、抽出された文字列は指定されたバッファとまったく同じ長さ-1であるか、バッファが文字列を保持するのに十分な大きさではありませんでした。

最後から2番目の文字がnullでない場合、抽出された文字列が正確な長さであるか、バッファに対して大きすぎる場合、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文字の場合、バッファにはファイルの文字列が含まれ、1つのヌル文字で終わります。

これは、完璧な解決策ではありませんが、最初の解決策を提供します。最初のバッファが十分に大きいことを常に確認したい場合は、そのバッファを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文字未満の場合、それほど大きなバッファを作成する理由はないかもしれません。

ドキュメントの備考セクションでは、初期化ファイルのセクションは次の形式である必要があると記載されています。

[セクション]
key= string

各セクションには2つの角括弧と等号が含まれていると想定できます。簡単なテストの後、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キロバイトはそれほど多くなく、今日のコンピューターはかなり高速です。

GetPrivateProfileString APIをかなり検索しましたが、通常、APIの知識が豊富でない人が、必要に応じて十分な大きさのバッファーを作成しようとすると、255のバッファー長を選択することがわかりました。最大254文字の長さの文字列をファイルから読み取ることができます。なぜ誰かがこれを使い始めたのかはわかりませんが、バッファ長が8ビットの符号なしの数値に制限されている文字列を使用してこのAPIを想像した人がいると思います。おそらくこれはWIN16の制限でした。

最大バッファー長が短い場合を除いて、バッファーを64バイトの下位から開始し、最大バッファー長または65,536までの数を4倍にします。数値を2倍にすることもできます。乗算を大きくすると、ファイルを読み取って大きな文字列を探す回数が減りますが、比較的言えば、中程度の長さの文字列には余分なパディングが含まれる場合があります。

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の機能によると、これは許容可能な初期化ファイルです。

[]
= Hello world!

ウィキペディアによると、空白の解釈はさまざまです。さらに別のテストの後、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未満であり、新しいバッファ制限を使用して1回だけ読み取ります。

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

たぶん、GetLastError直後に電話GetPrivateProfileStringするのが道です。バッファが十分に大きく、他にエラーがないGetLastError場合は、0を返します。バッファが小さすぎる場合は、をGetLastError返します234 (0xEA) ERROR_MORE_DATA

于 2015-11-10T21:34:02.207 に答える
0

少し遅れていることは知っていますが、すばらしい解決策を思いつきました。バッファスペースが残っていない場合(戻り長+ 1 =バッファ長)、バッファを拡張して値を再度取得します。バッファスペースが残るまで、このプロセスを繰り返します。

于 2016-05-13T16:05:29.717 に答える
-1

確かに最善の解決策はBroganのものですが、バッファサイズの上限としてファイルサイズをチェックするのは間違っています。特に、WindowsまたはシステムフォルダにあるINIファイルを処理する場合、レジストリで読み取りおよび/または書き込みが行われるようにマップされたキーの多くがあります。マッピング構造は次の場所にあります。

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

これがどのように機能するかについての完全な説明については、ドキュメントの備考セクションをGetPrivateProfileString読むことができます。

したがって、レジストリに再マップされた多くの文字列が十分に長くなる可能性がありますが、ディスク上の小さなINIファイルです。この場合、ソリューションは読み取りに失敗します。

このソリューションには、目的のファイルへの絶対パスを使用しない場合、またはGetPrivateProfileStringsWindowsディレクトリで初期化ファイルを検索するため、プログラムの現在の作業ディレクトリにない場合にも、別の小さな問題があります。この操作はFileLen関数内になく、ソリューションはそれをチェックしません。

最終的に64Kのメモリを割り当て、これを制限として受け入れました。

于 2020-02-07T09:45:42.700 に答える