最終更新日 2024-09-25

文字列の扱い方② unsafe と char *

概要

unsafe にして、char *にする。
この方法は「理論上は、誤った方法」ですが、.NET Frameworkの仕組み上、「現実的には問題が起きない」やり方です。

unsafe を使うためには

unsafe を使うためには、ビルドのオプションで「アンセーブコードの許可」にチェックを入れる必要があります。

ClassLibrary36.cs
using System;
using System.Runtime.InteropServices;

namespace ClassLibrary36
{

    public class Class1
    {
       static String rtnBufferOfABC = "";

       [DllExport]
       public unsafe static char* abc(char *p_wstr1, char *p_wstr2)
       {
            String str1 = new String(p_wstr1);
            String str2 = new String(p_wstr2);

            rtnBufferOfABC = str1 + str2;

            // マネージドな文字列の内容を指す生ポインタを返す。
            // 生ポインタを指す内容が関数の終了とともに消えないことを保証するためには、rtnBufferOfABC はメソッドスコープではなくクラススコープであるべきだ。
            // C#のメソッドを抜けると即座に、秀丸は返り値のポインタが指す「文字列内容」を、マクロ変数へとコピーする。
            // このため、C#側から見れば、メソッドが呼び出された瞬間だけ生ポインタは文字列をさしていれば良い。いつまでも文字列を保持する必要はない。

            fixed (char* p_str = rtnBufferOfABC) { return p_str; }

            // ここでfixedが解除されるため、このメソッドを抜ける直前、fixedの効果は確かになくなる。
            // そのため、ガベージコレクションが発生すると、p_str が rtnBufferOfABC を指さなくなるのではないかと思うかもしれない。
            // 理論的にはその通りなのであるが、現実的には、この「static なクラス静的フィールドである rtnBufferOfABC」が、
            // 関数から抜けた途端ガベージコレクトされる、再配置されるといったようなことにはならない。
            // 「ガベージコレクション」を複数回わざとマニュアルで強制実行したとしても、再配置されたりはしない。
        }
    }
}

呼び出し側

ClassLibrary36.mac
#DLL = loaddll( currentmacrodirectory + @"\ClassLibrary36.dll");

$add_str = dllfuncstrw( #DLL, "abc", "あいうえお", "素麺");
message($add_str);