none
C++でポインターのポインターを引き数に持つ関数のラッパーはどう書けば良いでしょうか? RRS feed

  • 質問

  • 下のようなC++でポインターのポインターを引き数に持つ関数を
    C#で利用するためのラッパーはどう書けば良いでしょうか?

    FileNameGet( char **FileName );

    2011年6月1日 7:32

回答

  • この関数呼び出しで使われるメモリをC++ / C#のどちらが確保するか、および、使用後にどちらが解放するかによって書き方が変わってきます。
    • 回答としてマーク クサキ 2011年6月3日 0:46
    2011年6月1日 8:06
  • これは文字列定数へのポインタを返しているので、C# では扱えません。メモリブロックとして受け取って文字列を生成することになります。ラッパーを作成するとすれば、こんなかんじでしょうか。

    public static string GetFileName()
    {
      IntPtr p;
      FileNameGet(out p);
    
      // CHAR なら Ansi, WCHAR なら Uni, TCHAR なら Auto
      return Marshal.PtrToStringAnsi(p);
    }
    
    [DllImport(...)]
    private static extern void FileNameGet(out IntPtr FileName);
    
    
    • 回答の候補に設定 Jitta 2011年6月2日 7:51
    • 回答としてマーク クサキ 2011年6月2日 8:46
    2011年6月2日 3:43

すべての返信

  • この関数呼び出しで使われるメモリをC++ / C#のどちらが確保するか、および、使用後にどちらが解放するかによって書き方が変わってきます。
    • 回答としてマーク クサキ 2011年6月3日 0:46
    2011年6月1日 8:06
  • C#で、stringの変数を定義して利用します。

     
    ちなみに、同じような目的の関数で引数が配列の下記のような関数
    void abcPathGet( char Path[] )
    がありますが、

           [DllImport("abcDLL", EntryPoint = "abcPathGet")]
            private static extern void abcPathGet(StringBuilder Path);
            public static void PathGet(out string Path)
            {
                StringBuilder PathBuiler = new StringBuilder(260);
                abcPathGet(PathBuiler);
                Path = PathBuiler.ToString();
            }

    のようなラッパーを作って利用しています。
    同じような利用の仕方をしたいと思います。

     

    2011年6月1日 9:37
  • どう利用したいかではなく、dll がどういう利用方法を想定しているかが問題です。

    特にポインタを返してくる場合、呼び出し先で確保された(かもしれない)どう解放するかが問題になります。戻されたポインタを SysFreeString または CoTaskMemFree で解放すればいいのなら 適切な MarshalAs 属性を付けた上で out string で受け取ればいいですが、それ以外の解放手段が必要か、または解放してはいけないのなら out IntPtr で受け取った上で Marshal.PtrToString*** などを使用する必要があります。

    2011年6月1日 11:28
  • あ、やっぱりクサキさんの変身は私の質問には答えられていないと読むべきですかね。

    そんなに難しい質問なのかなぁ…。でも他の人にも同じように確認しても答えられないこともありました。メモリ確保をどちらが行うか、ましてやメモリ解放などする気は全くない、というのが流行りなのかな?

    http://social.msdn.microsoft.com/Forums/ja-JP/csharpgeneralja/thread/d1f8113f-a3d0-462a-8f58-917b01410497/

    2011年6月1日 22:19
  • C++側は
    FileNameGet( char **FileName );
    {
         *FileName = "abc.txt";
    }
    のようなコーディングだけで、メモリの確保は行っていません。


    C#で、stringの変数を定義するということで、C#側でメモリを確保しているものと
    思っていましたが、C#側で中間的なメモリを確保する必要があるということですか。

    2011年6月2日 1:41
  • これは文字列定数へのポインタを返しているので、C# では扱えません。メモリブロックとして受け取って文字列を生成することになります。ラッパーを作成するとすれば、こんなかんじでしょうか。

    public static string GetFileName()
    {
      IntPtr p;
      FileNameGet(out p);
    
      // CHAR なら Ansi, WCHAR なら Uni, TCHAR なら Auto
      return Marshal.PtrToStringAnsi(p);
    }
    
    [DllImport(...)]
    private static extern void FileNameGet(out IntPtr FileName);
    
    
    • 回答の候補に設定 Jitta 2011年6月2日 7:51
    • 回答としてマーク クサキ 2011年6月2日 8:46
    2011年6月2日 3:43
  • 上手く行きました。どうもありがとうございました。

     

    2011年6月2日 7:25