Я делаю неуправляемую 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» требуются следующие три строки кода, поэтому для 30 дискретных переменных мне нужно написать 90 строк кода.
csharpInterfacedClassPointer->get_PropertyForSomeCharX(&bstrt);
strcpy_s(nstring, (char *)bstrt);
someCharX = nstring;
Вопрос в том: как написать для этого ярлык, чтобы он поместился в одну строку?
Я попробовал какую-то функцию с указателем функции «getter» и указателем 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.
Disclaimer: it was a long time (7 years to be more precise) since I have touched C++/COM code for the last time.
Что касается привязки метода экземпляра к указателю на функцию, проверьте это ТАК вопрос.
Другой вариант заключается в использовании 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
}
если ваш COM-метод возвращает BSTR (т. е. он имеет выходной параметр типа BSTR), вы не должны передавать предварительно выделенную строку, в противном случае вы получите
утечка памяти.
Кастинг BSTR на символ * не будет работать. BSTR являются строками Юникода. Также они закодированы так, что их длина предшествует фактическим символам.
Если вы используете ATL / MFC, вы можете использовать один из макросы преобразования строк.
Если вы НЕ используете ATL / MFC, вы можете использовать WideCharToMultiByte () функция или один из «умных» классов BSTR (CComBSTR в ATL, bstr_t и т. д.)
Назначение nstring в constCharString не будет влиять на вне строка. Если вы звоните 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
}
После исправления предыдущей проблемы вы столкнетесь с другой: вы не можете вернуть адрес локальной переменной! Когда ваш код возобновляет работу после возврата 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 () и ее использование заключаются в следующем:
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;
}
}
Этот вопрос можно удалить, если какой-нибудь мод собирается это прочитать. Я понял, что у меня совершенно другая проблема. Спасибо Вагаус за его усилия.