| ■No69050 (Azulean さん) に返信 > C++/CLI で試そうと思ったら、元のマネージ String の長さがわからないからコピーを用意して、そのコピーのポインタ配列を用意してとややこしいことに > なってしまった。 > 対象の関数が '\0' までしかバッファを見ないのなら、vector を1つ減らせると思います。 > (marshal_context のスコープを長くして、sourceBuffers を消して、marshal_as<const char*> の戻り値を sourceArray に入れる) > > また、呼び出し時に 255 バイトを超える文字列がくる可能性や、MBCS 文字セットで表現できない文字がくる可能性を想定していませんので注意。 > > // 知恵の拝借じゃなくて、丸投げだと思う。 > // キーワードを示して話をしたところで解決が遅く、サンプルコードを示した方が速い聞き方になっているので。 > > <コードを利用する方へ> > このコードは現状有姿のまま提供しているもので、不具合や脆弱性、非効率な処理が存在する可能性があります。 > このコードを利用した時点で、利用者自身がすべての責任を負うこととし、投稿者は責任を一切持ちません。 > > > #include <vector> > #include <msclr/marshal.h> > #include <cstring> > > using namespace System; > > namespace CppCliLib { > > public ref class CppWrapper > { > private: > static const size_t BUFFER_SIZE = 256; > public: > static int Execute(array<String^>^ sourceTexts, > [System::Runtime::InteropServices::OutAttribute] array<String^>^% destinationTexts) > { > int dataCount = sourceTexts->Length; > // ポインタ配列 > // 元の配列の長さが可変長なのでvectorで管理 > std::vector<char*> sourceArray(dataCount); > std::vector<char*> destinationArray(dataCount); > // 文字列バッファ > // 元の文字列の長さが不明であることと、DLLの関数が256バイトあることを前提に作っている > // 可能性を加味して、必ず自前のバッファにコピーする > std::vector<std::vector<char>> sourceBuffers(dataCount); > std::vector<std::vector<char>> destinationBuffers(dataCount); > > for (int i = 0; i < dataCount; ++i) > { > // バッファの準備 > sourceBuffers[i].resize(BUFFER_SIZE); > destinationBuffers[i].resize(BUFFER_SIZE); > // ポインタ配列(vector)への代入 > sourceArray[i] = &sourceBuffers[i][0]; > destinationArray[i] = &destinationBuffers[i][0]; > > // 元の文字列のバッファへのコピー > // marshal_asでメモリが確保されるが、marshal_contextのスコープが切れたら解放される > msclr::interop::marshal_context context; > strcpy_s(sourceArray[i], BUFFER_SIZE, context.marshal_as<const char*>(sourceTexts[i])); > } > > // DLL呼び出し > // TODO: 戻り値によって後の処理をする・しないを分ける必要があるかどうか? > int result = dllfunc(dataCount, &sourceArray[0], &destinationArray[0]); > > // 出力先バッファから出力先String^配列を作る > destinationTexts = gcnew array<String^>(dataCount); > for (int i = 0; i < dataCount; ++i) > { > // 出力先String^配列にバッファから文字列をコピーする > msclr::interop::marshal_context context; > destinationTexts[i] = context.marshal_as<String^>(destinationArray[i]); > } > > // 残しておいた戻り値を返す > return result; > } > }; > } >
Azulean さんへ 返信が遅くなりましたが、丸投げ質問に対応頂き誠にありがとう御座います。 ようやくC++の言語も判りかけてきたように思いますので、取り組んでみます。 |