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

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

新規登録して質問してみよう
ただいま回答率
85.37%
C++/CLI

C++/CLIは、.NET Frameworkの共通言語基盤であるCLI向けにC++を拡張したプログラム言語です。前身のC++マネージ拡張と比較するとシンプルで分かりやすい構文になっており、高い可読性を持ちます。

C#

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

structure

このタグは、プログラム言語におけるデータ型structure(構造体)に関するタグです。

C++

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

Q&A

解決済

1回答

1594閲覧

c++、c++/CLI、c#のstructのマーシャリングについて

wave_vague

総合スコア21

C++/CLI

C++/CLIは、.NET Frameworkの共通言語基盤であるCLI向けにC++を拡張したプログラム言語です。前身のC++マネージ拡張と比較するとシンプルで分かりやすい構文になっており、高い可読性を持ちます。

C#

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

structure

このタグは、プログラム言語におけるデータ型structure(構造体)に関するタグです。

C++

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

0グッド

0クリップ

投稿2022/03/10 06:15

編集2022/03/14 05:01

下記サイトからフリーダウンロードできるライブラリをc#で使用したいと思っております。
その際に、下記ライブラリは*.libしか作成されないため、*.dllを作成する必要があります。
*.dllを作成するにあたり、提供されているライブラリがクラスになっているため、c++/CLIラッパを採用して作成しています。

Urg_driver.cppを直接ラッピングしたUrgDriver.cppを新規で作成しています。

https://sourceforge.net/projects/urgnetwork/files/urg_library/urg_library_ja-1.2.5.zip/download

UrgDriver.cpp

1#include "pch.h" 2 3#include "ticks.h" 4extern "C" { 5#include "urg_sensor.h" 6#include "urg_utils.h" 7#include "urg_serial_utils.h" 8#include "urg_errno.h" 9#include "urg_debug.h" 10} 11 12#include "UrgDriver.h" 13#include <string> 14#include <vector> 15#include <msclr\marshal.h> 16 17using namespace msclr::interop; 18using namespace qrk; 19 20namespace QRK 21{ 22 UrgDriver::UrgDriver(void) 23 { 24 urg_ = new urg_t; 25 urg_t_initialize(urg_); 26 } 27 28 UrgDriver::~UrgDriver(void) 29 { 30 Close(); 31 } 32 33bool UrgDriver::StartMeasurement(MeasurementType type, 34 int scan_times, int skip_scan) 35 { 36 37 typedef struct { //struct部分にてマネージドクラスのメンバー関数ではローカルクラス定義は使用できません 38 urg_measurement_type_t c_type; 39 MeasurementType type; 40 } type_table_t; 41 42 43 type_table_t type_table[] = { 44 { URG_DISTANCE, QRK::MeasurementType::Distance }, 45 { URG_DISTANCE_INTENSITY, QRK::MeasurementType::Distance_intensity }, 46 { URG_MULTIECHO, QRK::MeasurementType::Multiecho }, 47 { URG_MULTIECHO_INTENSITY, QRK::MeasurementType::Multiecho_intensity }, 48 }; 49 50 size_t n = sizeof(type_table) / sizeof(type_table[0]); 51 for (size_t i = 0; i < n; ++i) { 52 const type_table_t* p = &type_table[i]; 53 if (type == p->type) { 54 int ret = urg_start_measurement(urg_, 55 p->c_type, scan_times, skip_scan); 56 if (ret == URG_NO_ERROR) { 57 last_measure_type_ = type; 58 } 59 return (ret == URG_NO_ERROR) ? true : false; 60 } 61 } 62 return false; 63 } 64 65bool UrgDriver::GetDistanceIntensity(System::Collections::Generic::IList<int>^ data, System::Collections::Generic::IList<unsigned short>^ intensity, int% time_stamp) 66 { 67 if (last_measure_type_ != QRK::MeasurementType::Distance_intensity) { 68 urg_.last_errno = URG_MEASUREMENT_TYPE_MISMATCH; 69 return false; 70 } 71 // 最大サイズを確保し、そこにデータを格納する 72 size_t data_size = MaxDataSize(); 73 data.resize(data_size); //①resize部分にて、class "System::Collections::Generic::IList<int>"にメンバー"resize"がありません 74 intensity.resize(data_size); //①と同じエラー 75 int ret = urg_get_distance_intensity(urg_, 76 &data[0], &intensity[0], (long*)time_stamp);//1. dataおよびintensity部分にて、式は左辺値または関数指定子である必要があります 77 if (ret > 0) { 78 data.resize(ret); //①と同じエラー 79 intensity.resize(ret);//①と同じエラー 80 adjust_time_stamp(time_stamp); 81 } 82 return (ret < 0) ? false : true; 83 } 84 85} 86

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

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

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

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

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

guest

回答1

0

ベストアンサー

対象のNative C++ライブラリがCライブラリのラッパーなので、C++/CLIで直接ラッピングしたほうがいいのでは、とは思いますけどね。

urg_tについては、WrappingClassが持つにしても、Managed側に露出する必要がないと思いますよ。
ref classは実体を持てないので、ポインタ(urg_t*)にして、WrappingClassのコンストラクタでnewなりmallocなりすればいいです。

つまりはこういう感じのコードになるんですよね。

C++

1#pragma once 2using OutAttribute = System::Runtime::InteropServices::OutAttribute; 3namespace QRK 4{ 5 public enum class ConnectionType { 6 Serial, 7 Ethernet, 8 }; 9 public enum class MeasurementType { 10 Distance, 11 Distance_intensity, 12 Multiecho, 13 Multiecho_intensity, 14 }; 15 public ref class UrgDriver 16 { 17 public: 18 19 static const int DefaultBaudrate = 115200; 20 static const int DefaultPort = 10940; 21 static const int InfinityTimes = -1; 22 23 UrgDriver(void); 24 ~UrgDriver(void); 25 26 static array<System::String^>^ FindPorts(void); 27 static array<System::String^>^ FindPorts([Out] array<bool>^% is_urg_ports); 28 System::String^ What(void); 29 30 bool Open(System::String^ device_name) { return Open(device_name, Default_baudrate, ConnectionType::Serial); } 31 bool Open(System::String^ device_name, int baudrate) { return Open(device_name, baudrate, ConnectionType::Serial); } 32 bool Open(System::String^ device_name, int baudrate, ConnectionType type); 33 void Close(void); 34...... 35 private: 36 void adjust_time_stamp(int% time_stamp) 37 { 38 time_stamp += time_stamp_offset_; 39 } 40 urg_t* urg_; 41 MeasurementType last_measure_type_; 42 int time_stamp_offset_; 43 44 System::String^ product_type_; 45 System::String^ firmware_version_; 46 System::String^ serial_id_; 47 };

C++

1#include "ticks.h" 2extern "C" { 3#include "urg_sensor.h" 4#include "urg_utils.h" 5#include "urg_serial_utils.h" 6#include "urg_errno.h" 7#include "urg_debug.h" 8} 9#include "UrgDriver.h" 10#include <string> 11#include <vector> 12#include <msclr\marshal.h> 13using namespace msclr::interop; 14using namespace qrk; 15namespace QRK 16{ 17 UrgDriver::UrgDriver(void) 18 { 19 urg_ = new urg_t; 20 urg_t_initialize(urg_); 21 } 22 23 array<System::String^>^ UrgDriver::FindPorts(void) 24 { 25 array<bool>^ dummy_is_urg_port; 26 return FindPorts(dummy_is_urg_port); 27 } 28 29 30 array<System::String^>^ UrgDriver::FindPorts(array<bool>^% is_urg_ports) 31 { 32 int n = urg_serial_find_port(); 33 array<System::String^>^ found_ports = gcnew array<System::String^>(n); 34 is_urg_ports = gcnew array<bool>(n); 35 36 for (int i = 0; i < n; ++i) { 37 found_ports[i] = marshal_as<System::String^>(urg_serial_port_name(i)); 38 is_urg_ports[i] = urg_serial_is_urg_port(i) ? true : false; 39 } 40 return found_ports; 41 } 42......

投稿2022/03/10 09:36

編集2022/03/11 12:29
matukeso

総合スコア1677

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

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

wave_vague

2022/03/11 00:32

回答ありがとうございます。 urg_tをManaged側に露出必要がないとのことなので、c#側で使用しなくてよいこと理解しました。 >ref classは実体を持てないので、ポインタ(urg_t*)にして、 >WrappingClassのコンストラクタでnewなりmallocなりすればいいです。 ここの部分なのですが、コンストラクタでnewしようとしており、WrapperClass.hにて下記のように記述したところ、class "qrk::UrgLib::pImpl"にアクセスできません。と表示されてしまいました。 UrgLib.cppで記述されている struct UrgLib::pImpl{}がprivateのためだと思われますが、、 namespace Wrapper { public ref class WrapperClass { private: qrk::UrgLib::pImpl* _urg_t; WrapperClass.cppのコンストラクタでは、_urg_t = new qrk::UrgLib::pImpl.(); と記述する予定でした。 urg_tをポインタにして、WrapperClassのコンストラクタでnewする方法をご教示いただけませんでしょうか
matukeso

2022/03/11 03:51

そうではなくて、WrapperClassがqrk::UrgLib::pimpl相当を実装をする話です。 当該pimplはC->C++変換をするクラスですが、WrapperClassが同じようにC->C++/cli変換をするなら、WrapperClassがurg_t*を持つことをになるでしょう。 WrapperClassがこれまで通り、C++->C++/cli変換するなら、pimplは無視して、UrgLib*だけ持っていればいいでしょう。
wave_vague

2022/03/11 05:34

回答ありがとうございます。 UrgLib.cppでincludeしていたcのヘッダーをWrapperClass.cppでもincludeし、 WrapperClassで struct UrgLib::pImpl相当を実装してみました(下記)。 その際に分からなかったことが数点ありました。 1.urg_t* urg_; 今の状態だと、識別子urg_tが定義されていません。 urg_tを定義する場合はどうすればよろしいでしょうか? 定義した後にWrapperClassのコンストラクタでnewする場合は、 urg_ = new urg_t; であっていますでしょうか? 2.pImpl(void)の実装 今の状態だと既定のコンストラクタは値クラスでは参照できません と表示されます。WrapperClassではどのように実装すればよろしいでしょうか? 3.urg_t_initialize(&urg_); の引数のマーシャリング 1の質問に重複するのですが、urg_t_initialize()も今の状態だと、識別子が定義されていないためエラーが表示されます。 UrgLib.cppでインクルードしているcのヘッダファイルを、WrapperClass.cppでもインクルードした場合、urg_t* urg_;のエラー含めいくつかのエラーは消えますが、消えないエラーをコメントアウトしビルドした際に大量のエラーが表示されました。 ※cのヘッダファイルだけWrapperClass.cppにインクルードした後ビルドしても同じエラーが出ます。 value class qrk::UrgLib::pImpl { urg_t* urg_; measurement_type_t last_measure_type_; long time_stamp_offset_; System::String^ product_type_; System::String^ firmware_version_; System::String^ serial_id_; System::String^ status_; System::String^ state_; pImpl(void) :last_measure_type_(Distance), time_stamp_offset_(0) { urg_t_initialize(&urg_); } void adjust_time_stamp(int% time_stamp) { long tmptime_stamp = time_stamp; if (tmptime_stamp) { tmptime_stamp += time_stamp_offset_; } } }; お手数をおかけしますがご教示いただけませんでしょうか
matukeso

2022/03/11 07:38

なんでvalue classなの? ref classでしょうよ。 urg_tとかurg_t_initializeが未定義云々はurg_sensor.hをincludeすればよべるでしよ。unmanaged ptrを渡すわけで、マーシャリングは要らない。
wave_vague

2022/03/11 08:33

回答ありがとうございます。 WrapperClass.cppにて下記修正を行ったところ、ビルド時に、 C3816 'struct qrk::UrgLib::pImpl'は、異なるマネージ修飾子を伴って、前に宣言または定義されました と表示されました。 このエラーはどのように修正すればよろしいか分かりますでしょうか? ・urg_sensor.hをインクルード ・value classをref classに修正 ・urg_t_initialize()の引数を&urg_からurg_に修正 また、UrgLib.hで定義されていたprivate:の下にある2行はWrapperClassでも実装(考慮)する必要がありますでしょうか? namespace qrk { class URGLIB_API UrgLib : public Lidar { private: struct pImpl; std::auto_ptr<pImpl> pimpl; }; }
matukeso

2022/03/11 12:22

それは単に、urg_driver.hのqrk::UrgLib::pImplと名前がかぶっているという話です。 WrapperClassがCのラッパーになるなら、urg_driver.hはincludeしないべきでしょうし、名前はC++のラッパーと紛らわしくなるのでちがうものにすべきでしょう。 implはC++特有の話なので、Managedでは不要と思います。直接implの中身を持てばいいです。 Lidarはインタフェイスなので、JavaっぽくInterfaceとImplementationを分けたり、DIで挿入したいなら入れてください。直接使うだけなら不要です。
wave_vague

2022/03/14 04:59

回答ありがとうございます。 ご教示いただいた内容を元にWrapperClassを間に挟むのをやめ、UrgDriverを直接ラッピングする方法を採用しました。 その際に分からないことが数点あったため、ご教示いただけませんでしょうか ※修正に当たり、質問本文も大幅に修正したためご確認お願い致します。 1.UrgDriver.cppでのbool UrgDriver::StartMeasurement()について typedef struct { urg_measurement_type_t c_type; MeasurementType type; } type_table_t; はどのように使用すればよろしいでしょうか 2.UrgDriver.cppでのbool UrgDriver::GetDistanceIntensity()について c++で使用できるresize()をSystem::Collections::Generic::IList<int>で使用する場合はどうすればよろしいでしょうか 現状、dataおよびintensity部分にて 式は左辺値または関数指定子である必要があります と表示されるのですが、 urg_get_distance_intensity()の引数はどのように指定すればよろしいでしょうか time_stampは単に(long*)でキャストしているだけですが、これでよいでしょうか 3.C#側からの呼び出しについて 以前は、using Wrapper;、WrapperClass wr = new WrapperClass();を宣言し、c++のメソッドを呼び出していましたが、 UrgDriverを直接ラッピングしているため、呼び出し方は下記方法になりますでしょうか using System.Runtime.InteropServices; //例Open()を呼ぶ場合 [DllImport("UrgDriver.dll")] static extern Open(string device_name, int baudrate, ConnectionType type); //実際に呼び出す場合 Open("対象IPアドレス"、10940、typeはどのように指定すればよいか) この場合、第3引数はc#側でどのように指定すればよろしいでしょうか
matukeso

2022/03/14 05:47

1.swicth 文で書ける筈です 2.ローカル変数としてvector<long>を定義して ert>0の条件式で引数のIList^へ積み替えます 3.C++/CliのdllができればC#側は参照追加でnew UrgDriverを書けます。
wave_vague

2022/03/14 07:06 編集

回答ありがとうございます。 1.switch文で書いてみました。下記のような感じで合ってますでしょうか? bool UrgDriver::StartMeasurement(MeasurementType type, int scan_times, int skip_scan) { switch (type) { case QRK::MeasurementType::Distance_intensity: {int ret = urg_start_measurement(urg_, URG_DISTANCE_INTENSITY, scan_times, skip_scan); if (ret == URG_NO_ERROR) { last_measure_type_ = type; } return (ret == URG_NO_ERROR) ? true : false; } break; case QRK::MeasurementType::Multiecho: {int ret = urg_start_measurement(urg_, URG_MULTIECHO, scan_times, skip_scan); if (ret == URG_NO_ERROR) { last_measure_type_ = type; } return (ret == URG_NO_ERROR) ? true : false; } break; case QRK::MeasurementType::Multiecho_intensity: {int ret = urg_start_measurement(urg_, URG_MULTIECHO_INTENSITY, scan_times, skip_scan); if (ret == URG_NO_ERROR) { last_measure_type_ = type; } return (ret == URG_NO_ERROR) ? true : false; } break; default: {int ret = urg_start_measurement(urg_, URG_DISTANCE, scan_times, skip_scan); if (ret == URG_NO_ERROR) { last_measure_type_ = type; } return (ret == URG_NO_ERROR) ? true : false; } break; } return false; } 2.ローカルでstd::vector<long> (std::vector<unsigned short>もついでに定義)を定義し、処理(下記)を書いてみたのですが、ret>0の条件で引数のIList^へ積み替える部分が分からなかったためご教示いただけますでしょうか。 ※time_stampもローカルでlongと定義しました。 bool UrgDriver::GetDistanceIntensity(System::Collections::Generic::IList<int>^ data, System::Collections::Generic::IList<unsigned short>^ intensity, int% time_stamp) { if (last_measure_type_ != QRK::MeasurementType::Distance_intensity) { urg_->last_errno = URG_MEASUREMENT_TYPE_MISMATCH; return false; } std::vector<long> tmpdata(data->Count); std::vector<unsigned short> tmpintensity(intensity->Count); for (int i = 0; i < (int)tmpdata.size(); i++) { tmpdata[i] = data[i]; } for (int i = 0; i < (int)tmpintensity.size(); i++) { tmpintensity[i] = tmpintensity[i]; } long tmptime_stamp = time_stamp; // 最大サイズを確保し、そこにデータを格納する size_t data_size = MaxDataSize(); tmpdata.resize(data_size); tmpintensity.resize(data_size); int ret = urg_get_distance_intensity(urg_, &tmpdata[0], &tmpintensity[0], &tmptime_stamp); time_stamp = tmptime_stamp; data->Clear(); for (int i = 0; i < (int)tmpdata.size(); i++) { data->Add(tmpdata[i]); } intensity->Clear(); for (int i = 0; i < (int)tmpintensity.size(); i++) { intensity->Add(tmpintensity[i]); } if (ret > 0) { data.resize(ret); intensity.resize(ret); adjust_time_stamp(time_stamp); } return (ret < 0) ? false : true; } 3.対象dllを呼び出したいc#のプロジェクト参照にて右クリック→参照の追加で対象のdllにチェックを付けてOK using UrgDriver; UrgDriver urgdriver = new UrgDriver(); で使用しようと思います。
matukeso

2022/03/14 07:01

switchはurg_measurement_type_tを埋めるだけでいいのでは。urg_start…以下の分は共通なのでswitchの外に移せます。 tmpdataは用意したsize()個のうち、ret個だけが有効なので、そのぶんだけIList::Addします。
wave_vague

2022/03/14 08:11

回答ありがとうございます。 switchの箇所は今の状態でも問題はないが、urg_start…以下の分はswitchの外に移せるということなのでそちらで実装しようと思います。 >tmpdataは用意したsize()個のうち、ret個だけが有効なので、そのぶんだけIList::Addします。 下記のような感じでしょうか? ※if(ret > 0)の上で記述していた内容を中に移行しました if (ret > 0) { //data.resize(ret); //intensity.resize(ret); data->Clear(); for (int i = 0; i < (int)tmpdata.size(); i++) { data->Add(tmpdata[i]); } intensity->Clear(); for (int i = 0; i < (int)tmpintensity.size(); i++) { intensity->Add(tmpintensity[i]); } adjust_time_stamp(time_stamp); }
matukeso

2022/03/14 08:21

そのforループの条件はi<retだ、と言ったつもりですしたが。
wave_vague

2022/03/14 08:34

回答ありがとうございます。 下記のように修正しました。 intensityは型はdataと異なりますが、処理はdataと同様になると考えるためintensityのforループ条件もi < retとして考えてよろしいでしょうか? if (ret > 0) { //data.resize(ret); //intensity.resize(ret); data->Clear(); for (int i = 0; i < ret; i++) { data->Add(tmpdata[i]); } intensity->Clear(); for (int i = 0; i < ret; i++) { intensity->Add(tmpintensity[i]); } adjust_time_stamp(time_stamp); }
wave_vague

2022/03/15 02:42

この処理で大丈夫でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問