Здравствуйте Max_Akimov, Вы писали:
MA>...Прокси нет.
Ну, дык а чё ты хотел без прокси? Если прокси не зарегистрирована, то по умолчанию генерируется динамическая oleautomation-прокаи/стабина на базе tlb-хи. В tlb не попадает ни слова о твоих size_is-ах. Она видит "[in] long *s" и по правилам COM-а думает что ей должны передать размещенный указатель.
MA>Все это работает под win 2000 COM+, VC6, sp5.
Да уж под другой ОСью вряд ли заработает даже так...
MA>Объясните на пальцах плз. возможна ли в принципе передача массивов под COM+ без использования proxy.
Конечно возможна. Кстати COM+ ничем не отличается от простого COM-а, т.е. DCOM-а. Только для этого нужно меньше умных книг читать.

Т.е. нужно забыть о любых атрибутах для параметров кроме in, out и retval. Остальные просто не пободают в tlb (используются только для "ручной" компиляции прокси/стаба).
Предвижу вопрос... а как же тогда?
А очень просто ... с помощью SAFEARRAY. При этом код становится oleautomation-совместимым и может вызываться из VB и Delphi.
IDL для oleautomation-варианта буде выглядеть так:
Клиент на C++/ATL:
// Импорт для нашего COM-сервера. В реальной жизни проще пользоваться включение инклюда...
#import "..\Debug\OleautAry.dll" no_namespace, named_guids, no_implementation, raw_interfaces_only, raw_dispinterfaces,
raw_native_types
...
// Использование массива...
LRESULT OnClickedButton1(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
// Массив будет состоять из 6-и элементов и иметь нижнюю границу равную нулю
const int iLBound = 0, iCnt = 6;
// Создаем COM-сервер
CComPtr<IOleautIntAry> spObj;
HRESULT hr = spObj.CoCreateInstance(CLSID_OleautIntAry);
if(hr)
return 0;
// Создаем SAFEARRAY long-ов (VT_I4)
LPSAFEARRAY psa = SafeArrayCreateVector(VT_I4, iLBound, iCnt);
if(FAILED(psa))
return 0;
// Получаем доступ к "телу"
long * pLng = NULL;
hr = SafeArrayAccessData(psa, (void**)&pLng);
if(FAILED(hr))
return 0;
// Помещаем данные в наш массив
for(int i = iLBound; i < iCnt; i++)
{
pLng[i] = i * 6;
}
// "Отпускаем" массив
hr = SafeArrayUnaccessData(psa);
if(FAILED(psa))
return 0;
// Вызываем удаленный вызов
hr = spObj->InLongAry(&psa);
ATLASSERT(!hr);
// Уничтожаем массив
SafeArrayDestroy(psa);
return 0;
}
Сервер C++/ATL:
// IDL:
[
object,
uuid(3F252A3D-9109-46B6-BD7E-FBF4E59C0626),
dual, // Обязательно для oleautomation-маршалинга
//oleautomation, // Можно использовать вместо dual
pointer_default(unique)
]
interface IOleautIntAry : IDispatch
{
[id(1), helpstring("Метод принимающий SAFEARRAY long-ов")]
HRESULT InLongAry([in] SAFEARRAY(long) * ary);
};
// Реализация:
STDMETHODIMP COleautIntAry::InLongAry(SAFEARRAY ** ppsa)
{
if(!ppsa)
return E_POINTER;
if(!*ppsa)
return E_INVALIDARG;
// Посылаем товарищей если размерность массива не единица :)
if(SafeArrayGetDim(*ppsa) != 1)
return E_INVALIDARG;
// Получаем доступ к "телу"
long * pLng = NULL;
HRESULT hr = SafeArrayAccessData(*ppsa, (void**)&pLng);
if(FAILED(hr))
return hr;
// Узнаем верхнюю и нижнюю границу массива
LONG iLBound; LONG iUBound;
hr = SafeArrayGetLBound(*ppsa, 1, &iLBound);
ATLASSERT(!hr);
hr = SafeArrayGetUBound(*ppsa, 1, &iUBound);
ATLASSERT(!hr);
// Читаем данные и выводим из в окно отладчика (сервера!)
for(int i = iLBound; i <= iUBound; i++)
{
ATLTRACE("pLng[%d] = %d\n", i, pLng[i]);
}
// "Отпускаем" массив
return SafeArrayUnaccessData(*ppsa);
}
Исползование хелперов (например, нашего CascSaheArray из ascLib
http://www.rsdn.ru/files/?libs/asclib.xml) упрощает код в 3-5 раз и (естественно) уменьшает количество ошибок.
PS
Еще можно просто запаковать данные в BSTR (используя SysAllocStrinByteLen. Но этот вариант менее предпочтительнее, так так могут появится проблемы с конвертациями (об этом предупреждают гуру, но я ни разу не нарывался), а так же в виду корявости и не совместимости с другими средствами разработки.