Страница 1 из 1

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

Добавлено: 25 окт 2004, 02:28
VI
Привет 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 - как ?


Спасибо

Владимир

Добавлено: 25 окт 2004, 14:14
Romeo
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 напрямую, то в этом (и только в этом случае) мы должны насильно освободить память. Хотя последний вариант вызова является возможным, тем не менее его использование считается плохой практикой программирования, которая влечёт за собой резкое увеличение потенциальных ликов памяти.

Добавлено: 25 окт 2004, 19:56
VI
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.

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

Владимир

Добавлено: 25 окт 2004, 20:15
Romeo
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 удалит всё за собой сама.

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

Спасибо

Владимир

Добавлено: 25 окт 2004, 21:10
Romeo

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

IMyCOMInterfacePtr p;

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

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

strOut = bstrOut; // такой оператор приведения также перегружен в _bstr_t.

Добавлено: 26 окт 2004, 23:30
VI
Большое спасибо, Romeo.
Буду переписывать свои ваяния :-)

Владимир