94538


下記の通り `Data` のマーシャリングはできたのですが、`unsigned char*` を `string` にする方法がわかりません。  
`data` の長さが分からないとできないような気がしているのですが、間違っていませんか？

**C側**

[code]

    typedef struct {
        unsigned char* data;
    } Data;
    
[/code]

**C#側**

[code]

    [StructLayout(LayoutKind.Sequential)]
    public class Data
    {
        public IntPtr data;
    }
    
    private extern static void func(out IntPtr data);
    
    static void Main()
    {
        IntPtr p = new IntPtr();
        func(out p);
        Data data = (Data)Marshal.PtrToStructure(p, typeof(Data));
        ???
    }
    
[/code]


CC BY-SA 4.0
2023-04-16T02:18:21.620
94533
2023-04-17T23:34:19.093
2023-04-16T05:52:10.303
3060
57945
question
c# c
CのDLLから受け取ったunsigned char* をstringにしたい


質問に不備があり申し訳ございません。  
UTF-8だったので、コメントでいただいたMarshalAsAttributeを利用して解決できました。

[code]

    [StructLayout(LayoutKind.Sequential)]
    public class Data
    {
        [MarshalAs(UnmanagedType.LPUTF8Str)]
        public string data;
    }
    
[/code]


CC BY-SA 4.0
2023-04-16T05:10:00.390
94535
2023-04-16T05:10:00.390
57945
94533
answer


既に解決済みですが、`IntPtr`で受けなくても`Data`で直接受けられそうです。

[code]

    [StructLayout(LayoutKind.Sequential)]
    public class Data {
        [MarshalAs(UnmanagedType.LPUTF8Str)]
        public string data;
    }
    
    private extern static void func(out Data data);
    
    static void Main() {
        func(out var data);
        Console.WriteLine(data.data);
    }
    
[/code]

また、[`UnmanagedType.LPUTF8Str`を使用するには、.NET Framework
4.7以降が必要](https://learn.microsoft.com/ja-jp/dotnet/standard/native-
interop/customize-struct-
marshalling#:%7E:text=UnmanagedType.LPUTF8Str%20%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E3%81%AB%E3%81%AF%E3%80%81.NET%20Framework%204.7%20\(%E3%81%BE%E3%81%9F%E3%81%AF%E3%81%9D%E3%82%8C%E4%BB%A5%E9%99%8D%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3\)%20%E3%81%BE%E3%81%9F%E3%81%AF%20.NET%20Core%201.1%20\(%E3%81%BE%E3%81%9F%E3%81%AF%E3%81%9D%E3%82%8C%E4%BB%A5%E9%99%8D%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3\)%20%E3%81%AE%E3%81%84%E3%81%9A%E3%82%8C%E3%81%8B%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%A7%E3%81%99%E3%80%82%20.NET%20Standard%202.0%20%E3%81%A7%E3%81%AF%E4%BD%BF%E7%94%A8%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82)です。現在サポートが有効な.NET
Framework 4.6.2などでは利用できないので注意が必要です。（質問者さんに関しては解決したと言っているので大丈夫ですが）

* * *

この手の質問では必ずと言っていいほど、質問から切り離されてしまいますが、一般的にはデータをやり取りする以上、そのデータのメモリ確保を誰が行うかという問題と切り離すことができません。なぜなら、確保した者がメモリ解放も行う必要があり、その場合、確保した者にメモリアドレスを教える必要も出てくるからです。登場人物はC#
AppとC DLLなので考えられるパターンは

  1. C DLLは固定バッファーを保持しており、C# Appに値を返す。固定バッファーなのでメモリを解放する必要はない。
  2. C# Appでメモリ確保し、C DLLにアドレスを通知し、そこに書き込んでもらう。
  3. C DLLがメモリ確保し、C# Appに値を返す。C# AppはC DLLに解放すべきメモリアドレスを通知し、C DLLは通知されたアドレスのメモリを解放する。
  4. C# AppとC DLLで共通のメモリアロケータを使う。C DLLでメモリ確保し、C# Appでメモリ解放する。

ぐらいでしょうか。質問におけるC
DLLのインターフェースからは1.のように見受けられますが、それ以外の場合はインターフェースが異なってきますし、C#での記述も異なってきます。


CC BY-SA 4.0
2023-04-16T09:16:28.030
94538
2023-04-17T23:34:19.093
2023-04-17T23:34:19.093
4236
4236
94533
answer