Привет 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 - как ?
Спасибо
Владимир
Имена функций в создаваемой dll, изменение типа пер. для COM
Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain
- 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 напрямую, то в этом (и только в этом случае) мы должны насильно освободить память. Хотя последний вариант вызова является возможным, тем не менее его использование считается плохой практикой программирования, которая влечёт за собой резкое увеличение потенциальных ликов памяти.
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" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Romeo,
Спасибо за ответ. Но я должен откровенно признаться, что я не C++ программер и для меня иппользование С++ было связано с жестокой необходимостью решения проблемы. А так мой уровень в С++ чуть хуже, чем "Hello World" :-)))) Посему ближе к телу ;-)
Вот прототип моей функции из 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.
Заранее спасибо за ответ
Владимир
Спасибо за ответ. Но я должен откровенно признаться, что я не C++ программер и для меня иппользование С++ было связано с жестокой необходимостью решения проблемы. А так мой уровень в С++ чуть хуже, чем "Hello World" :-)))) Посему ближе к телу ;-)
Где можно найти примеры сингаксиса?Для решения подобной проблемы используй def файл. Там нужно прописать нужные имена функций и всё будет ОК.
Да, я понимаю что это разные вещи CHAR* и BSTR, но объясни пожалуйста мне пару вещей.Передавать CHAR * в COM-метод некорректно по той причине, что существует понятие адрессного пространства процесса
Вот прототип моей функции из 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):
2.
_bstr_t strKey = cKey // верно.
BSTR pstrValue = (BSTR) cValue // глупость
3. Если сделал [_bstr_t strKey = cKey], то ничего освобождать за собой не нужно, _bstr_t удалит всё за собой сама.
Код: Выделить всё
; EnvelopesFramework.def : Declares the module parameters.
LIBRARY "EnvelopesFramework.DLL"
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
_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" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Romeo, спасибо,
Ну а как правильно из CHR* сделать BSTR
Как правильно из BSTR и _bstr_t запихнуть обратно в CHAR* чтобы я увидел значение в xBase
Спасибо
Владимир
Ну а как правильно из 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" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Большое спасибо, Romeo.
Буду переписывать свои ваяния :-)
Владимир
Буду переписывать свои ваяния :-)
Владимир