外出自粛中でも楽しく過ごす!QAまとめ>>

現在、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);

このQ&Aに関連する最新のQ&A

A 回答 (2件)

// C++/CLI側の例。



namespace CppCliString
{
// マネージ構造体(値クラス)。
public value class MessagePack
{
public:
UInt32 Code;
UInt32 SessionId;
};

public ref class Class1
{
public:
static void PrintAndClear(MessagePack% msg)
{
printf(__FUNCTION__ "(): Code = 0x%08X, SessionID = %u\n", msg.Code, msg.SessionId);
msg.Code = 0xFFFFFFFF;
msg.SessionId = 0;
}
};
}

// C#側の例。

{
CppCliString.MessagePack msg = new CppCliString.MessagePack();
msg.Code = 10;
msg.SessionId = 7;
Console.WriteLine("Code = 0x{0}, SessionID = {1}", msg.Code.ToString("X8"), msg.SessionId);
CppCliString.Class1.PrintAndClear(ref msg);
Console.WriteLine("Code = 0x{0}, SessionID = {1}", msg.Code.ToString("X8"), msg.SessionId);
}


C#側に合わせたデータ型定義をC++/CLI側で行なうのが基本です。
C#側にポインタ型のインターフェイスを見せるようなことは、何がなんでも避けるべきです。
というか質問を見る限り、明らかにネイティブC++とC++/CLIを混同している上に、C#でポインタを使うことがいかに非生産的な行為であるかを認識されていないようなので、C#とネイティブC++を一通り学び終えた後で、下記の書籍を熟読してからC++/CLIに手を付けることをお勧めします。

http://www.amazon.co.jp/%E5%AE%9F%E8%B7%B5C-CLI- …
    • good
    • 0
この回答へのお礼

丁寧なご回答ありがとうございます。
おかげさまで、やりたいことを実行できました。
ご指摘通り、もうすこしC++/CLIについて勉強したいと思います。
ありがとうございました。

お礼日時:2011/02/22 12:43

C++のstructとC#のstructはまったくの別物てことをふまえての質問でしょうか?

    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aと関連する良く見られている質問

QC#で構造体の配列を持った構造体を使いたいのですが

C#で構造体の配列を持った構造体を使いたいのですが
Cならば
struct xyz {
struct abc _abc[32];
int index;
};
struct abc {
int a;
int b;
int c;
};

struct xyz _xyz[8];
xyz[0]._abc[3].b = 1;

のような使い方で という感じで やっていた事を C#で 同じような事をやろうとしても うまくいきません
うまくやる方法をどなたかご存知ないでしょうか

Visual Studio 2005行った場合
コンパイルで
構文エラーです。不適切な配列の宣言子です。マネージ配列を宣言するには、次元指定子を変数の識別子の前に指定します。固定サイズ バッファ フィールドを宣言するには、フィールド型の前に fixed キーワードを使用します
となり

fixed をつけると

固定サイズ バッファの型は次のうちの 1 つでなければなりません: bool、byte、short、int、long、char、sbyte、ushort、uint、ulong、float または double

となってしまいます

C#で構造体の配列を持った構造体を使いたいのですが
Cならば
struct xyz {
struct abc _abc[32];
int index;
};
struct abc {
int a;
int b;
int c;
};

struct xyz _xyz[8];
xyz[0]._abc[3].b = 1;

のような使い方で という感じで やっていた事を C#で 同じような事をやろうとしても うまくいきません
うまくやる方法をどなたかご存知ないでしょうか

Visual Studio 2005行った場合
コンパイルで
構文エラーです。不適切な配列の宣言子です。マネージ配列を宣言するに...続きを読む

Aベストアンサー

C# では、配列は「単なる連続したメモリ領域」ではなくて「添字によってオブジェクトを格納できるオブジェクト」であることに注意しなくてはいけません。つまり、C では配列は一種の構造体でしたが、C# では配列は参照型のオブジェクトです。
よって、C のように予めサイズを固定しておくということは基本的にできません。配列の大きさは配列のインスタンスが作られるときに動的に決まります。

C# では、参照型のオブジェクトを構造体のメンバにすることはあまりありません。null 値の扱いが面倒だからです。
また、C# では構造体の大きさは大きくとも 20 バイト程度までにします。C# では基本的に「構造体へのポインタ」はありません。巨大な構造体をそのまま扱うのはメモリの使い方の観点からいって非効率的です。

今回の件では、構造体ではなくクラスにするのがよいかと思われます。

QC#、C++間のDLLの呼び出しについて

いつも拝見させていただいております。

さっそくですが、質問致します。

現在、ネイティブなC++ DLLを作成しています。
これを今回、C#のアプリケーションから呼び出すことになりました。
DLL内にはクラスを作成しており、内部にXMLのデータを保持するような
クラスを作成しております。(XML操作にはMSXMLを使用しております。)

問題なのはC++アプリケーションから呼び出した時は正常に動作するのですが、C#からの呼び出しの時はC++アプリケーションから呼び出した時には発生していないエラーが検出されます。

エラー内容は
System.AccessViolationException
保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。
になります。
エラー内容からしてC++内でのメモリ操作に問題があると
思われるのですが、C++からの実行時には検出されていないので理由がわからずに困っております。
ネイティブなDLLに対してはデバッグも行えないため、手に負えません。
(現在、1行ごとにログを埋め込み、TCHAR型のnewを4byte行っている箇所で処理がストップしてしまっているようです。C++からの呼び出し時には正常に処理される箇所です。)
ネイティブなDLLに対してのデバッグ方法や似たような現象にあわれた方がいらっしゃいましたらご助力お願い致します。


・対象のDLLのクラスは_declspec(dllexport)にてエクスポートを行っています。

・C#からの呼び出し時にはネイティブなDLLのためC++/CLIで作成したプロジェクトでラッパークラスを作成してアクセスを行っています。

・C++アプリケーションからの呼び出し時はプロパティの設定でインクルードディレクトリ、LIBファイルの設定等を行って直接DLLを参照して
実行(呼び出し)しています。

いつも拝見させていただいております。

さっそくですが、質問致します。

現在、ネイティブなC++ DLLを作成しています。
これを今回、C#のアプリケーションから呼び出すことになりました。
DLL内にはクラスを作成しており、内部にXMLのデータを保持するような
クラスを作成しております。(XML操作にはMSXMLを使用しております。)

問題なのはC++アプリケーションから呼び出した時は正常に動作するのですが、C#からの呼び出しの時はC++アプリケーションから呼び出した時には発生していないエラーが検出...続きを読む

Aベストアンサー

C++側の出力ファイル .DLL .PDB などを C#の出力フォルダ bin\debug などに出力しておいて

C#側のプロジェクトプロパティのデバッグの『アンマネージ コードのデバッグ』にチェックを付けておく

こうしておけば C++のコードもデバッグできると思いますよ

QC++からC#のdllを参照する際、引数内に構造体があった場合の処理

いつもお世話になっております。

http://satoshi.web5.jp/memo/connect_dll.htm

VC++2008のMFCプロジェクトにて、C#のdllの関数を扱いたく、
上記サイトを参考に実装してみました。

上記サイトでも挙げているように、C#dll内の関数の引数が、
整数・文字列の場合は、うまく動作するのですが、
引数に構造体を渡し、dllにて構造体のデータを設定してやる関数にて、
引数の構造体ポインタを、どのように渡してやれば良いのかが
分かりません。

具体的には、
VARIANTARGの配列をnewし(変数pVarg)、
pVargに型と変数をセットして、Invoke関数に渡しますが、
その際の、pVargにセットしてやる型が分かりません。

このような場合は、どうすれば良いのでしょう?
よろしくお願いします。

Aベストアンサー

 こんばんは。補足頂きました。

[StructLayout(LayoutKind.Sequential)]
public struct ADUser
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string account;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string mail;
}

 ではないでしょうか。念の為にもう一度掲載します。

//C#サイド
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

namespace ClassLibrary1
{
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Class1
{
[StructLayout(LayoutKind.Sequential)]
public struct ADUser
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string account;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string mail;
}

[MethodImpl(MethodImplOptions.Synchronized)]
public int fun(int intPtr)
{
System.IntPtr ptr = new System.IntPtr(intPtr);
ADUser test = (ADUser)Marshal.PtrToStructure(ptr, typeof(ADUser));
test.account = "123-456-7890";
test.name = "c++ to c# struct pointer";
test.mail = "xxx@abc.def.jp";
Marshal.StructureToPtr(test, ptr, true);
return 0;
}
}
}

//C++サイド
typedef struct ADUSER{
char account[100];
char name[100];
char mail[100];
}ADUser;

int main()
{
::CoInitialize( NULL );

CLSID clsid;
BSTR bstrDLL = _com_util::ConvertStringToBSTR( "ClassLibrary1.Class1" );
HRESULT hResult = ::CLSIDFromProgID(bstrDLL, &clsid);
if(!SUCCEEDED(hResult))
return 0;

IUnknown* pUnk = NULL;
hResult = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnk);
if(!SUCCEEDED(hResult))
return 0;

IDispatch* pDisp = NULL;
hResult = pUnk->QueryInterface( IID_IDispatch, (void**)&pDisp );
if(!SUCCEEDED(hResult))
return 0;

DISPID dispid = 0;
LPOLESTR fun = L"fun";
hResult = pDisp->GetIDsOfNames(IID_NULL, &fun, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if(!SUCCEEDED(hResult))
return 0;

ADUser test = {0};
DISPPARAMS params = {0};

params.cArgs = 1;
params.cNamedArgs = 0;
params.rgdispidNamedArgs = NULL;

VARIANTARG* pVarg = new VARIANTARG[params.cArgs];
::ZeroMemory(pVarg, sizeof(VARIANTARG) * params.cArgs);

pVarg[0].vt = VT_INT;
pVarg[0].intVal = (int)&test;

params.rgvarg = pVarg;

hResult = pDisp->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);

::printf("[account : %s][name : %s][mail : %s]\n", test.account, test.name, test.mail);

::CoUninitialize();
::SysFreeString(bstrDLL);
delete []pVarg;

return 0;
}

 こんばんは。補足頂きました。

[StructLayout(LayoutKind.Sequential)]
public struct ADUser
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string account;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string name;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public string mail;
}

 ではないでしょうか。念の為にもう一度...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング