質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
DLL

DLL(Dynamic Link Library)とは、他のモジュールからも使用する事が出来る、関数とデータが格納されているモジュールのことです。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

2回答

8510閲覧

【C++ / C#】動的配列を含む構造体をDLLからC#で受け取る方法

Siroinaba

総合スコア11

DLL

DLL(Dynamic Link Library)とは、他のモジュールからも使用する事が出来る、関数とデータが格納されているモジュールのことです。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2021/09/08 22:01

編集2021/09/09 00:11

データをDLL(C++)からC#にマーシャリングして、データの受け渡しを行っているのですが、
動的配列を含む構造体をDLLからC#受け渡しする際、上手くマーシャリングが行かず、困っています。

C++

1struct A 2{ 3 int arrayLength; // 下記、動的配列(dArray)の長さ 4 DynamicArray* dArray; // newによるメモリ確保を使用し、動的配列として使用 5} 6 7struct DynamicArray 8{ 9 int arrayId; 10 float arrayVal; 11} 12 13// 構造体Aのデータ設定 14public void SetupA(A* a, int length) 15{ 16 a->arrayLength = length; 17 18 a->dArray = new DynamicArray[length]; 19 for(int idx = 0; idx < length; idx++) 20 { 21 a->dArray[idx].arrayId = idx; 22 a->dArray[idx].arrayVal = idx % 1.5f; 23 } 24}

上記の構造体をC#で以下のようにして、受け取ろうと考えています。

C#

1public struct A 2{ 3 int arrayLength; 4 DynamicArray[] dArray; 5 6 public void Setup(IntPtr ptr) 7 { 8 arrayLength = (int)Marshal.PtrToStructure(ptr, typeof(int)); 9   ptr += sizeof(int); 10 11 for(int idx = 0; idx < arrayLength; idx++) 12 { 13 dArray[idx].arrayId = (int)Marshal.PtrToStructure(ptr, typeof(int)); 14 ptr += sizeof(int); 15 16 dArray[idx].arrayVal = (float)Marshal.PtrToStructure(ptr, typeof(float)); 17 ptr += sizeof(float); 18 } 19    20 } 21} 22 23public struct DynamicArray 24{ 25 int arrayId; 26 float arrayVal; 27} 28 29// ptrには、DLLの受け取りたいAの先頭ポインタが入ります 30public void GetA(IntPtr ptr) 31{ 32 private A a = new A(); 33 a.Setup(ptr); 34}

可変配列部分が固定配列であれば、上手くいったのですが、
上記の形だと、arrayIdは正しく受け取ることができるのですが、
その下のdArrayから正しい数値を受け取ることができないようになってしまっております。

マーシャリングやC++自体不慣れでポインタ等の知識が不足している状態ですが、
何卒よろしくお願い致します。

《追記》
dArrayのそれぞれの要素の実体メモリ部分はnewで割り当てた別のところにあるのに、C#側でシーケンシャルなアクセスをしているからでは?というご指摘を頂き、恐らくこちらが原因だと思われます。
ただ、C#でunsafeを使うことで、ポインタを使用することができるとは思うのですが、Marshal.PtrToStructure()でポインタをマーシャリングする事ができませんでした。 もし、DLL側からポインタを受け取って、そのポインタを使用してその箇所の値にアクセスする手段がありましたら、ぜひご教授頂けないでしょうか?何卒、よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2021/09/08 22:55

C++側、 > DynamicArray* dArray; // newによるメモリ確保を使用し、動的配列として使用 とあって、dArrayのそれぞれの要素の実体メモリ部分はnewで割り当てた別のところにあるのに、C#側でシーケンシャルなアクセスをしているからでは。C++側でstruct Aの全体を構築しているコードを示した方が良いと思います。例えば struct A a; DynamicArray* ptop = new struct DynamicArray[5]; DynamicArray* p = ptop; for (int i = 0; i < 5; i++) { p->arrayID = i + 1; p->arrayVal = i + 1; ++p; } a.arrayLength = 5; a.dArray = ptop こんなかんじでしょうか?
Siroinaba

2021/09/08 23:23 編集

ご指摘ありがとうございます。 > dArrayのそれぞれの要素の実体メモリ部分はnewで割り当てた別のところにあるのに、C#側でシーケンシャルなアクセスをしているからでは。 確かにご指摘の通り、確保したメモリにアクセスできていないというが、問題ですね。 ただ、C#でunsafeを使うことで、ポインタを使用することができるとは思うのですが、Marshal.PtrToStructure()でポインタをマーシャリングする事ができませんでした。 もし、DLL側からポインタを受け取って、そのポインタを使用してその箇所の値にアクセスする手段がありましたら、ぜひ教えて頂けないでしょうか?よろしくお願い致します。 >C++側でstruct Aの全体を構築しているコードを示した方が良いと思います。 struct Aのデータを構築する処理を追記させて頂きました。 もし、不足している点などありましたら、ご指摘頂けると幸いです。
dodox86

2021/09/08 23:37

確認なのですが、C++側のDLLと言うのはWindowsネイティブのDLLのことで、C++/CLIの.NETアセンブリではないのですよね。
Siroinaba

2021/09/08 23:50

はい、C++/CLIの.NETアセンブリではない認識です。
dodox86

2021/09/09 00:03

ご提示のコードは抜粋版なのだとは思いますが、それにしてもところどころコンパイル通りません。意図を掴みかねるので断念しました。 例1:スペルミス 誤:Marshal.PtrToStructre 正:Marshal.PtrToStructure 例2:これは何? クラス?メソッド?? public GetA(IntPtr ptr) { private A a = new A(); a.Setup(ptr); }
Siroinaba

2021/09/09 00:12

大変失礼いたしました。 ご指摘頂いた2点修正致しました。
ishina_yum

2021/09/09 01:52

構造体のアライメントの考慮は大丈夫でしょうか? 最近のコンパイラだとデフォルトが4バイト以下にはなっていないと思いますけれど。
退会済みユーザー

退会済みユーザー

2021/09/09 11:48 編集

C++側のソースこれコンパイル通ります?多分コンパイルエラーだと思いますけど。コードを提示するなら、最低限自環境でコンパイル通る状態のものにしてください。 あと、呼び出し規約つけてないけど、その辺りきちんと理解出来てます? 言語間の相互運用ってそれなりに知識を要求されるので、きちんとMicrosoftのドキュメント等をよく読んで仕様をよく理解した上で行ってください。
guest

回答2

0

正直な所、アンマネージドコードの相互運用に関しては、Microsoft公式のドキュメントが一番詳しく載っているので、最初に読みましょう。
アンマネージ コードとの相互運用
ネイティブ相互運用性
ネイティブ相互運用性のベスト プラクティス

今回の例だと、このへんでしょう。
クラス、構造体、および共用体のマーシャリング

matukesoさんがIntPtr使った方法回答してますので、別の方法としてunsafe使った方法を載せておきます。あと、DLL側でnewでメモリ割り当てしてるなら、DLL側にメモリ解放用の関数も用意しておかないとまずいです。

cs

1using System; 2using System.Runtime.InteropServices; 3 4namespace ConsoleApp1 5{ 6 class Program 7 { 8 [StructLayout(LayoutKind.Sequential)] 9 struct A 10 { 11 public int arrayLength; 12 public unsafe DynamicArray* dArray; 13 } 14 15 [StructLayout(LayoutKind.Sequential)] 16 struct DynamicArray 17 { 18 public int arrayId; 19 public float arrayVal; 20 } 21 22 [DllImport("DllTest.dll", CallingConvention = CallingConvention.Cdecl)] 23 extern static void SetupA([Out] out A a, int length); 24 25 public static void Main() 26 { 27 var a = new A(); 28 SetupA(out a, 10); 29 unsafe 30 { 31 for (var i = 0; i < a.arrayLength; i++) 32 { 33 var dyn = a.dArray[i]; 34 Console.WriteLine($"id:{dyn.arrayId} val:{dyn.arrayVal}"); 35 } 36 } 37 38 Console.ReadKey(); 39 } 40 } 41} 42

投稿2021/09/09 11:01

編集2021/09/09 23:02
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

c#

1struct Aintop{ public int len; public IntPtr pdArray;} 2 3public void Setup(IntPtr ptr){ 4 Ainterop ai=(Aintop)Marshal.PtrToStruct(ptr, typeof(Aintop)); 5 this.ArrayLength=ai.len; 6 this.dArray=new DynamicArray[ai.len]; 7 for(int i=0; i<this.dArray.Length; i++) 8 this.dArray[i] = (DynamicArray)Marshal.PtrToStructure( ai.pdArray+i*8, typeof(DynamicArray)); 9 }

みたいな。

投稿2021/09/09 05:16

matukeso

総合スコア1590

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問