C言語で書かれているコードをC#で再現したいのですが、
C言語初心者の為に、教えてください。
開発環境は、VS2022
x64環境で出力したDLLを使用しています。
▽▽▽C言語側▽▽▽
typedef struct { uint8_t data_type; /**「RawPoint」or「SpherPoint」のType */ uint8_t timestamp[8]; uint8_t data[1]; /**< Point cloud data. */ } EthPacket ; typedef struct { int32_t x; int32_t y; int32_t z; uint8_t reflectivity; } RawPoint; typedef struct { uint32_t depth; uint16_t theta; uint16_t phi; uint8_t reflectivity; } SpherPoint; //デリゲートメソッド void GetData(uint8_t handle, EthPacket *data, uint32_t data_num, void *client_data) { if (data) { if(data ->data_type == enumData.Raw) { RawPoint *p_point_data = (RawPoint *)data->data; <-ここでは x y z reflectivityの値が入っている }else if ( data ->data_type == enumData.Spher) { SpherPoint *p_point_data = (SpherPoint *)data->data; } } }
▽▽▽C#側▽▽▽
[StructLayoutAttribute(LayoutKind.Sequential)] public class EthPacket { public byte data_type; /**「RawPoint」or「SpherPoint」のType */ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] timestamp; public IntPtr data; /**< Point cloud data. */ } [StructLayoutAttribute(LayoutKind.Sequential)] public class RawPoint { public int x; public int y; public int z; public byte reflectivity; } [StructLayoutAttribute(LayoutKind.Sequential)] public class SpherPoint { public uint depth; public ushort theta; public ushort phi; public byte reflectivity; } void GetData(byte handle, IntPtr ptr, uint data_num, IntPtr client_data) { if (ptr != IntPtr.Zero) { EthPacket data = (EthPacket)Marshal.PtrToStructure(ptr, typeof(EthPacket)); GCHandle gch = GCHandle.Alloc(data.data, GCHandleType.Pinned); if (data.data_type == (byte)enumData.Raw) { RawPoint p_point_data = (RawPoint)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(RawPoint)); <-ここでは x y のみ値が入っている } else if (data.data_type == (byte)enumData.Spher { SpherPoint p_point_data = (SpherPoint)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(SpherPoint)); } gch.Free(); } }
RawPoint p_point_data = (RawPoint)Marshal.PtrToStructure(gch.AddrOfPinnedObject(), typeof(RawPoint));
でデータを確認すると、x , y のみ値が入っていますが、 Z , reflectivityのデータが0のままです。
ポインタからclassへの変換方法が間違っているのかが解からず困っています。
C++ C#への移行に詳しい方、ご教授ください。
なぜわざわざクラスにしているのでしょうか?
クラスでなく、構造体を使えば、Marshal.PtrToStructure で事足りる気がします。
KOZ6.0 さん
ありがとうございます。
public class EthPacket → public struct EthPacket
public class RawPoint → public struct RawPoint
public class SpherPoint → public struct SpherPoint
に変更しても結果は同じでした。。。
また、data.data = Intptr なので、
RawPoint p_point_data =(RawPoint)Marshal.PtrToStructure(data.data, typeof(RawPoint));
で良いのではと思いましたが、結果は
「System.AccessViolationException」とアクセスできませんでした。。
参照へのアクセス方法も異なるのでしょうか?
引数の ptr には EthPacket 構造体のアドレスが入っているのでしょうけど、どのように値をセットしているのでしょうか?
また、C++ は 32bit 前提の構造体になっていますが 32bit でコンパイルする必要は無いのでしょうか?
>引数の ptr には EthPacket 構造体のアドレスが入っているのでしょうけど、どのように値をセットしているのでしょうか?
値をセットいる箇所を見つけました。
一部、転記します。
void DataHandler::OnDataCallback(uint8_t handle, void *data, uint16_t size) {
EthPacket *eth_data = (EthPacket *)data;
if (eth_data == NULL) {
return;
}
if (handle >= callbacks_.size()) {
return;
}
DataCallback cb = callbacks_[handle];
switch (eth_data->data_type) {
case kRaw:
size = (size - kPrefixDataSize) / sizeof(RawPoint);
break;
case kSpherical:
size = (size - kPrefixDataSize) / sizeof(SpherPoint);
break;
default:
return;
}
if (cb) {
cb(handle, eth_data, size, client_data_[handle]); ←ここでC#側に通知k
}
}
void DataHandlerImpl::OnData(socket_t sock, void *client_data) {
struct sockaddr addr;
int addrlen = sizeof(addr);
uint8_t handle = static_cast<uint8_t>(reinterpret_cast<uintptr_t>(client_data));
if (handle > data_buffers_.size()) {
return;
}
std::unique_ptr<char[]> &buf = data_buffers_[handle];
if (buf.get() == NULL) {
buf.reset(new char[kMaxBufferSize]);
}
int size = kMaxBufferSize;
size = util::RecvFrom(sock, reinterpret_cast<char *>(buf.get()), kMaxBufferSize, 0, &addr, &addrlen);
if (size <= 0) {
return;
}
if (handler_) {
handler_->OnDataCallback(handle, buf.get(), size); ←ここでCallBack
}
>また、C++ は 32bit 前提の構造体になっていますが 32bit でコンパイルする必要は無いのでしょうか?
C++側は別の人が作ったのですが、64bit版しか無いようです。。
私に作成するノウハウがあれば良いのですが、C#側しか触ったことが無いために、C+側に手を入れる事が出来ておりません。。
質問は編集できますので補足情報は質問側に記述してください。
C# のコードが出てくるものと思っていましたが、C++/CLR から C# の DLL を呼び出しているんですか?
肝心の EthPacket 構造体の data メンバをセットしている箇所が見当たりませんし、64ビットのアドレスを uint8_t で保持できるのか疑問です。
なんだか、unsafe を使ったほうがいいような気がしてきました。
「C#でポインタを使用する方法」
https://so-zou.jp/software/tech/programming/c-sharp/grammar/type/pointer/
EthPacket は、おそらく可変長で data メンバにアドレスが入っているのではなく、これ以降 RawPoint 構造体もしくは SpherPoint 構造体が入ってくるのかなと思います。
>EthPacket は、おそらく可変長で data メンバにアドレスが入っているのではなく
なるほど!!
アドレスかと思いMarshal.PtrToStructureメソッドを呼んでいましたが、構造体だったのですね!!

回答1件
あなたの回答
tips
プレビュー