プラグインのEditor_GetLineについて

  1. CSV を表示するプラグインを Delphi XE2 開発中ですが、判らない事があるので教えて下さい。

    以下の関数を作成して、プラグインから指定した行を取得してみました。

    1回目の「Editor_GetLine」で、文字数を取得して、2回目の「Editor_GetLine」で文字列を取得できました。
    この方法であってますでしょうか?

    「TGetLineInfo」の「flags」と「byteCrLf」の使い方が判らなかったので、0 を指定して取得しています。
    「flags」と「byteCrLf」の使用方法を教えてください。

    function TFormCsvList.GetLine(Index: Integer; var LineString: String; Sender: TObject): Integer;
    var
    iLen1: Integer;
    iMax1: Integer;
    iRow1: Integer;
    pGetLineInfo1: TGetLineInfo;
    pGetLineInfo2: TGetLineInfo;
    Buffer1: array [0..LINE_LENGTH_MAX+1] of WideChar;
    Buffer2: array [0..LINE_LENGTH_MAX+1] of WideChar;
    begin
    //1回目でサイズを取得
    pGetLineInfo1.cch := 0; // 0 を設定すると、バッファサイズを返す
    pGetLineInfo1.flags := 0; // 不明
    pGetLineInfo1.yLine := Index; // 0 ベースの行番号を渡す
    pGetLineInfo1.byteCrLf := 0; // 不明
    //取得
    iLen1 := Editor_GetLine(Application.Handle, @pGetLineInfo1, @Buffer1);
    //最大文字数を設定
    if iLen1 > LINE_LENGTH_MAX then
    begin
    iMax1 := LINE_LENGTH_MAX;
    end
    else
    begin
    iMax1 := iLen1;
    end;

    //2回目で文字列を取得
    pGetLineInfo2.cch := iMax1; // 0 を設定すると、バッファサイズを返す
    pGetLineInfo2.flags := 0; // 不明
    pGetLineInfo2.yLine := Index; // 0 ベースの行番号を渡す
    pGetLineInfo2.byteCrLf := 0; // 不明
    //取得
    Editor_GetLine(Application.Handle, @pGetLineInfo2, @Buffer2);

    //結果
    LineString := '';
    for iRow1 := 0 to iMax1-1 do
    begin
    LineString := LineString + String(Buffer2[iRow1]);
    end;
    //結果
    Result := iLen1;
    end;

    よろしくお願いします。

     |  大石剛司  |  返信
  2. プラグイン開発、お疲れ様です。

    > 1回目の「Editor_GetLine」で、文字数を取得して、2回目の「Editor_GetLine」で文字列を取得できました。
    > この方法であってますでしょうか?
    はい、間違ってはいませんが、この場合は 1 度目の「Editor_GetLine」は不要ですね。

    Editor_GetLine で cch := 0 で、バッファサイズを取得するのは、必要最小限のメモリを確保するためなので、この例のようにあらかじめ LINE_LENGTH_MAX サイズのバッファが確保されている場合は、2 回目の「Editor_GetLine」だけでも大丈夫です。

    2 回目の cch := iMax1 を、cch := LINE_LENGTH_MAX としてやれば、そこに収まる分だけの文字が取得されると思います。

    必要な文字数を取得したうえ、行全体を確実に取得したい場合は、今回の例のように 2 度、「Editor_GetLine」を発行してやる必要がありますが、その例を書いておきますね。

    ちょっと、以前に作っていたプラグインのソースからの抜粋なので、部分的ではありますが…

      LLinesAll: Integer;
      LBuf: array of Char;
      LInfo: TGetLineInfo;
    begin
        LLinesAll := Editor_GetLines(FActiveHandle, POS_LOGICAL);
        for I := 0 to LLinesAll - 1 do
        begin
          LInfo.cch := 0;
          LInfo.byteCrLf := 0;
          LInfo.flags := FLAG_LOGICAL;
          LInfo.yLine := I;
          LLen := Editor_GetLine(FActiveHandle, @LInfo, nil);
          SetLength(LBuf, LLen);
          LInfo.cch := LLen;
          Editor_GetLine(FActiveHandle, @LInfo, PChar(LBuf));

    こんな感じにすると、無駄なメモリを抑えつつ、1 行まるまる確実に取得できると思います。

    > 「flags」と「byteCrLf」の使用方法を教えてください。

    flags は論理行または表示行、などのオプションを指定することができます。

    FLAG_LOGICAL = 1; (論理行で取得します)
    FLAG_WITH_CRLF = 2; (取得する文字列の末尾に改行文字を含めます)
    FLAG_GET_CRLF_BYTE = 4; (byteCrLf の部分に情報を含めて取得します)

    「byteCrLf」は、flags に FLAG_GET_CRLF_BYTE を含めた場合に、byteCrLf の中に以下の情報が返ってきます。

    FLAG_CR_ONLY = 1; (改行コードが CR)
    FLAG_LF_ONLY = 2; (改行コードが LF)

    0 が返ってきた場合は改行コードが CRLF です。

    ちょっとややこしいですが、お試しくださいませ。

     |  Kuro  |  返信
  3. 解説ありがとうございます。不明点がなくなりスッキリしました。

    ただ、教えていただいたプログラムを使うと、プラグインを閉じるときに「無効なポインタ操作」となってしまいます。

    最初は AllocMem を使用して、動的にメモリを確保していましたが、エラーになってしまい、解決できなかったので、事前に配列を確保する方法を採用しましたが、多分、教えていただいたプログラムと同じ状況のような気がします。

    一応、プラグイン側では、設定しているサイズより実際の文字数が多い場合は、メッセージを表示するようにしています。

    DLL の作成は慣れていないので判らない事が多いです。
    プラグインは完成しましたが、もう少しデバッグを行っていきます。

    ありがとうございました。

     |  大石剛司  |  返信
  4. ご返信ありがとうございます。

    > ただ、教えていただいたプログラムを使うと、プラグインを閉じるときに「無効なポインタ操作」となってしまいます。
    うーん、謎ですね。
    上記のコードは実際にプロ生ちゃんプラグインの内部で使用しているものなので問題ないはずですし、Delphi の動的配列 (SetLength で確保) は自動的にメモリを解放してくれますので…

    明示的に解放する場合は

    SetLength(LBuf, 0);

    や、

    LBuf := nil;

    で可能ですが、通常は何もしなくても勝手に解放してくれます。
    もしかして、動的配列ではなくて、配列のサイズを指定されているとか…?

    > DLL の作成は慣れていないので判らない事が多いです。
    > プラグインは完成しましたが、もう少しデバッグを行っていきます。
    はい、がんばってくださいね ^^
    プラグインの仕様は C++ との互換性をある程度考慮しているため、ポインタまわりの操作がちょっと難しいかもしれませんね。

     |  Kuro  |  返信
  5. 基本となる Baisc でステップ毎に、動作を確認してみて、サンプルは正常に動作する事を確認できました。
    同じように、自分で作成したプラグインも、ステップ毎に確認して、試行錯誤の結果、原因が判明しました。

    取得した文字列を変換する処理が以下ではダメでした。
    LineString := String(Lbuf);

    以下に変更したら大丈夫でした。
    LineString := PChar(Lbuf);

    これで、何とか、CSVを展開して表示するプラグインが完成できました。
    キーボードのカスタマイズ設定を可能としましたが、Mery に要望があった、キーボードをキーでソートする機能も組み込んでみました。

    アドバイスありがとうございました。

     |  大石剛司  |  返信
スポンサーリンク