を整列化時に、それががmscorlib.dllでアクセス違反の例外が発生し起動++私は、サードパーティのコードから構造体次ています変換のstd ::ベクトルその後、P/Cで
typedef struct NodeInfoTag
{
long lResult;
int bComplete;
char *pszNodeAddr;
char *pszParentAddr;
RTS_WCHAR *pwszNodeName;
RTS_WCHAR *pwszDeviceName;
RTS_WCHAR *pwszVendorName;
unsigned long ulTargetType;
unsigned long ulTargetId;
unsigned long ulTargetVersion;
unsigned short wMaxChannels;
}NodeInfotyp;
と定義
# ifndef RTS_WCHAR_DEFINED
# define RTS_WCHAR_DEFINED
typedef wchar_t RTS_WCHAR; /* wide character value */
# endif
(だから、基本的にはwchar_tです)
その後、私はCPLCHandlerCallback
クラスを拡張CScanNetworkCallback
と呼ばれる自分のクラスを、持っている、A:RTS_WCHARへ
.hファイル:
class CScanNetworkCallback : public CPLCHandlerCallback
{
public:
bool bScanComplete;
NodeInfotyp* pNodeInfo;
NodeInfotyp* pNodeInfoList;
std::vector<NodeInfotyp> vList;
CScanNetworkCallback();
virtual ~CScanNetworkCallback(void);
virtual long Notify(CPLCHandler *pPlcHandler, CallbackAddInfoTag CallbackAdditionalInfo);
};
実装がでスロー私自身のものの一部で、独自のガイドラインに従います、したがって、基本的
CScanNetworkCallback::CScanNetworkCallback(void) : CPLCHandlerCallback()
{
bScanComplete = false;
}
CScanNetworkCallback::~CScanNetworkCallback()
{
delete pNodeInfo;
delete pNodeInfoList;
}
long CScanNetworkCallback::Notify(CPLCHandler *pPlcHandler, CallbackAddInfoTag CallbackAdditionalInfo)
{
if (pPlcHandler != NULL)
{
if (CallbackAdditionalInfo.ulType == PLCH_SCAN_NETWORK_CALLBACK)
{
pNodeInfo = CallbackAdditionalInfo.AddInf.pNodeInfo;
if (pNodeInfo->lResult == RESULT_OK)
{
vList.push_back(*pNodeInfo);
bScanComplete = false;
}
else
{
pNodeInfoList = &vList[0]; //New pointer points to the vector elements, which will be used as an array later on
// I have also tried copying it, to the same result:
//std::copy(vList.begin(), vList.end(), pNodeInfoList);
bScanComplete = true;
}
}
}
return RESULT_OK;
}
Notify
を同じベンダーからのクラスメソッドは、ノードの情報をpNodeInfoに割り当てる(ノードが何であるか無視してください、それはATMではありません)、ネットワーク内に「ノード」が見つかるたびに呼び出されます。スキャンプロセス中にネットワーク内のすべてのノードに呼び出され、この情報をC++に送信する必要があるため、std::vector
を使用して、後で使用するすべてのコールバック情報を格納する以外の方法はありません。コンパイル時にいくつのノードがあるか分からない。 else
部分は、すべてのノードが見つかった後に呼び出されます。
PROASADLL __declspec(dllexport) void scanNetwork(){
pScanHandler->ScanNetwork(NULL, &scanNetworkCallback);
}
オブジェクトscanNetworkCallback
静的である:C#コードのうち、意味を理解するためには、私は、p /呼び出されますが、いくつか他のC++メソッドの実装を記述する必要があります。 pScanHandler
はサードパーティのベンダの別のクラスへのポインタであり、そのメソッドのScanNetwork
は別のスレッドで実行されます。
Notify
ノードがネットワークで発見されたときに方法、またはその効果
そして最後に何かを呼び出します
PROASADLL __declspec(dllexport) NodeInfotyp* getScanResult(int* piSize) {
*piSize = scanNetworkCallback.vList.size();
return scanNetworkCallback.pNodeInfoList;
}
これは、すべてのノードの情報を指すポインタと、その量をoutパラメータとして返します。今度は、C#のコードを見てみましょう:
public static List<NodeInfoTag> AsaScanNetworkAsync()
{
Console.WriteLine("SCANNING NETWORK");
scanNetwork(); // C++ Method
while (!isScanComplete()) // Holds the C# thread until the scan is complete
Thread.Sleep(50);
int size = 0;
IntPtr pointer = getScanResult(out size); // works fine, I get some IntPtr and the correct size
List<NodeInfoTag> list = Marshaller.MarshalPointerToList<NodeInfoTag>(pointer, size); // PROBLEM!!!
// Continue doing stuff
}
は、これはC++ NodeInfotyp構造体に一致するように、クラスNodeInfoTag
です:
[StructLayout(LayoutKind.Sequential)]
public class NodeInfoTag
{
public int Result;
public int Complete;
[MarshalAs(UnmanagedType.LPStr)] //char*
public string NodeAddress;
[MarshalAs(UnmanagedType.LPStr)] //char*
public string ParentAddress;
[MarshalAs(UnmanagedType.LPWStr)] //wchar_t
public string VendorName;
public uint TargetType;
public uint TargetId;
public uint TargetVersion;
public short MaxChannels;
}
そして、私は私のメモリアクセス違反を取得する場所です。
internal class Marshaller
{
public static List<T> MarshalPointerToList<T>(IntPtr pointer, int size)
{
if (size == 0)
return null;
List<T> list = new List<T>();
var symbolSize = Marshal.SizeOf(typeof(T));
for (int i = 0; i < size; i++)
{
var current = (T)Marshal.PtrToStructure(pointer, typeof(T));
list.Add(current);
pointer = new IntPtr(pointer.ToInt32() + symbolSize);
}
return list;
}
}
特に、マーシャリングを行うときにエラーが発生するのは、var current = (T)Marshal.PtrToStructure(pointer, typeof(T));
という行です。このC#コードはうまく動作するために使用されていましたが、C++の部分はひどく畳み込まれていてエラーが発生しやすいため、よりシンプルにすることにしましたが、なぜこの例外が発生するのかわかりませんC++ではすべてのC++リソースが利用可能であることを確認しています。なぜなら、テスト目的ではC++で何も削除しないため、スタティックメモリに割り当てられたクラス内のグローバルスコープの変数のみを使用しているからです。それで、私は何を逃したのですか?
編集:私はpNodeInfoList = &vList[0];
を削除しないと、次のようにgetScanResult
を書き直し:
static NodeInfotyp pNodeInfoList;
//(...)
PROASADLL __declspec(dllexport) NodeInfotyp* getScanResult(int* piSize) {
*piSize = scanNetworkCallback.vList.size();
std::move(scanNetworkCallback.vList.begin(),
scanNetworkCallback.vList.end(), &pNodeInfoList);
return &pNodeInfoList;
}
ませサイコロを。関係する変数にnew
またはmalloc
を使用せず、pNodeInfoList(配列)をクラスメンバーからグローバル変数に変更しました。また、私が言われたように、私はmove
を使用しています、所有権の問題を解決するために使用することができます。その他のヒント?
"その他のヒント?"すでにC++コードを書いているので、P/Invokeの代わりにC++/CLIを使用してみてはいかがですか? –
それは長い時間がかかります... – makoshichi
"長い時間を取る"?あなたが書くことを意味しますか?実行時間ですか? –