C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[3]: Void*を引数にもつCで作成したDLLへの構造体の渡し方


(過去ログ 12 を表示中)

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■3611 / inTopicNo.1)  Void*を引数にもつCで作成したDLLへの構造体の渡し方
  
□投稿者/ もんすけ (1回)-(2007/05/17(Thu) 11:31:48)

分類:[C# (Windows)] 

環境:WindowsXP Pro
言語:Microsoft Visual C# 2005

下のようなCで作成した関数(DLL)があるとします。

typedef struct{
int a;
int b;
} structA;

typedef struct{
int c;
double d;
} structB;

int test3(void* p, int n)
{
if (p == null){
return 0;
}
if (n == 1){
(*(structA *)p).a = 111;
(*(structA *)p).b = 222;
return 1;
}
else if (n == 2){
(*(structB *)p).c = 333;
(*(structB *)p).d = 444.4;
return 2;
}
return -1;
}

下はC#から呼びだすプログラムです。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace CStest
{
class Program
{
[DllImport("DLLTest.dll")]
static extern int test3(IntPtr p, int n);

[StructLayout(LayoutKind.Sequential)]
private struct structA
{
int a;
int b;
}
[StructLayout(LayoutKind.Sequential)]
private struct structB
{
int c;
double d;
}

static void Main(string[] args)
{
structA sta;
structB stb;
int n = 0;
int ret;

n = 0;
ret = test3(IntPtr.Zero, n);
n = 1;
ret = test3((IntPtr)sta, n);←エラー1
n = 2;
ret = test3((IntPtr)stb, n);←エラー2
}
}
}

ビルドすると以下のエラーが出ます。
エラー 1 型 'CStest.Program.structA' を型 'System.IntPtr' に変換できません。
エラー 2 型 'CStest.Program.structB' を型 'System.IntPtr' に変換できません。

どのようにすれば実現できるのかご教授下さい。
よろしくお願いします。

引用返信 編集キー/
■3612 / inTopicNo.2)  Re[1]: Void*を引数にもつCで作成したDLLへの構造体の渡し方
□投稿者/ Blue (306回)-(2007/05/17(Thu) 11:38:01)
2007/05/17(Thu) 11:39:10 編集(投稿者)

C言語のように単純にキャストできませんので、
マーシャラを使って一度IntPtrの領域から転送するようにします。

Marshal.AllocHGlobalでstructA の領域を確保

Marshal.StructureToPtrでstaの内容をコピー

test3を呼び出す

Marshal.PtrToStructureでstaにコピー

Marshal.FreeHGlobalでIntPtrの指す領域を開放

Marshal.StructureToPtr メソッド
http://msdn2.microsoft.com/ja-jp/library/system.runtime.interopservices.marshal.structuretoptr(VS.80).aspx
引用返信 編集キー/
■3614 / inTopicNo.3)  Re[2]: Void*を引数にもつCで作成したDLLへの構造体の渡し方
□投稿者/ Hongliang (139回)-(2007/05/17(Thu) 11:55:12)
Hongliang さんの Web サイト
構造体の数が少ないのなら、オーバーロードで済ませた方が楽かも。
[DllImport("DLLTest.dll")]
static extern int test3(out StructA p, int n);
[DllImport("DLLTest.dll")]
static extern int test3(out StructB p, int n);

構造体にプリミティブな値型しか含まれないなら、GCHandle.Alloc で GCHandleType.Pinned すれば手軽かも。
unsafe ありなら fixed でも。
引用返信 編集キー/
■3615 / inTopicNo.4)  Re[3]: Void*を引数にもつCで作成したDLLへの構造体の渡し方
□投稿者/ もんすけ (2回)-(2007/05/17(Thu) 12:36:24)
No3614 (Hongliang さん) に返信
> 構造体の数が少ないのなら、オーバーロードで済ませた方が楽かも。
> [DllImport("DLLTest.dll")]
> static extern int test3(out StructA p, int n);
> [DllImport("DLLTest.dll")]
> static extern int test3(out StructB p, int n);
>
> 構造体にプリミティブな値型しか含まれないなら、GCHandle.Alloc で GCHandleType.Pinned すれば手軽かも。
> unsafe ありなら fixed でも。

なるほど!!そういう事ができるんですね。φ(..)メモメモ
Blue の方法もあることを覚えておきます。

C#をはじめて間もないのでわからないことがたくさん有りますが、このような掲示板の存在と回答していただける方々に感謝いたします。
どうもありがとうございました。

最後に解決したソースを公開しておきます。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace CStest
{
class Program
{
[DllImport("DLLTest.dll")]
static extern int test3(IntPtr p, int n);
[DllImport("DLLTest.dll")]
static extern int test3(ref structA p, int n);
[DllImport("DLLTest.dll")]
static extern int test3(ref structB p, int n);

[StructLayout(LayoutKind.Sequential)]
private struct structA
{
int a;
int b;
}
[StructLayout(LayoutKind.Sequential)]
private struct structB
{
int c;
double d;
}

static void Main(string[] args)
{
structA sta = new structA();
structB stb = new structB();
int n = 0;
int ret;

n = 0;
ret = test3(IntPtr.Zero, n);
n = 1;
ret = test3(ref sta, n);
n = 2;
ret = test3(ref stb, n);
}
}
}

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -