- PR -

アンマネージドメモリの確保

1
投稿者投稿内容
とっちゃん
会議室デビュー日: 2005/06/13
投稿数: 8
投稿日時: 2005-06-21 11:30
C# でアンマネージDLLのラッパークラスを作ろうとしているのですが
ローカル変数にメモリを確保する方法がわかりません。MSDNとかも調
べてみましたが、データのマーシャリングについて今ひとつよくわか
りません。
どなたかご教授いただけないでしょうか?

具体的には以下のようなコードを書きたいのですが。

[C]
struct sinf
{ unsigned char c_no;
char *str;
char *buff;
} ;

char buff[2000];
struct sinf sinf;

unsigned int WINAPI Function1( struct sinf *) ;

BOOL WrapFunction()
{
sinf.buff = buff;

if( Function1( &sinf ) != 0)
{
return( FALSE );
}
return( TRUE );
}

C#では以下のように書いたのですが、
[C#]
[StructLayout(LayoutKind.Sequential)]
struct sinf
{
char no ;
string str ;
byte[] buff;
}

static sinf sinf;

public class sample
{
[DllImport("FUNCTION.DLL")]
private extern static uint Function1( ref sinf inf );

public static bool wrapFunction( )
{
// ここでメモリを確保?

if( Function1( ref sinf ) != 0)
{
return false;
}
return true;
}
}
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2005-06-21 13:12
以下の情報が参考になるかもしれません。

[HOWTO] Visual C# .NET でオペレーティング システムの Service Pack レベルを判断する方法


_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
とっちゃん
会議室デビュー日: 2005/06/13
投稿数: 8
投稿日時: 2005-06-21 14:07
説明が足りなかったみたいです。すみません。
お聞きしたかったのは構造体の中に文字列を確保するのではなく、
クラスのローカル変数としてメモリを確保して、構造体にはその
アドレスを渡すというものです。

例でいうと、構造体sinfの中のbuffがローカル変数buffへのポインタ
を保持している(Cプログラム参照)部分がお聞きしたかったところ
です。
Cプログラムでは単に
char buff[2000];
として領域を確保していますが、C#ではどうなるのでしょう?

甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2005-06-21 14:18
引用:

とっちゃんさんの書き込み (2005-06-21 14:07) より:
Cプログラムでは単に
char buff[2000];
として領域を確保していますが、C#ではどうなるのでしょう?


同じですよ。
改訂版 C#入門 第21章 ポインタを使用できる「安全でないコード」あたりを熟読してください。
とっちゃん
会議室デビュー日: 2005/06/13
投稿数: 8
投稿日時: 2005-06-21 20:24
私の勘違いだったらすみません。
struct sinf
{
char no ;
string str ;
[MarshalAs(UnmanagedType.ByValArry, SizeConst = 2000)}
byte[] buff;
}

となるということでしょうか。
しかし、これだと構造体中に2000バイトの配列が確保されてしまいませんか?

甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2005-06-21 22:43
本当に読んだ?
C#にもポインタ変数があります。fixedやunsafeを使えばC++と同じように
コード:
struct{
    char no;
    char *str;
    char *buff;
}
...
    char buff[2000];
    sample.str = &buff[0];


見たいなコードを記述することが出来ます。
コード:
[MarshalAs(UnmanagedType.LPArry, SizeConst = 2000)}
byte[] buff;


とかでも出来そうな気がしますが、未確認です。
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2005-06-21 23:11
.NETにおけるポインタ/ハンドル用の型はSystem.IntPtr構造体です。
メモリ確保はSystem.Runtime.InteropServices.Marshal.AllocHGlobalで行い、
System.Runtime.InteropServices.Marshal.FreeHGlobalで解放します。
バイト配列との相互コピーやデータの読み書きもSystem.Runtime.InteropServices.Marshalクラスにメソッドがあります。
GCの管理外のメモリを扱うことになるのでメモリリークには注意が必要です。
とっちゃん
会議室デビュー日: 2005/06/13
投稿数: 8
投稿日時: 2005-06-24 16:19
皆さんアドバイスありがとうございました。

アドバイスを参考にいろいろ調べて何とか解決しました。
アンマネージとマネージドの連携ということで難しく考えすぎていたようです。
要はCでのポインタの扱いを理解できていれば難しいことではなかったのですが、
最近はそのCでさえもご無沙汰していましたので戸惑ってしまいました。

ただし、GCについてはやはり注意が必要ですね。この辺は甕星さんのご指摘が
参考になりました。

ちなみに
[MarshalAs(UnmanagedType.LPArry, SizeConst = 2000)}
byte[] buff;

とすると配列中に2000バイト確保してしまうので本件の構造体では適用できません。
ここでは
ntPtr buff;
として、System.Runtime.InteropServices.Marshal.AllocHGobalでメモリを確保する
のが順当なようです。
1

スキルアップ/キャリアアップ(JOB@IT)