Question

I'm making an unmanaged C++ DLL which uses the C# managed DLL. I'm writting the C++ library as I need to use functions and headers defined in a software for which the C++ library can be added as an addon. But the things I want to make are so complex that my sparse knowledge of C++ would slow me down so I decided to do things in my favourite C# and connect the DLLs via COM and I was successful.

I'm somehow successful in making the code work, but less successful in keeping the code concise as I'm clearly not a professional C++ programmer.

The problem is with converting various string types. BSTR and const char * in particular.

The following code converst const char * to BSTR:

BSTR bstrt;
const char * someChar;

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

The problem is, I have plenty of discrete someChars with corresponding discrete interface methods...the property method is generated from the C# interface so I can't change it. Each of the "someChar" requires the following three lines of code so for 30 discrete variables, I'd need to write 90 lines of code.

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

The question is: how do write some shortcut for this so it'd fit just in one line?

I tried some sort of function with the "getter" function pointer and the someChar pointer.

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);

But then the compiler says some weird things aboud bound functions and how they are not allowed as pointers...I googled what does it mean and the solutions given required to alter the function definition but I can't do that since the definition is generated from the C# code (by regasm.exe).

Important note: I need to get the const char * type in the end because it is the required input type to the functions of the program for which I'm making the C++ DLL.

Was it helpful?

Solution 2

This question can be deleted if any mod is going to read this. I realized I have a totally different problem. Thanks Vagaus for his effort.

OTHER TIPS

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

Regarding binding an instance method to a function pointer check this SO question.

Another option is to use the IDispatch interface (if your COM component implement it)

Regarding ConvertAndAssign() implementation, IMO it has some issues. In order to make it easier to explain I have copied it bellow:

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. if your COM method returns a BSTR (i.e, it has an out parameter of type BSTR) you should not pass on a pre-allocated string otherwise you'll end up leaking memory.

  2. Casting bstr to char * will not work. BSTRs are Unicode strings. Also they are encoded such its length preceeds the actual characters. If you are using ATL/MFC you can use one of the string conversion macros. If you are NOT using ATL/MFC you can use WideCharToMultiByte() function or one of the "Smart" BSTR classes (CComBSTR in ATL, bstr_t, etc)

  3. Assigning nstring to constCharString will have no effect on the outside string. If you are calling ConvertAndAssign like follows

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

    Inside ConvertAndAssign() function consCharString will point to NULL in the begning. After the assignment constCharString does point to nstring but outsideStr still points to NULL (remember, when you called ConvertAndAssign() function a copy of the pointer value was passed to it).

    In order to get what you want you can either pass a reference or a pointer to a pointer:

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

    or a pointer to a pointer:

     char *outsideStr = NULL;
     ConvertAndAssign(whatever, &outsideStr);
    
     void ConvertAndAssign(get_string_func bstr_get_fx, const char **constCharString) 
     {
          .
          .
          .
          *constCharString = nstring; // Assignment
     }
    
  4. After fixing the previous issue you'll hit another one: You cannot return the address of a local variable! When your code resumes after ConvertAndAssign() returns, this address is not allocated for you anymore (it's part of the stack, so it may even look to be working, but I assure you, it is not; the slightest changes in your code may break it)

    To fix this you need to pass a pre-allocated string:

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

    or allocate a string in the heap.

Given all the above, one possible implementation for ConvertAndAssign() and its usage is as follow:

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;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top