ブログ側から記事を移動させました...
構造体配列の先頭ポインタを取る方法って,どう書くんだっけ?
の話
かなぁ~り,めんどくさい手段とれば,取れそうな感じ
まずはC++のDLL側ソース(さっきのソース,バグってます(ww)
C++:
- //ヘッダ側(.h)
- #ifndef __FUNC_TESTFUNC_H__
- #define __FUNC_TESTFUNC_H__
- #ifdef __cplusplus
- extern "C"
- {
- #endif
- typedef struct {
- float wx;
- float wy;
- float wz;
- int x;
- int y;
- } POINT_LCTOWL, *PPOINT_LCTOWL;
- int WINAPI get_PointInfoArray(PPOINT_LCTOWL &aryPtr, int &arySize); //構造体配列の先頭ポインタと配列長を取得
- #ifdef __cplusplus
- }
- #endif
- #endif //__FUNC_CARIBXML_H__
- //実装側(.cpp)
- #include "StdAfx.h"
- #include "TestFunc.h"
- POINT_LCTOWL g_PointInfoArray[10];
- extern "C" int WINAPI get_PointInfoArray(PPOINT_LCTOWL &aryPtr, int &arySize)
- {
- g_PointInfoArray[0].wx = 1;
- g_PointInfoArray[0].wy = 2;
- g_PointInfoArray[0].wz = 3;
- g_PointInfoArray[1].wx = 11;
- g_PointInfoArray[1].wy = 12;
- g_PointInfoArray[1].wz = 13;
- g_PointInfoArray[2].wx = 21;
- g_PointInfoArray[2].wy = 22;
- g_PointInfoArray[2].wz = 23;
- aryPtr = &g_PointInfoArray[0];
- arySize = 10;
- return 0;
- }
んで,C#側
これがウルトラ面倒だわ
C#:
- namespace arrydllTestOya
- {
- [StructLayout(LayoutKind.Sequential)]
- public struct POINT_LCTOWL{
- public float wx;
- public float wy;
- public float wz;
- public int x;
- public int y;
- }
- public partial class Form1 : Form
- {
- [DllImport("arrayDllTest.dll")]
- public static extern int get_PointInfoArray(out IntPtr ary, out int aryCount);
- public Form1()
- {
- InitializeComponent();
- }
- private void button1_Click(object sender, EventArgs e)
- {
- POINT_LCTOWL[] a;
- IntPtr b;
- int ac;
- get_PointInfoArray(out b, out ac);
- for (int i = 0; i <ac; i++) {
- //ポインタを、sizeずつずらしていく。
- //ポインタから構造体に変換して配列に格納。
- a[i] = (POINT_LCTOWL)Marshal.PtrToStructure(
- }
- string st;
- st = a[0].wx.ToString() + "," + a[0].wy.ToString() + "," + a[0].wz.ToString();
- listBox1.Items.Add(st);
- st = a[1].wx.ToString() + "," + a[1].wy.ToString() + "," + a[1].wz.ToString();
- listBox1.Items.Add(st);
- st = a[2].wx.ToString() + "," + a[2].wy.ToString() + "," + a[2].wz.ToString();
- listBox1.Items.Add(st);
- GC.Collect();
- }
- }
- }
-
1.DLL側から,構造体配列の先頭ポインタをIntPtr型で受取り
2.構造体配列のインスタンスを生成
3.各要素ごとにIntPtrの値+構造体サイズのオフセット値を計算して
4.3で計算した値をMarshal.PtrToStructure()にて,配列要素に叩き込む
って形にしないと,いけないっぽい
んで,問題が...
GC(ガーベジコレクション)が走ったら,DLL(アンマネージ)内のメモリ,勝手に解放しないか??
ちょいと心配...
-
追記
-
なんとなく,だけど,Marshal.PtrToStructure()って,ポインタの書き換えとか,やっているんじゃなくて
IntPtrのメモリ位置から指定サイズ分のブロック切り出して,マーシャリング
んで,配列の要素に,そのブロック実体をコピーしているような気がしてきた
これなら,GCの解放動作とか,問題にはならないけど...
でも毎度毎度,コピーするってのもなんだかなぁ(速度的にナニだし)
DLL内部のメモリブロック,ポインタから直接参照するって方法,ないものかねぇ~
もう少し突っ込んでテストしてみるけど
基本,これで,DLL内の構造体配列は,参照できた,ということで♥
参考 : WTSEnumerateSessionsとP/Invoke@ぬるり。さんのページ


