C#とC++/CLI間でポインタが指す内容が変わる

このQ&Aのポイント
  • C#とC++/CLI間のクラスのやり取りで、ポインタが指す内容が変化する問題について
  • C++/CLI側で定義されているクラスとメソッドの使い方について紹介します
  • C#側でのメソッド参照時に注意すべき点について解説します
回答を見る
  • ベストアンサー

C#とC++/CLI間でポインタが指す内容が変わる

現在、C++/CLIプログラムをC#で使う必要があり、 C++/CLIで定義したメソッドとクラスでC#側とやり取りする必要が生じております。 以下の書き方で、C++/CLIとC#間のクラスのやり取りはできたのですが、 C++/CLI側で定義されているメソッド内で、ポインタが指し示す値(*id.head)が変わってしまいます(文字化けみたいな感じになる)。 引き渡したポインタ変数の値は一致しているのですが、 どうすれば、C++/CLI側で値を正しく取得できるのでしょうか?。 【C++/CLI側で定義されているクラス】 public value class class1 { public : ULONG code; header    *head; }; typedef struct _header { CHAR achCHdrType[2]; CHAR achMsgLen[2]; } header ; 【C++/CLI側で定義されているメソッド】 ULONG session::open(class1& id) { return session_oepn(id.code, *id.head) } 【C#側でのメソッド参照】 class1 c1 = new class1(); uint status = session.open(&c1); よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • sygh
  • ベストアンサー率76% (42/55)
回答No.2

// C++/CLI側。 #include <cstdio> #include <windows.h> using namespace System; namespace CppNative { struct SomeHeaderInfo { // なんで要素数が 2 なのか、この構造体で何がしたいのか、まったくもって不明。 char Type[2]; char MessageLength[2]; }; inline ULONG OpenDummySession(ULONG code, const SomeHeaderInfo& info) { for (int i = 0; i < 2; i++) printf(__FUNCTION__ "(): Type[%d] = %d, MessageLength[%d] = %d\n", i, static_cast<int>(info.Type[i]), i, static_cast<int>(info.MessageLength[i])); return code; } } namespace CppManaged { public value class SomeHeaderInfo { public: char Type0; char Type1; char MessageLength0; char MessageLength1; }; public value class DataPack { public: UInt32 Code; SomeHeaderInfo Header; }; public ref class Session { public: static UInt32 Open(DataPack% dataPack) { CppNative::SomeHeaderInfo temp = {}; temp.Type[0] = dataPack.Header.Type0; temp.Type[1] = dataPack.Header.Type1; temp.MessageLength[0] = dataPack.Header.MessageLength0; temp.MessageLength[1] = dataPack.Header.MessageLength1; return CppNative::OpenDummySession(dataPack.Code, temp); } }; } // C#側。 { CppManaged.DataPack dataPack = new CppManaged.DataPack(); dataPack.Code = 128; dataPack.Header.Type0 = 10; dataPack.Header.Type1 = 20; dataPack.Header.MessageLength0 = 110; dataPack.Header.MessageLength1 = 120; uint status = CppManaged.Session.Open(ref dataPack); Console.WriteLine("Status = {0}", status); } C++/CLIは玄人向けの言語です。 悪いことは言わないので、怪我する前にネイティブC++とC#を基礎から勉強し直した方がいいです。

kokukuma
質問者

お礼

ご回答ありがとうございます。 すでに深手を負ってる感は否めないですねw。 ご指摘通り、基礎をもっと勉強します。。 もし、public value class DataPackにポインタ変数が含まれていた場合、C#側で正しい値を取得する方法はあるのでしょうか? C#側でポインタを使うべきでないとは思うのですが、利用しなければいけないソフトが処理の結果をポインタで返して来るもので。

その他の回答 (1)

  • chie65535
  • ベストアンサー率43% (8521/19370)
回答No.1

異なる言語間では「引数の参照渡し」は出来ません。 参照する場所では「参照した先」が「別世界」なので、参照する時点では「参照すべき場所に、参照すべき内容のデータが存在しない」のです。 「参照渡し」と「ポインタ渡し」は、言語仕様上、ほぼ同じ動作を行いますから、混同している人が多いですが「実装レベルでは、まったく異なる記述」なので注意しましょう。 また「異なる言語での引数渡し」ですので、関数を参照している場所と、関数を定義している場所で「関数の呼び出し規約」も統一させなければなりません。 「関数の呼び出し規約」とは、例えば __stdcallとか__cdeclとかってマクロで定義してあるヤツです。 これが一致してないと、引数の積み込みと取り出しの実装が食い違ったり、引数をレジスタ渡ししているのにスタックから取り出そうとしたりと、色々と問題が起きます。

kokukuma
質問者

お礼

ご回答ありがとうございます。 異なる言語間で引数を渡すのは難しそうですね。 実際、値を受けわたす方法としては、「参照渡し」や「ポインタ渡し」などを使わずに、変数を一つ一つ渡す方がよいのでしょうか? 載せたコードでは省略しましたが、かなり量が多くて・・・。

関連するQ&A

  • C++/CLIのDLLを、C#で参照した際の変数型

    現在、C++/CLIで作成したDLLを、C#で使おうとしています。 http://xptn.dtiblog.com/blog-entry-20.html 上記サイトを参考に、DLLを参照することはできたのですが、 C++/CLI側で「ulong」で定義した引数が、 C#で参照したとき「uint」に変わってしまっています。 【C++/CLI】  opensession(ULONG arg1, ULONG* arg2 ); 【C#】  opensession(UINT arg1, UINT* arg2); 調べてはいるのですが、 この原因がどうしてもわかりません。 ご教授のほど、よろしくお願いします。

  • C,C++,C++/CLIの構造体とクラス

    C++の構造体・クラスって、メンバのアクセス指定子のデフォルトが privateかpublicかという違い「だけ」しか全くないのでしょうか? クラスにおける value class / ref class という分類はC++/CLIのもので これについては value class の方は C言語の構造体に近いという事でいいでしょうか? ref classの方は ネイティブのC++のクラスを マネージ用にしたようなもので C++/CLIの構造体は C++のそれと同じで OKですか? そしてそれらの構造体には、値型・参照型といった分類はないのでしょうか?

  • C++/CLIのDLLをC#で使う

    C++/CLIのDLLをC#で使う ソリューションの中にC++/CLIでクラスを作成し、出力がDLLのプロジェクトと、 C#でGUI画面の処理のプロジェクトがあります。 このときC#側でC++/CLI側で作ったDLLを使用したいのですが、やり方がわかりません。 DLL自体はC#のDebugフォルダに入っており、参照設定で読み込んでいます。 ご教授のほど、よろしくお願いいたします。

  • C++/CLIとC#の連携について

    いつも拝見させていただいております。 現在、C++/CLIとC#にて連携を行っているのですが、C++/CLIで作成したクラス配列 がC#側でどのようにすれば受け取れるのか方法がわかりません。 C++/CLIで作成しているクラス配列はSystem::Collections::Generic::Listを使用 して配列化しています。 下記がC++/CLIのソースになります。 List<testClass>^% testClass::GetList() { List<testClass>^ lpTestClassList = gcnew List<testClass>(); testClass^ lpTestClass; lpTestClass = gcnew testClass(); lpTestClassList->Add(lpWatchServiceMasterInfoWrapper); return lpTestClassList; } これをC#側で使用しようとすると下記エラーが発生します。  「この言語によってサポートされていません」 C++/CLI⇒C#間の連携ではListクラスを使用することは不可能なのでしょうか? クラスを配列にして引き渡したいだけなので、他の方法等含めて何か参考になることがありましたら ご教授ください。 よろしくお願い致します。 開発環境  C++/CLI ⇒ DLL(ネイティブなコードを参照するためのラッパー用DLL)  C# ⇒ アプリケーション

  • C#のピクチャボックスにCLIのHBITMAPを

    C#のピクチャボックスにC++/CLIのHBITMAPを貼り付けたいです。 方法を教えてくれませんか? 今、考えている方法は以下ですが、中々難しいです。 1.C#側 BitmapからIntPtr型で hDC を取得  → C++/CLIに渡せない 2.C++/CLIでhDCにHBITMAPを貼り付け  →IntPtr型を定義できない・・・。 以上、宜しくお願い致します。

  • MFCのC++/CLI へIntPtrをキャスト

    MFCのC++/CLI へIntPtrのデータを受け渡せません。。。 コードは以下になります。 ------------------------------ C# System.IntPtr hBitmap; p.GetBitmapHandle((void*)hBitmap);//CLI側のメソッド ------------------------------ C++/CLI (MFC) void GetBitmapHandle( void* hBitmap ){ hBitmap = m_hBitmap; } HBITMAP m_hBitmap; ------------------------------ 非常に困ってます。助けてください!

  • 【C++】関数ポインタの使い方

    関数ポインタの使い方で悩んでいます。 下記の (1)のようにグローバルメソッドとして定義したメソッドを関数ポインタに代入することは出来るのですが、 (2)のようにクラスのメンバメソッドとして定義したメソッドは関数ポインタに代入することは出来ませんでした。 Error:バインドされた関数へのポインターは関数の呼び出しにのみ使用できます。 というエラーが発生します。 関数ポインタに外部参照でメソッドを代入することは出来ないのでしょうか? -----(1)------------------------------------------------------------------ #include "stdafx.h" #include <iostream> using namespace std; int f(int a, int b){ return a * b; } int _tmain(int argc, _TCHAR* argv[]) { typedef int (* FUNC_POINTER)(int, int); FUNC_POINTER fp; fp = f; cout << fp(1,2) <<endl; getchar(); return 0; } ------------------------------------------------------------------------- -----(2)------------------------------------------------------------------ #include "stdafx.h" #include <iostream> using namespace std; class MPointerList{ public: int f(int a, int b){ return a * b; } }; int _tmain(int argc, _TCHAR* argv[]) { typedef int (* FUNC_POINTER)(int, int); FUNC_POINTER fp; //fp = f; MPointerList mP; fp = mP.f; cout << fp(1,2) <<endl; getchar(); return 0; } -------------------------------------------------------------------------

  • C++/C#間での構造体の引き渡し方法に関して

    現在、C++で作成したクラスを、 C#から呼び出し実行しようとしております。 引数として、構造体を利用したいので、 C++側、C#側でそれぞれ下記のように 構造体を定義しました。 【C++】 typedef struct _Msg { ULONG Code; ULONG sessionId; }Msg; 【C#】 [StructLayout(LayoutKind.Sequential)] public struct Msg { public uint Code; public uint sessionId; } そして、下記のようにC++側で定義したクラスを C#側で呼び出そうとしたのですが、 「Msg*から_Msg*に変換できません」という コンパイルエラーが発生してしまいました。 構造体の定義は同じものになっていると思うのですが、 この原因は何だと考えられるでしょうか。 よろしくお願いいたします。 【C++】 ULONG Wrap::API( Msg* sample_Msg ) { return 1; } 【C#】 Msg sample_msg; Wrap.API(&sample_msg);

  • .NET C++/CLIのガーベジコレクションについて

    .NET C++/CLIのガーベジコレクションについて .NET C++/CLIで、マネージピープの配列をネイティブDLLにポインタ引数として渡す動作で、 配列が正常に渡っていることは確認したのですが、ネイティブDLL側で配列の処理をしている最中に、 ガーベジコレクションが起こり、誤動作することはあるのでしょうか。 ちなみに、マーシャリングは以下のように行いました。 // マネージ側コード [DllImport("native.dll")] void ArraySet( [MarshalAs(UnmanagedType::LPArray)] array <int> ^ Data ); array <int> ^ Data = gcnew array <int>(64); ArraySet( Data ); // この中で配列の処理中にガーベジコレクションが起こると誤動作?

  • C#,C++/CLI,MFCにおけるデータ型の対応と、メソッドへの渡し方

    現在、Visual Studio 2005の、Visual C#、C++/CLI、MFCを使ったシステムを構築しています。 具体的には、MFCで書かれたライブラリ(DLL)をC++/CLIでラップし、C#から呼び出して使うというものです。 現在は、http://www.atmarkit.co.jp/fdotnet/special/vcppinvista02/vcppinvista02_04.html http://msdn2.microsoft.com/ja-jp/library/ac7ay120(VS.80).aspx これらのサイトを参考にしながら、一部のMFCで書かれたメソッドを、C#から呼び出すことに成功しました。しかし、int型やHANDLE型などの、上記サイトに記述されているデータ型を用いたメソッドのラッピングや呼び出しはできたのですが、HDCやLPRECTなどの特殊な型の場合のやり方がよく分かりません。 具体的に現在分からないのは、次の通りです。 HDC(デバイスコンテキスト)、HWND(ウィンドウのハンドル)、CIRCLE,RECT等の構造体、LPRECTなどの構造体のアドレス、POINT*などの構造体のポインタ これらが、C#やCLIでどのような型になるのか、メソッドに渡す時にどのように記述するのかが分かりません。 以上、どなたか分かる方いらっしゃいましたら、ご回答をお願いします。

専門家に質問してみよう