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

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

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

Re[9]: ポインタからの構造体配列の取得


(過去ログ 100 を表示中)

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

■59729 / inTopicNo.1)  ポインタからの構造体配列の取得
  
□投稿者/ nao (1回)-(2011/06/05(Sun) 20:09:19)

分類:[.NET 全般] 

質問失礼します。
VB2005でポインタから構造体配列を取得することができず、困っています。
使用言語はVB2005、VC++2008,OSはWindows7です。

VC++で作成したDLLからコールバックされる関数の引数に構造体配列のポインタが
指定されており、その構造体配列をVB2005側で取得したいのですがうまくいきません。
marshal.copyでは構造体は扱えず、
marshal.ptrToStructでは配列の先頭の構造体しか取得できませんでした。
VC++側で構造体配列は連続的に配置されています。

以下、コードです。

  ’構造体の宣言
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Structure glbImage
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=1024)> Dim filePath As String
Dim saveCount As Integer
Dim Result As Integer
End Structure

'コールバック関数
Public Function CallBack(ByVal pImages As IntPtr,ByVal FileNum as Integer) As UInt32

Dim rvImages As glbImage
Dim rvImagesArray(FileNum - 1) As glbImage

'配列の先頭の構造体のみ取得可能
rvImages = Marshal.PtrToStructure(pImages, rvImages.GetType)

    '取得できず
rvImagesArray = Marshal.PtrToStructure(pImages, rvImages.GetType)

End Function

何かご存知の方いらっしゃいましたらご教授ください。

引用返信 編集キー/
■59730 / inTopicNo.2)  Re[1]: ポインタからの構造体配列の取得
□投稿者/ Azulean (752回)-(2011/06/05(Sun) 20:19:17)
試していません。

pImages に glbImage 型分のサイズを加算すれば、配列の次の要素を示すポインタにできるとは思います。
そこから再度 PtrToStructure を実行することを FileNum に基づいた回数分繰り返せばよいとは思いますが、実験していません。

# ポインタの位置をずらす操作は安全と言いがたく、そういった事情を考慮したせいか加算・減算操作は直接実装されていません。
# やや手こずるかもしれませんね。
引用返信 編集キー/
■59731 / inTopicNo.3)  Re[2]: ポインタからの構造体配列の取得
□投稿者/ Hongliang (780回)-(2011/06/05(Sun) 20:42:10)
Delegate 定義において、配列を受け取るパラメータに対して MarshalAs 属性で SizeParamIndex フィールドを併用すればコールバックの引数として直接配列を宣言できたような気が。
Delegate 略(<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal images As glbImage(), 略
// 確認はしてないです。VBは慣れないので書き方間違ってるかも。
引用返信 編集キー/
■59732 / inTopicNo.4)  Re[2]: ポインタからの構造体配列の取得
□投稿者/ nao (3回)-(2011/06/05(Sun) 20:46:35)
No59730 (Azulean さん) に返信
> 試していません。
>
> pImages に glbImage 型分のサイズを加算すれば、配列の次の要素を示すポインタにできるとは思います。
> そこから再度 PtrToStructure を実行することを FileNum に基づいた回数分繰り返せばよいとは思いますが、実験していません。
>
> # ポインタの位置をずらす操作は安全と言いがたく、そういった事情を考慮したせいか加算・減算操作は直接実装されていません。
> # やや手こずるかもしれませんね。

回答ありがとうございます。
まだ実験されていないとのことですが、IntPtr型への加算方法はどのように行うかご存知でしょうか?
.NetFrameWork4.0ではIntptr.addがサポートされているようなのですが、.NetFrameWork2.0では
同様のメソッドが見当たりません。


引用返信 編集キー/
■59733 / inTopicNo.5)  Re[3]: ポインタからの構造体配列の取得
□投稿者/ nao (4回)-(2011/06/05(Sun) 21:28:11)
No59731 (Hongliang さん) に返信
> Delegate 定義において、配列を受け取るパラメータに対して MarshalAs 属性で SizeParamIndex フィールドを併用すればコールバックの引数として直接配列を宣言できたような気が。
> Delegate 略(<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal images As glbImage(), 略
> // 確認はしてないです。VBは慣れないので書き方間違ってるかも。

回答ありがとうございます。
すみません、記載不足でしたが、VC++のDLLはこちらで変更できないのです。
確かに上記のように直接配列を渡すことができれば問題ないと思うのですが。。

引用返信 編集キー/
■59734 / inTopicNo.6)  Re[4]: ポインタからの構造体配列の取得
□投稿者/ Azulean (753回)-(2011/06/05(Sun) 21:31:55)
No59732 (nao さん) に返信
> まだ実験されていないとのことですが、IntPtr型への加算方法はどのように行うかご存知でしょうか?

直接はその手段が用意されていないので、整数型を経由することになるでしょう。

No59733 (nao さん) に返信
> ■No59731 (Hongliang さん) に返信
>>Delegate 定義において、配列を受け取るパラメータに対して MarshalAs 属性で SizeParamIndex フィールドを併用すればコールバックの引数として直接配列を宣言できたような気が。
>>Delegate 略(<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal images As glbImage(), 略
>>// 確認はしてないです。VBは慣れないので書き方間違ってるかも。
>
> すみません、記載不足でしたが、VC++のDLLはこちらで変更できないのです。

Hongliang さんが提示されているのは VB.NET でその関数を宣言する部分の変更ですよ?
DLL 自体を編集することを提案されているものではありません。
引用返信 編集キー/
■59735 / inTopicNo.7)  Re[5]: ポインタからの構造体配列の取得
□投稿者/ nao (5回)-(2011/06/05(Sun) 21:46:39)
No59734 (Azulean さん) に返信
> ■No59732 (nao さん) に返信
>>まだ実験されていないとのことですが、IntPtr型への加算方法はどのように行うかご存知でしょうか?
>
> 直接はその手段が用意されていないので、整数型を経由することになるでしょう。

色々と調べてみます。ありがとうございます。

> ■No59733 (nao さん) に返信
>>■No59731 (Hongliang さん) に返信
> >>Delegate 定義において、配列を受け取るパラメータに対して MarshalAs 属性で SizeParamIndex フィールドを併用すればコールバックの引数として直接配列を宣言できたような気が。
> >>Delegate 略(<MarshalAs(UnmanagedType.LPArray, SizeParamIndex:=1)> ByVal images As glbImage(), 略
> >>// 確認はしてないです。VBは慣れないので書き方間違ってるかも。
>>
>>すみません、記載不足でしたが、VC++のDLLはこちらで変更できないのです。
>
> Hongliang さんが提示されているのは VB.NET でその関数を宣言する部分の変更ですよ?
> DLL 自体を編集することを提案されているものではありません。

DLL側はポインタをパラメータに指定してくるのにこちらで構造体配列をパラメータとして
しまってよいのでしょうか?
ポインタについて初心者のため、的外れな発言であればお許しください。
引用返信 編集キー/
■59737 / inTopicNo.8)  Re[6]: ポインタからの構造体配列の取得
□投稿者/ shu (754回)-(2011/06/05(Sun) 22:18:17)
No59735 (nao さん) に返信

> >>まだ実験されていないとのことですが、IntPtr型への加算方法はどのように行うかご存知でしょうか?
>>
>>直接はその手段が用意されていないので、整数型を経由することになるでしょう。
>
> 色々と調べてみます。ありがとうございます。

http://d.hatena.ne.jp/Schima/20090314/1236998650
にC#ですが載ってます。
// ポインタの加算
ptr = new IntPtr(ptr.ToInt32() + Marshal.SizeOf(typeof(T)) * 2);
部分がポインタ演算相当ですね。



copyで一括byte配列にして順番に構造体に入れていくのが確実ではないかと思います。
copy=>byte配列=>MemoryStream=>BynaryReader
みたいな感じで。
引用返信 編集キー/
■59738 / inTopicNo.9)  Re[6]: ポインタからの構造体配列の取得
□投稿者/ Azulean (754回)-(2011/06/05(Sun) 22:25:34)
No59735 (nao さん) に返信
> DLL側はポインタをパラメータに指定してくるのにこちらで構造体配列をパラメータとして
> しまってよいのでしょうか?

マネージの配列はネイティブの配列と比べて、要素数を持つなどの違いがあります。
ネイティブの配列から直接要素数を取ることができないので、SizeParamIndex で関数の何番目が要素数を表すかを指定する形になっています。

DLL 側はポインタという表現かもしれませんが、単に配列の先頭でしょう。
前述の要素数の部分さえ押さえられていれば、配列として扱うのは不思議ではありません。


> ポインタについて初心者のため、的外れな発言であればお許しください。

機会があれば、C 言語のポインタや配列について学んでもよいと思いますよ。
Win32API を扱う場合に知っていると理解しやすいこともあると思いますし。
引用返信 編集キー/
■59740 / inTopicNo.10)  Re[7]: ポインタからの構造体配列の取得
□投稿者/ Hongliang (781回)-(2011/06/05(Sun) 22:47:46)
なお、SizeParamIndex を使って配列として受け取る方法は、
・渡された領域をコールバック内で解放する必要がある(普通はそんな設計にしないと思いますが)
・コールバックの呼び出しもとにコールバック内での変更を戻す必要がある
といったケースでは使えません。
引用返信 編集キー/
■59741 / inTopicNo.11)  Re[8]: ポインタからの構造体配列の取得
□投稿者/ nao (6回)-(2011/06/05(Sun) 22:53:11)
No59740 (Hongliang さん) に返信
> なお、SizeParamIndex を使って配列として受け取る方法は、
> ・渡された領域をコールバック内で解放する必要がある(普通はそんな設計にしないと思いますが)
> ・コールバックの呼び出しもとにコールバック内での変更を戻す必要がある
> といったケースでは使えません。

SizeParamIndexを1に指定するとコールバックできなくなってしまい、
SizeParamIndexの指定を外してみたところ、先頭の構造体のみ配列内に構造体を取得できました。
SizeParamIndexや配列のマーシャリングについてあまりよくわかっていないため、もう少し調べてみます。

引用返信 編集キー/
■59747 / inTopicNo.12)  Re[9]: ポインタからの構造体配列の取得
□投稿者/ nao (7回)-(2011/06/06(Mon) 09:37:49)
SizeParamIndex=3に指定してみたら構造体配列の全要素が取得できました。
なぜかがわかっていないので後で復習しますが、今回は解決とさせていただきます。
回答して頂いた皆さん、本当にありがとうございました。
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -