11347


C#からAndroid上の自作DLL経由でファイル内のある部分のバイナリーデータを取得するサンプルを作っています。

下記ソースのfpはファイルポインタになっていて、ファイルの中身は１０個のファイルのバイナリーが敷き詰められています。

**■質問**  
ファイル内のファイル５のデータとファイル６のデータの間にNULLがなかった場合、  
ファイルのオフセット位置をファイル５にしてファイルポインタを返すと  
オフセット位置以降のすべてのバイナリーがC#側に返るのでしょうか？

現在テストしているとすごい数のバイト配列になっているので、  
ファイルの末端までのバイト配列が返っているのではないかと思っています。

オフセット位置を指定して次のデータまでのバイト配列を返してもらうには  
データ間にNULLがあれば良いのか、改行コードをいれるのか、  
サイズ指定してmemcpyしたバッファを返せば良いのか  
調べているのですが答えにたどり着けません。

**●C#**

[code]

    [DllImport ("ReadFile")]
    private static extern byte[] GetFileMemory(int offset);
    
[/code]

**●C++**

[code]

    extern "C"{
        const char** GetFileMemory(int offset);
    }
    
    const char** GetFileMemory(int offset)
    {
        fseek(fp, offset, SEEK_SET);
    
        return (const char**)fp;
    }
    
[/code]


CC BY-SA 3.0
2015-06-13T07:17:56.680
11311
2015-06-15T01:36:21.110
2015-06-13T10:47:01.847
8000
5261
question
c# c++ pinvoke
C++からC#へファイルポインタを返した時、ファイル終端までのデータが返る？


まず、 `fopen()` した時点では **ファイルの中身は読み込んでいません** 。実際にデータを読み取るためには、自分で確保したバッファを
`fread()` 等に渡します。これを必要なサイズ or EOF に到達するまで繰り返すことになります。このあたりはまず C
言語等の資料を参考にしてください。

次に C# 側にマーシャリングするわけですが、C#側で管理される `byte[]` 型にする以上、その **配列全体をマネージヒープ上にコピー**
しなければなりません。となるとサイズの情報が必要になりますが、C言語のポインタにはそんなものありませんから、

  * （確認していませんが）`MarshalAsAttribute.SizeConst` でサイズを指定しておく
  * `IntPtr` で受け取って `Marshal.Copy` する
  * C#側から `byte[]` を渡して、そこにC側でセットしてもらう

などのアプローチをとる必要があります。

参考

  * [配列に対する既定のマーシャリング](https://msdn.microsoft.com/ja-jp/library/z6cfh6e6\(v=vs.110\).aspx)
  * [c# - Can IntPtr be cast into a byte array without doing a Marshal.Copy? - Stack Overflow](https://stackoverflow.com/a/9733059/2818869)

なお、質問に提示された宣言でどのようなマーシャリングが行われたのか定かではありませんが、ヌル終端の文字列もしくは SafeArray
として扱われたのかなと考えています。

>
> Heap領域が１度膨れ上がるとアプリを落とすまで解放されないので、C++側(ネイティブ側)でリソースファイルを管理‌​しC#側のHeapに載らないようにしてます。

今回の場合、いずれにせよ `byte[]` がマネージヒープに載るわけですし、 `Stream` クラスを使えば C#
でもファイルの一部分だけを読み取ることができますが、それでも甲斐はあるのでしょうか？


CC BY-SA 3.0
2015-06-15T01:31:15.873
11347
2015-06-15T01:36:21.110
2017-05-23T12:38:55.250
-1
8000
11311
answer