Имена функций в создаваемой dll, изменение типа пер. для COM

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
VI
Сообщения: 6
Зарегистрирован: 25 окт 2004, 02:03
Откуда: Canada

Привет All,
Вот написал я свою dll для ипользования ее в xBase++ (Alaska Software). Просто xBase++ не поддерживает в лоб COM/ActiveX и мне нужно было ActiveX интерфейсные методы зваернуть в DLL функии и вызывать из из xBase по средством DllCall().

Вопрос №1
Я определял как EXPORT WORD MyFunc() а получил в dll _MyFunc@0. Если я вдруг поменяю параметр функция получает новое имя и мне приходиться еще и это отслеживать.
Как можно с этим бороться.

Вопрос №2
Мои COM интерфесные принимают [IN] BSTR и [OUT] BSTR* параметры, т.е. к примеру имя параметра и пустой буфер для возврата результата.
Из xBase++ я могу только дать CHAR*
т.е.
EXPORT WORD CALLBACK SetConfig( CHAR * strKey, CHAR * pstrValue)
....
HRESULT hr = pLink->SetConfig(BSTR strKey, BSTR* pstrValue);
....
Как правильно завернуть CHAR* в BSTRы для входного и выходного параметров.
Часть методов принимают _bstr_t параметры, но я понял что _bstr_t можно приравнивать к CHAR* т.е.
_bstr_t myvar = cChar
Нужно ли очищать созданные в с++ фукции BSTRы и нужно ли очищать созданные _bstr_t - как ?


Спасибо

Владимир
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

1. Для решения подобной проблемы используй def файл. Там нужно прописать нужные имена функций и всё будет ОК.

2. Передавать CHAR * в COM-метод некорректно по той причине, что существует понятие адрессного пространства процесса. Именно для этого BSTR и была придумана. BSTR строки размещаются в специально отведённом месте памяти с помощью определённых API функций. К этой памяти имеют доступы ВСЕ процессы операционной сисемы. Таким образом ответ следующий: какой бы не была среда программирования, в любом случае (может явно, а может и неявно) она должна позволять прораммисту манипулировать с системными строками, если она претендуют на статус "среды программирования под Windows".

2.1. По поводу _bstr_t. Очищать ничего не надо, _bstr_t очищается сама в деструкторе (см. код класса _bstr_t, благо сорцы доступны).

2.2. Несколько советов и поясений. Предположим у нас есть кокласс и native интерфейс. При импорте соответствующей tlb, VC создаёт врапперы методов этого интерфейса в которых для удобства программиста происходят замены: BSTR -> _bstr_t, VARIANT -> variant_t, ISomeInterface * -> ISomeInterfacePtr. Плюс эти методы не возвращают HRESULT, а вместо этого бросают _com_error_exception.

2.3. Идеология имплементации COM-интерфейсов, методы которых манипулируют со строками такова: когда пользователь снаружи передаёт строку, COM-объект должен скопировать эту строку во внутреннюю переменную - это можно достигнуть используя оператор присваивания класса _bstr_t. Если COM-объект "отдаёт" строку, то он также должен скопировать содержимое внутренней переменной (метод _bstr_t::copy()) в out-параметр, за освобождением памяти в этом случае будет следить COM-враппер. Если же мы в контейнере вызываем метод get напрямую, то в этом (и только в этом случае) мы должны насильно освободить память. Хотя последний вариант вызова является возможным, тем не менее его использование считается плохой практикой программирования, которая влечёт за собой резкое увеличение потенциальных ликов памяти.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
VI
Сообщения: 6
Зарегистрирован: 25 окт 2004, 02:03
Откуда: Canada

Romeo,
Спасибо за ответ. Но я должен откровенно признаться, что я не C++ программер и для меня иппользование С++ было связано с жестокой необходимостью решения проблемы. А так мой уровень в С++ чуть хуже, чем "Hello World" :-)))) Посему ближе к телу ;-)
Для решения подобной проблемы используй def файл. Там нужно прописать нужные имена функций и всё будет ОК.
Где можно найти примеры сингаксиса?
Передавать CHAR * в COM-метод некорректно по той причине, что существует понятие адрессного пространства процесса
Да, я понимаю что это разные вещи CHAR* и BSTR, но объясни пожалуйста мне пару вещей.
Вот прототип моей функции из dll.
EXPORT WORD CALLBACK SetConfig( CHAR * сKey, CHAR * сValue)
Вот прототип COM метода
HRESULT hr = pLink->SetConfig(BSTR strKey, BSTR* pstrValue);

Я создаю две переменные
BSTR strKey = (BSTR) cKey
BSTR pstrValue = (BSTR) cValue

Это не работает, COM метод недополучает входной параметр. Когда я переопределяю входной параметр
_bstr_t strKey = cKey
^^^^^^^^^^^^^^^^^^^^
BSTR pstrValue = (BSTR) cValue

Как бы все работает, насколько это корректно?

Если входной параметр у COM метода _bstr_t, нужно ли создавать новую переменую типа _bstr_t или cKey можно в лоб воткнуть в параметры СОМ метода.

После выхода из СОМ метода, xBase должен забрать ссылку CHAR* заполненую в СОМе. Как это сделать корректно из BSTR и _bstr_t и чтобы не создать memory leaks. И опять ;-) должен ли очищать созданные мною в dll функции bstr_t и BSTR

И еще, я в dll описываю две static - один поинтер полученый после CoCreateInstance() и второй поинтер на интерфейс после QueryInterface(). Что корректно, каждый раз при вызове СОМ метода запрашивать интерфейс или можно использовать прописанный в статик. Для чего - я должен инициализировать СОМ, послать пару методов, потом выполнить xBase логику и вернуться опять к кому, чтобы вызвать новый метод с данными от xBase.

Заранее спасибо за ответ

Владимир
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

1. Def-файл должен выглядить следующим образом (если используется VC7):

Код: Выделить всё

; EnvelopesFramework.def : Declares the module parameters.

LIBRARY      "EnvelopesFramework.DLL"

EXPORTS
	DllCanUnloadNow      PRIVATE
	DllGetClassObject      PRIVATE
	DllRegisterServer      PRIVATE
	DllUnregisterServer   PRIVATE
2.
_bstr_t strKey = cKey // верно.
BSTR pstrValue = (BSTR) cValue // глупость

3. Если сделал [_bstr_t strKey = cKey], то ничего освобождать за собой не нужно, _bstr_t удалит всё за собой сама.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
VI
Сообщения: 6
Зарегистрирован: 25 окт 2004, 02:03
Откуда: Canada

Romeo, спасибо,
Ну а как правильно из CHR* сделать BSTR
Как правильно из BSTR и _bstr_t запихнуть обратно в CHAR* чтобы я увидел значение в xBase

Спасибо

Владимир
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Код: Выделить всё

IMyCOMInterfacePtr p;

CHAR * strIn;
_bstr_t bstrIn;
_bstr_t bstrOut;
CHAR * strOut;

bstrIn = strInt; // такой оператор для BSTR существует и всё замечательно отработает
bstrOut = p->MyMethod(bstrIn);

strOut = bstrOut; // такой оператор приведения также перегружен в _bstr_t.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
VI
Сообщения: 6
Зарегистрирован: 25 окт 2004, 02:03
Откуда: Canada

Большое спасибо, Romeo.
Буду переписывать свои ваяния :-)

Владимир
Ответить