Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Реализация COM совместимой коллекции на С++

1.8K
28 апреля 2008 года
Arkady
153 / / 18.12.2007
Надо выгрузить данные через COM интерфейс.

Как он реализуется более чем подробно описано в "Inside Com" Дейла Роджерсона и вопросов не вызывает. Но у него нет ни слова о том, какие ограничения накладываются на выгружаемые данные, структуры.

А они точно накладываются, в каком-нибудь VBA нельзя принимать указатели, где-то может не быть нужного типа данных и т.п.. Я уверен, что есть конкретные требования к выгружаемой коллекции. Из разбросанных статей в интернете я понял, что это должен быть массив и у него должны быть определены ряд команд доступа к его элементам. Но найденные мною требования явно не полные. И ни один из них не для С++.

Еси кто-нибудь имеет ссылку или знает их, помогите пожалуйста!
1
28 апреля 2008 года
kot_
7.3K / / 20.01.2000
Цитата: Arkady
Надо выгрузить данные через COM интерфейс.

Как он реализуется более чем подробно описано в "Inside Com" Дейла Роджерсона и вопросов не вызывает. Но у него нет ни слова о том, какие ограничения накладываются на выгружаемые данные, структуры.

А они точно накладываются, в каком-нибудь VBA нельзя принимать указатели, где-то может не быть нужного типа данных и т.п.. Я уверен, что есть конкретные требования к выгружаемой коллекции. Из разбросанных статей в интернете я понял, что это должен быть массив и у него должны быть определены ряд команд доступа к его элементам. Но найденные мною требования явно не полные. И ни один из них не для С++.

Еси кто-нибудь имеет ссылку или знает их, помогите пожалуйста!


Христос Воскрес!
Вопрос свой уточните пожалуйста. СОМ-интерфейс - это СОМ-интерфейс и причем здесь С++?
Данные передаються либо через массивы Variant(TVariant в ВСВ), либо
через BSTR(ближайшим аналогом является в билдере WideString).
По данной ссылке (http://www.rsdn.ru/article/com/QnAinoutbstr.xml) можно так же посмотреть.

1.8K
29 апреля 2008 года
Arkady
153 / / 18.12.2007
Спасибо! Про С++ я гвоорил к тому, что не нашел примеров на С++ реализующих такое.

У меня ещё вопрос. Дейл Роджерсон в книге дает анализ, когда лучше использовать обычные интерфейсы, диспетчеризацию или дуальные. И рекомендует использовать обычные!!
При этом про передачу данных с использованием BSTR, SafeArray и Variant говорит только рассказывая про IDispatch, т.е. про диспетчеризацию.

Отсюда у меня глубокое непонимание, обязан ли я их использовать просто реализовав IUnknown и используя обычный массив указателей на виртуальные функции, в качестве COM-интерфейса?

Дело в том, что как он говорит, диспетчер, в случае если компонент загружается в адресное пространство клиентского процесса, работает в 100 раз медленнее чем vtbl (массив указателей на виртуальные функции), но вообще ни слова о том, какие есть правила выгрузки данных через такие интерфейсы, о выгрузке говорится только в рамках диспетчеризации. И у меня есть подозрение, что использование Variant как раз является замедляющим диспетчера фактором! Т.е. возможно если использовать Variant в vtbl - я получу замедление как у диспетчера, и потому люди используют что-то ещё? Или нет? :)

Помогите пожалуйста! =)
1
29 апреля 2008 года
kot_
7.3K / / 20.01.2000
Цитата: Arkady
Спасибо! Про С++ я гвоорил к тому, что не нашел примеров на С++ реализующих такое.

У меня ещё вопрос. Дейл Роджерсон в книге дает анализ, когда лучше использовать обычные интерфейсы, диспетчеризацию или дуальные. И рекомендует использовать обычные!!
При этом про передачу данных с использованием BSTR, SafeArray и Variant говорит только рассказывая про IDispatch, т.е. про диспетчеризацию.

Отсюда у меня глубокое непонимание, обязан ли я их использовать просто реализовав IUnknown и используя обычный массив указателей на виртуальные функции, в качестве COM-интерфейса?

Дело в том, что как он говорит, диспетчер, в случае если компонент загружается в адресное пространство клиентского процесса, работает в 100 раз медленнее чем vtbl (массив указателей на виртуальные функции), но вообще ни слова о том, какие есть правила выгрузки данных через такие интерфейсы, о выгрузке говорится только в рамках диспетчеризации. И у меня есть подозрение, что использование Variant как раз является замедляющим диспетчера фактором! Т.е. возможно если использовать Variant в vtbl - я получу замедление как у диспетчера, и потому люди используют что-то ещё? Или нет? :)

Помогите пожалуйста! =)


Христос Воскрес!
Вобще-то, все зависит от задач и целей которые при это необходимо достигнуть.
В целом вопрос выглядит так: "Что лучше, маленький кооператив, который размещаеться в гараже, или большое предприятие, на сотне гектаров" :)
Естественно диспечер добавляет дополнительный слой - и за это надо платить дополнительными накладными расходами. Нужно ли это, или вполне можно обойтись - собственно вам и решать.

1.8K
29 апреля 2008 года
Arkady
153 / / 18.12.2007
Спасибо за ссылку, но я её читал, она хорошая, но этого я там не нашел.

Цитата: kot_
Христос Воскрес!
Вобще-то, все зависит от задач и целей которые при это необходимо достигнуть.
В целом вопрос выглядит так: "Что лучше, маленький кооператив, который размещаеться в гараже, или большое предприятие, на сотне гектаров" :)
Естественно диспечер добавляет дополнительный слой - и за это надо платить дополнительными накладными расходами. Нужно ли это, или вполне можно обойтись - собственно вам и решать.



Я немного не о том. На примере покажу.

 
Код:
interface I_UPMain : IUnknown
{
//PPCA and PSTK management
    virtual HRESULT UPregp(ULONG* res, BSTR* TaskName) = 0;
    virtual HRESULT UPunregp(ULONG res, BSTR TaskName) = 0;
    virtual HRESULT UPregt(Variant* res, SafeArray* Data) = 0;
    virtual HRESULT UPunregt(Variant res, SafeArray Data) = 0;
}


Моя DLL выгружает и регистрирует такой интерфейс. Вопрос, сможет ли использовать этот интерфейс Visual Basic? Теоретически должен, потому что ULONG, int и т.п. - это члены Variant и VBA должен уметь с ними работать.
А вот догадается ли он преобразовывать указатели (у него же их нет)? Какие из перечисленных функций интерфейса, VB сможет использовать?
1
29 апреля 2008 года
kot_
7.3K / / 20.01.2000
:)
У вас слегка отвлеченное понятие о VB.
Аналогом в VB (не ручаюсь за точность - все таки достаточно редко использую)
 
Код:
Declare Function UPregp(ByRef res as ULONG, ByRef TaskName As BSTR) AS HRESULT

гдето так примерно.
1.8K
29 апреля 2008 года
Arkady
153 / / 18.12.2007
Цитата: kot_
:)
У вас слегка отвлеченное понятие о VB.
Аналогом в VB (не ручаюсь за точность - все таки достаточно редко использую)
 
Код:
Declare Function UPregp(ByRef res as ULONG, ByRef TaskName As BSTR) AS HRESULT

гдето так примерно.



Да, я с VB практически не знаком. Правильно ли я понимаю, что этот ответ можно понимать как "да, каждый из перечисленных методов интерфейса, после выгрузки компонента в VB, сможет использоваться и не надо думать, что VB такой тупой, он всё это поймет"?

1
30 апреля 2008 года
kot_
7.3K / / 20.01.2000
Цитата: Arkady
Да, я с VB практически не знаком. Правильно ли я понимаю, что этот ответ можно понимать как "да, каждый из перечисленных методов интерфейса, после выгрузки компонента в VB, сможет использоваться и не надо думать, что VB такой тупой, он всё это поймет"?


Правильно.

1.8K
30 апреля 2008 года
Arkady
153 / / 18.12.2007
Цитата: kot_
Правильно.



Отлично. Ещё, для работы с BSTR Майкрософт разработал обертку bstr_t, которая скрывает проблемы с памятью и чтением, которые есть у BSTR (связаны с возможным появением нулей в середине строки).

Но при этом я нигде не видел, чтобы говорилось, что COM поддерживает bstr_t. У меня очень отвлеченное понимание, что такое bstr_t, при этом авторы статей не уточняют, если я через интерфейс буду передавать не BSTR, а bstr_t, интерфейс так же будет всё понимать?

Или грамотным решением является передавать BSTR, а потом тут же прятать его в bstr_t и работать уже с оберткой, а перед выходом - конвертировать назад в BSTR?

Как-то сложно всё получается :)

1
30 апреля 2008 года
kot_
7.3K / / 20.01.2000
BSTR по сути - массив. bstr_t - класс. Т.е. разница примерно же такая как между char* и AnsiString.
СОМ не поддерживает bstr_t - вы можете передавать тип bstr_t там где требуется BSTR, и быть уверенными что вы получите ожидаемый результат, но если вас беспокоит переносимость методов - то вы должны объявлять их используя только BSTR.
1.8K
01 мая 2008 года
Arkady
153 / / 18.12.2007
Цитата: kot_
BSTR по сути - массив. bstr_t - класс. Т.е. разница примерно же такая как между char* и AnsiString.
СОМ не поддерживает bstr_t - вы можете передавать тип bstr_t там где требуется BSTR, и быть уверенными что вы получите ожидаемый результат, но если вас беспокоит переносимость методов - то вы должны объявлять их используя только BSTR.



Спасибо!
Но теперь у меня другая засада (как-то жутко невезет с этими bstr):
Выдается ошибка линкера, если нет

 
Код:
#include "comutil.h"
#include "comdef.h"
#pragma comment(lib, "comsupp.lib")

Как утверждает интернет, но при этом гугл и яндекс отказываются мне помогать найти эту либу, а на моей машине её, как показывает search по всем дискам, нет =(

И где её в итоге брать не понятно -(

Как в такой ситуации ведут себя старые, много повидавшие программисты? :)
1.8K
01 мая 2008 года
Arkady
153 / / 18.12.2007
Как в этой ситуации повел себя я, спектакль в 4х действиях:
1) выяснил, что такая либа есть в Visual Studio, поставил её, нашел там действительно comsupp.lib.
2) Вставил в проект. Облом. Оказывается эта либа имеет тип(?) COFF, а должна OMF. Интернет подсказал, что Builder имеет утилиту coff2omf для исправления этой проблемы.
3) В результате вызвал утилиту без параметров (так как параметры какие-то очень странные там) и получил из файла в 185kb файлик на 512b. Который якобы OMF.
4) Вставил в проект - облом, он там вообще не видит реализации этих функций и опять вылетает старая пара linker error. Новая либа полностью игнорируется, хотя на COFF Билдер не ругается с нею (и то хорошо). Если вставляю старую и новую либу вместе - старая ведет себя как без новой, та же ошибка с COFF (что это такое я не знаю, поэтому пробовал по-разному).

В итоге, что я делал не так? Почему человек, просто желающий иметь возможность нормально работать с BSTR в своем проекте, который не может без BSTR ввиду необхдимости соответствовать СОМ-интерфейсу, должен ТАК мучиться?
Неужели я один такой, кто пытается использовать bstr_t или variant_t?
А если другие пользуются - они тоже эти круги ада проходят? =(
246
01 мая 2008 года
GIZMO
1.8K / / 30.07.2004
Цитата: Arkady
Как в этой ситуации повел себя я, спектакль в 4х действиях:
...
4) Вставил в проект - облом, он там вообще не видит реализации этих функций и опять вылетает старая пара linker error. Новая либа полностью игнорируется, хотя на COFF Билдер не ругается с нею (и то хорошо). Если вставляю старую и новую либу вместе - старая ведет себя как без новой, та же ошибка с COFF (что это такое я не знаю, поэтому пробовал по-разному).


эта утилита не работает со статическими либами...

Цитата: Arkady
Как в этой ситуации повел себя я, спектакль в 4х действиях:
В итоге, что я делал не так? Почему человек, просто желающий иметь возможность нормально работать с BSTR в своем проекте, который не может без BSTR ввиду необхдимости соответствовать СОМ-интерфейсу, должен ТАК мучиться?
Неужели я один такой, кто пытается использовать bstr_t или variant_t?
А если другие пользуются - они тоже эти круги ада проходят? =(


Другие обходятся WideString, а кто совсем мучиться не желает обходятся ATL(и ее обертками для BSTR).

1.8K
01 мая 2008 года
Arkady
153 / / 18.12.2007
Но kot сказал, что для переносимости интерфейса надо, чтобы данные были строго BSTR, все учебники и статьи это подтверждают.

Как же быть? Выходит на Билдере никто никогда не делает комовские сервера? Даже простенькие внутрипроцессовые? :(

Вообще у меня код более менее голый (чуть-чуть Вин Апи и остальное чистый С++), Вижуал Студию я установил, считаете, что бысрее я его перенесу туда, разбирусь в Студии (я её не видел 7 лет), чем добьюсь корректной работы BSTR в Билдере?
246
01 мая 2008 года
GIZMO
1.8K / / 30.07.2004
Цитата: Arkady
Спасибо!
И где её в итоге брать не понятно -(


Здесь смотрел?

246
01 мая 2008 года
GIZMO
1.8K / / 30.07.2004
Цитата: Arkady
Но kot сказал, что для переносимости интерфейса надо, чтобы данные были строго BSTR, все учебники и статьи это подтверждают.


Правильно говорит. Передавать надо BSTR, но естественное желение потом "красиво" работать с ним в теле функции или я че-то не понимаю тогда про попытки использования bstr_t?

Цитата: Arkady

Как же быть? Выходит на Билдере никто никогда не делает комовские сервера? Даже простенькие внутрипроцессовые? :(


Я делаю.

Цитата: Arkady

Вижуал Студию я установил, считаете, что бысрее я его перенесу туда, разбирусь в Студии (я её не видел 7 лет),


Зачем? ATL есть в Билдере.

Цитата: Arkady

чем добьюсь корректной работы BSTR в Билдере?


я за 15 минут добился корректной работы _bstr_t (включая поиск, закачку, установку и ответ Вам) , а BSTR итак корректно работает

1.8K
01 мая 2008 года
Arkady
153 / / 18.12.2007


Отличная ссылка, там куча файлов по кому и 4ре либы на нужную мне тему:
comsupp.lib
comsuppd.lib
comsuppw.lib
comsuppwd.lib

Первую я вставил в проект и линкер ошибки больше нет!! УРА!

Итого: обертка для корректного использования BSTR внутри компоненты у меня есть, GIZMO - огромное спасибо!

Но теперь проблема прохода данных через интерфейс, потому что это должен быть только BSTR, и при этом он не функционирует, как должен, это описано в теме "Работа с BSTR" =(

Так что пока результат один - никакого результата всё равно =(

1.8K
01 мая 2008 года
Arkady
153 / / 18.12.2007
Цитата: GIZMO

я за 15 минут добился корректной работы _bstr_t (включая поиск, закачку, установку и ответ Вам) , а BSTR итак корректно работает


=) Это потому, что Вы знали, как правильно двигаться, а я вчера танцевал с бубном, что описано выше))

Вот есть код

 
Код:
wchar_t wc[4];
mbstowcs(wc, "alba", 4);
BSTR bwc = SysAllocString(wc);

Я создал массив wchar-ов длиною 4.
Положил в него слово "alba" длиною 4.
Создал переменную BSTR bwc, используя специальную для этого функцию, положив туда свою переменную alba.

Слово, которое лежит в bwc - "al", длиною 2.

Мне надо добиться того, чтобы BSTR содержал то, что мне надо (в данном примере целиком слово "alba"). Тогда я смогу передавать через интерфейс данные и быть уверенным, что они передаются целиком, а не первые 2 символа...

Может быть правильным решением является самому составить BSTR? Выделить память, записать первые 4ре байта - длину, потом строку, и возвращать указатель на начало строки? Просто насколько я понимаю, SysAllocString для этого и сделан...
246
01 мая 2008 года
GIZMO
1.8K / / 30.07.2004
Цитата: Arkady

GIZMO - огромное спасибо!


Спасибо (на самом деле) Darko Miletic, а здесь Спасибо GIZMO

Цитата: Arkady

Мне надо добиться того, чтобы BSTR содержал то, что мне надо (в данном примере целиком слово "alba").


BSTR ws = SysAllocString(L"alba") ?

1.8K
01 мая 2008 года
Arkady
153 / / 18.12.2007
Цитата: GIZMO
Спасибо (на самом деле) Darko Miletic, а здесь Спасибо GIZMO


BSTR ws = SysAllocString(L"alba") ?



Да, и это:

 
Код:
BSTR bwc = SysAllocString(L"alba");


и это
 
Код:
wchar_t wc[4];
mbstowcs(wc, "alba", 4);
BSTR bwc = SysAllocString(wc);


дает на выходе "al". Если я ставлю входящее слово длинною в 8 или 6 символов, всё равно длина выходящего тут будет 2 символа. Первые два из вставляемых. =(

Может у меня Билдер кривой?

ЗЫ: сайт запрещает давать отзыв дважды)
246
01 мая 2008 года
GIZMO
1.8K / / 30.07.2004
Цитата: Arkady

дает на выходе "al". Если я ставлю входящее слово длинною в 8 или 6 символов, всё равно длина выходящего тут будет 2 символа. Первые два из вставляемых. =(

Может у меня Билдер кривой?


Покажи код как ты передаешь строку и для какого метода

ЗЫ: Попробуй передай &WideString("alba") это один фиг развернется в BSTR*

1.8K
01 мая 2008 года
Arkady
153 / / 18.12.2007
Цитата: GIZMO
Покажи код как ты передаешь строку и для какого метода

ЗЫ: Попробуй передай &WideString("alba") это один фиг развернется в BSTR*



Если передавать &WideString("alba"), то это будет указатель на указатель, и он ругается.

Ниже три варианта и три попытки вызова функции интерфейса.

Код:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
wchar_t wc[4];
mbstowcs(wc, "alba", 4);
BSTR bwc = SysAllocString(wc);
BSTR bwc2 = SysAllocString(L"alba");
BSTR bwc3 = SysAllocString(WideString("alba"));

I_Face->UPregp(bwc);
I_Face->UPregp(bwc2);
I_Face->UPregp(bwc3);


Как оказалось, идёт правильное выполнение всех трёх =((( Просто подсветка Билдера показывает, будто в слове 2 элемента. А на самом деле слово "alba" передавалось, и видимо давно. А то, что внутри компонента длина слова несовпадала, скорее всего моя невнимательность, там раньше я SysStringLen вызывал от bstr_t, похоже.... не факт, но хочу верить, что это было и именно это причина.

Правда теперь нет уверенности, что оно так всегда будет себя вести, но желаемый результат получен! Ура!
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог