Доброго всем времени суток.
Проблема следующая: DCOM сервер написан на C++, клиент — VB.NET.
Сервер отдает клиенту VARIANT, в котором — SAFEARRAY(BSTR)*. Клиент получает в результате ссылку на Nothing.
IDL:
interface IServiceMgr : IDispatch{
[id(1), helpstring("Asks manager for specified action")] HRESULT Manage([in] VARIANT Action, [in] VARIANT Params ,
[out] VARIANT* Result);
};
C++:
VARIANT tmp;
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].lLbound=0;
rgsabound[0].cElements =2;
BSTR HUGEP *pBSTR;
VariantInit(&tmp);
VariantClear(Result);
VariantChangeType(&tmp,&tmp,VARIANT_NOVALUEPROP,VT_ARRAY);
VariantChangeType(Result,Result,VARIANT_NOVALUEPROP,VT_ARRAY);
tmp.parray=SafeArrayCreate(VT_BSTR,1,rgsabound);
Result->parray=SafeArrayCreate(VT_BSTR,1,rgsabound);
hr = SafeArrayAccessData(tmp.parray, (void HUGEP* FAR*)&pBSTR);
pBSTR[0]=SysAllocString(L"Hello!");
pBSTR[1]=SysAllocString(L"World!");
SafeArrayUnaccessData(tmp.parray );;
VariantCopy(Result,&tmp);
VariantClear(&tmp);
return S_OK;
VB:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim SM As ServiceManagerLib.ServiceMgr = New ServiceManagerLib.ServiceMgr
Dim Result(2) As String
Result(0) = New String("Hi")
Result(1) = New String("All!")
Dim Action As String = "StartService"
Dim Parameter As String = "Parameter"
SM.Manage(Action, Parameter, Result)
If Result.GetType().IsArray Then
MessageBox.Show(Result(0))
MessageBox.Show(Result(1))
End If
СОМ сервер зарегистрирован через сборку взаимодействия, Result обьявлен как ByRef Object
После вызова Manage Result получает Nothing. МСДН по маршалингу обьектов по умолчанию уже перечитал весь — бесполезно, там четко
говорится, что VT_ARRAY|VT_BSTR должен преобразовываться в System.Array(String)....Но — не работает
Благодарю за внимание всех откликнувшихся.
Проблема решена самостоятельно,
Для тех, кто наступит на те же грабли — баг — в VariantChangeType — НИ ОДИН ИЗ ЧЕТЫРЕХ ЕЕ ФЛАГОВ НЕ РАБОТАЕТ.
Используйте прямой доступ к полю типа:
Variant->vt= VT_ARRAY | VT_BSTR;
Re[2]: Проблема с маршалингом массива BSTR в VB
От:
Аноним
Дата:
27.07.06 21:52
Оценка:
А чего вы нагородили-то? Вы индус? 2/3 кода к делу вроде не относятся: чего-то туда-сюда копируете типы меняете? Зачем два SAFEARRAY? И память у вас течет, вроде. Ну процессор вам положим не жалко, нечего ему без дела сидеть, а по клавишам тучать сильно любите что ли? Надо SAFEARRAY с двумя строчкамия? Примерно так:
SAFEARRAY* pSa = SafeArrayCreateVector(VT_BSTR, 0, 2);
BSTR* pBSTR = reinterpret_cast<BSTR>(pSa->pvData);
pBSTR[0]=SysAllocString(L"Hello!");
pBSTR[1]=SysAllocString(L"World!");
Result->vt = VT_ARRAY|VT_BSTR;
Result->parray = pSa;
Написал из головы, может чего поправить надо, но в целом примерно так.
Опять написал из головы, может чего поправить надо. По кол-ву строчек вас уже догнал, но их качество всё же другое.
Re[4]: Проблема с маршалингом массива BSTR в VB
От:
Аноним
Дата:
27.07.06 23:03
Оценка:
Мне стало интересно и я отпрофайлил об варианта. Второй — в 10 раз быстрее — примерно так я и ожидал. Профайлил в Debug, роли играть не должно — только вызовы API, по сути, оптимизация мало чего изменит.
Надо пояснить:
1 7.7 94.7 ThatFn(&Result);
1 0.7 9.1 ThisFn(&Result);
первое число — 1 — кол-во вызовов (1)
второе число 7.7 и 0.7 — процент от общего времеи выполнения всей программы
третье число 94.7 и 9.1 — время в микросекудах
Re[6]: Проблема с маршалингом массива BSTR в VB
От:
Аноним
Дата:
27.07.06 23:16
Оценка:
С другой стороны — фигня этот профайлинг. Если поменять порядок вызовов функций — результат изменится на противоположный — всё время жрёт первый вызов SafeArrayCreate[Vector].
Масса! Джимми иметь задавать глупый вопрос, масса!
А почему Вы не сделали (BSTR*) (Result->parray->pvData)? Ведь белым людям
можно приводить все, что угодно куда угодно!?Невзирая на степень недокументированности
тех или иных полей структтуры — ведь m$ никогда их не меняет(там тоже белые люди)!
1."Неважно, как быстро работает твоя программа, если она не работает."(с)
2.Приведенный мною код — результат двухсуточного чтения MSDN и попыток понять,
что же именно и где в <стандартных> функциях для VARIANT не работает.Понял.
Финальный вариант, оттестированный и работающий с клиентом, как надо :
BSTR HUGEP *pBSTR;
VariantInit(Result);
Result->vt= VT_ARRAY | VT_BSTR; // Вот где собака порылась...
Result->parray=SafeArrayCreateVector(VT_BSTR,0,2);
if(!Result->parray)
{
return E_OUTOFMEMORY;
}
hr = SafeArrayAccessData(Result->parray ,(void HUGEP* FAR*)&pBSTR);
{pBSTR[0]=...}
SafeArrayUnaccessData(Result->parray );
return S_OK;
Не профилировал — IMHO, глупость.
P.S. Не флейма глупого ради, а совета для, ежели кто так же мучаться будет.
Re[8]: Проблема с маршалингом массива BSTR в VB
От:
Аноним
Дата:
28.07.06 06:20
Оценка:
Здравствуйте, StandAlone, Вы писали:
SA>Здравствуйте, Аноним, Вы писали:
SA>Масса! Джимми иметь задавать глупый вопрос, масса! SA>А почему Вы не сделали (BSTR*) (Result->parray->pvData)? Ведь белым людям
не люблю сишные касты даже когда вместо reinterpret — плюсовые подсвечиваются.
SA>можно приводить все, что угодно куда угодно!?Невзирая на степень недокументированности SA>тех или иных полей структтуры — ведь m$ никогда их не меняет(там тоже белые люди)!
Можете пользоваться SafeArrayAccess(unaccess)Data. А (BSTR*) (Result->parray->pvData) пишут далеко не самые плохие програмеры в самом Майкрософте. Причина, скорее всего таковы:
а)SafeArrayAccess(unaccess)Data задуманы для синхронизированного доступа (IMHO) к данным — пока SafeArray исключительно ваш — можно обойтись
б)Когда их придумали — предпологали что SafeArray может изменится. Но потом стало очевидно, что этого никогда не случиться.
SA>1."Неважно, как быстро работает твоя программа, если она не работает."(с)
Старая истина.И в вашем коде серьзная проблема — он игнорирует возможные ошибки.
SA>2.Приведенный мною код — результат двухсуточного чтения MSDN и попыток понять, SA>что же именно и где в <стандартных> функциях для VARIANT не работает.Понял.
Могу вам в двух словах сформулировать: не стоит ожидать успешной конверсии VT_EMPTY и VT_NULL во что либо ещё. VariantChangeType вообще-то возвращает HRESULT, который вообще-то проверять положено — можно даже себе пару дней раздумий сэкономить если так и делать. Не стоит ожидать всегда успешной VariantChangeType — даже при "легальной" конверсии может и E_OUTOFMEMORY вернуть, например. И нюансов при преобразованиях хватает.
SA>Финальный вариант, оттестированный и работающий с клиентом, как надо
Понимать что код делает тяжеловато, не дай бог в таком стиле чего посложнее сделать. Говоря о потерях времени я имею в виду не SafeArrayAccess, а абсолютно ненужное создание второго SafeArray, второго VARIANT, и странные манипуляции со всем этим хозяйством. Кстати, VARIANT — обычная и документированная структура, можете делать с ней всё что хотите.
Приведенный мною код — основан на опыте прим. 5 лет почти исключительно ATL/СОМ программирования (правда давно им почти не занимаюсь), уж не знаю скольких дней с МСДН, и бесчисленного кол-ва виденных МС исходников (по части Result->parray->pvData).