0

C# マネージ DLL を使用するアンマネージ C++ DLL を作成しています。C++ ライブラリをアドオンとして追加できるソフトウェアで定義された関数とヘッダーを使用する必要があるため、C++ ライブラリを作成しています。しかし、私が作りたいものは非常に複雑で、C++ に関する知識が乏しいため、作業が遅くなるので、お気に入りの C# で作成し、DLL を COM 経由で接続することにしました。成功しました。

私は何とかコードを機能させることに成功していますが、明らかにプロの C++ プログラマーではないため、コードを簡潔に保つことにはあまり成功していません。

問題は、さまざまな文字列型の変換にあります。BSTR と const char * 特に。

次のコードは、const char * を BSTR に変換します。

BSTR bstrt;
const char * someChar;

csharpInterfacedClassPointer->get_PropertyForSomeChars(&bstrt);
strcpy_s(nstring, (char *)bstrt);
someChar = nstring;

問題は、対応する離散インターフェイス メソッドを持つ離散 someChars がたくさんあることです...プロパティ メソッドは C# インターフェイスから生成されるため、変更できません。それぞれの "someChar" には次の 3 行のコードが必要なので、30 個の離散変数の場合、90 行のコードを記述する必要があります。

csharpInterfacedClassPointer->get_PropertyForSomeCharX(&bstrt);
strcpy_s(nstring, (char *)bstrt);
someCharX = nstring;

問題は、1 行に収まるようにショートカットを作成するにはどうすればよいかということです。

「ゲッター」関数ポインターと someChar ポインターを使用して、ある種の関数を試しました。

typedef HRESULT (__stdcall *get_string_func)(BSTR * str); //getter function pointer

//the converting function
void ConvertAndAssign(get_string_func bstr_get_fx, const char * constCharString) 
{
const size_t nsize = 1000;
char nstring[nsize];

BSTR bstrt;
bstrt = bstr_t(constCharString);
bstr_get_fx(&bstrt);
strcpy_s(nstring, (char *)bstrt);
constCharString = nstring;
}

//calling the function...as I thought that would work
ConvertAndAssign(sPtr->get_DataFile, someChar);

しかし、コンパイラは、バインドされた関数とそれらがポインターとして許可されていない方法についていくつかの奇妙なことを言います...私はそれが何を意味し、与えられた解決策は関数定義を変更するために必要でしたが、定義が生成されているのでそれを行うことはできませんC# コードから (regasm.exe による)。

重要な注意:最後に const char * 型を取得する必要があります。これは、C++ DLL を作成しているプログラムの関数に必要な入力型であるためです。

4

2 に答える 2

1
Disclaimer: it was a long time (7 years to be more precise) since I have touched C++/COM code for the last time.

インスタンスメソッドを関数ポインターにバインドすることについては、このSOの質問を確認してください。

もう 1 つのオプションは、IDispatchインターフェイスを使用することです (COM コンポーネントが実装している場合)。

ConvertAndAssign() の実装に関しては、IMO にはいくつかの問題があります。説明を簡単にするために、以下にコピーしました。

void ConvertAndAssign(get_string_func bstr_get_fx, const char * constCharString) 
{
    const size_t nsize = 1000;
    char nstring[nsize];

    BSTR bstrt;
    bstrt = bstr_t(constCharString); // issue 1
    bstr_get_fx(&bstrt);
    strcpy_s(nstring, (char *)bstrt); // issue 2
    constCharString = nstring; // issues  3 & 4
} 
  1. COM メソッドが BSTR を返す場合 (つまり、BSTR 型の out パラメーターがある場合)、事前に割り当てられた文字列を渡さないでください。そうしないと、メモリ リークが発生します。

  2. bstrを char * にキャストしても機能しません。BSTR は Unicode 文字列です。また、その長さが実際の文字より前になるようにエンコードされます。ATL/MFC を使用している場合は、いずれかの文字列変換マクロを使用できます。ATL/MFC を使用していない場合は、WideCharToMultiByte()関数または「スマート」BSTR クラス (ATL の CComBSTR、bstr_t など) のいずれかを使用できます。

  3. nstringconstCharStringに割り当てても、外側の文字列には影響しません。次のように ConvertAndAssign を呼び出している場合

    char *outsideStr = NULL;              
    ConvertAndAssign(whatever, outsideStr);
    

    ConvertAndAssign() 関数内のconsCharStringは、最初は NULL を指します。割り当ての後、constCharStringは nstring を指しますが、 outsideStrは引き続き NULL を指します (ConvertAndAssign() 関数を呼び出したときに、ポインター値のコピーが渡されたことを思い出してください)。

    必要なものを取得するには、ポインターへの参照またはポインターを渡すことができます。

     void ConvertAndAssign(get_string_func bstr_get_fx, const char * &constCharString) 
     {
          constCharString = nstring; // Assignment
     }   
    

    またはポインタへのポインタ:

     char *outsideStr = NULL;
     ConvertAndAssign(whatever, &outsideStr);
    
     void ConvertAndAssign(get_string_func bstr_get_fx, const char **constCharString) 
     {
          .
          .
          .
          *constCharString = nstring; // Assignment
     }
    
  4. 前の問題を修正した後、別の問題にぶつかるでしょう: ローカル変数のアドレスを返すことはできません! ConvertAndAssign() が返された後にコードが再開されると、このアドレスはもう割り当てられていません (スタックの一部であるため、動作しているように見えるかもしれませんが、そうではないことを保証します。コードのわずかな変更で、壊せ)

    これを修正するには、事前に割り当てられた文字列を渡す必要があります。

    char outsideStr[1000];
    ConvertAndAssign(whatever, outsideStr);
    
    void ConvertAndAssign(get_string_func bstr_get_fx, const char * constCharString) 
    {
        strcpy_s(constCharString, /* result str here */ );
    }
    

    またはヒープに文字列を割り当てます。

上記のすべてを考えると、ConvertAndAssign() の 1 つの可能な実装とその使用法は次のとおりです。

char outsideStr[1000];
ConvertAndAssign(whatever, outsideStr);

void ConvertAndAssign(get_string_func bstr_get_fx, const char * constCharString) 
{
    BSTR bstrt;
    if(SUCCEEDED(bstr_get_fx(&bstrt)))
    {
         // Assumes constCharString points to a buffer large enough to hold the converted string.
        strcpy_s(constCharString, CW2A(bstr)); // not completely correct since bstr may contain the byte 0 but I guess thats not your scenario.
        SysFreeString(bstr);
    }
    else
    {
         // error handling.
         constCharString[0] = 0;
    }
}
于 2012-09-10T20:36:03.220 に答える
0

MOD がこれを読む場合、この質問は削除できます。私はまったく別の問題を抱えていることに気づきました。Vagaus の努力に感謝します。

于 2012-09-11T15:25:01.480 に答える