| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Помогите с пересылкой массива COM-клиенту |
| Автор: arg 16.5.2003, 21:58 |
| Хочу передать из клиента серверу указатель, а сервер должен распределить память, заполнить массив и вернуть. Пользуюсь C++ Builder 5 и его стандартным Type Library Editor. Так вот редактор не дает установить атрибуты указателя, например, [size_is], которые нужны для сообщения маршалеру о размере массива, если я правильно понимаю. Как быть? |
| Автор: Guest_tim 17.5.2003, 02:22 |
| Может это и не то, что нужно, но предлагаю вариант: Я использую VARIANT и его поле parray - указатель на SAFEARRAY. Примерно так: VARIANT *vt; ::CoTaskMemAlloc(sizeof(VARIANT)); ::VariantInit(vt); pComponent->Method(VARIANT *vt); { //Устанавливаем тип указателя на массив VariantChangeType(...vt...); //Массив создаем при помощи функции SafeArrayCreate SAFEARRAY *psa; psa = SafeArrayCreate(...) //Здесь заполняем массив... vt->parray = psa; } Примерно так, конечно несколько строк пропущено, но думаю разберетесь. Если будут проблемы напишу подробнее Тим |
| Автор: arg 18.5.2003, 21:18 |
| Guest_tim, мне ваш вариант очень понравился. Я сделал так, как понял, но не получается. Взгляните: На стороне сервера ******************************** STDMETHODIMP TFillStructureImpl::GetArray(VARIANT* parr) { int i; int* psadata; SAFEARRAY *psa; SAFEARRAYBOUND rgsabnd; VariantChangeType(parr,parr,VARIANT_NOVALUEPROP,varInteger); rgsabnd.cElements=5; rgsabnd.lLbound=0; psa = SafeArrayCreate(varInteger,1,&rgsabnd); SafeArrayLock(psa); SafeArrayAccessData(psa,&(void*)psadata); for(i=0;i<5;i++) psadata[i]=i+1; SafeArrayCopy(psa,&(parr->parray)); SafeArrayUnaccessData(psa); SafeArrayUnlock(psa); return S_OK; } ******************************** На стороне клиента ******************************** VARIANT *vt; int *psadata; vt=(VARIANT *)CoTaskMemAlloc(sizeof(VARIANT)); VariantInit(vt); SrvObj->GetArray(vt); SafeArrayLock(vt->parray); SafeArrayAccessData(vt->parray,&(void*)psadata); ... ******************************** на стороне клинета после таких операций в psadata неопределенные значения. Плиз, подскажите, что я сделал не так? |
| Автор: Guest_tim 19.5.2003, 19:39 |
| Вот мой код, это метод моего класса по работе с ADO. Этот метод заполняет SAFEARRAY набором данных, полученный от SQL запроса. Суть метода похожа на Ваш. Обратите внимание, как я пакую массив в вариант: ... //Пакуем массив в VARIANT V_VT(vtOutRecordsArray) = VT_ARRAY | VT_VARIANT; V_ARRAY(vtOutRecordsArray) = pSA; ... И еще одна особенность - я не блокирую SAFEARRAY (SafeArrayLock(psa);), может в этом дело (хотя не должно быть). Попробуйте так запаковать. Ниже клиентский код по распаковке. Клиентский компонент по отношению к серверному работает с ASP страницей (но не суть важно). На HTML тэги можно не обращать внимания Такой подход работает (создано лично), если проблемы не исправятся будем думать дальше. Надеюсь поможет Тим ========================================================================= На сервере: ========================================================================= void CSmartADO::FillArrayFromRecordset(VARIANT *vtOutRecordsArray) { if (m_spRecordset) { //Число записей в наборе long lRecordsCount = 0; //Определяем число записей в наборе while (!m_spRecordset->adoEOF) { m_spRecordset->MoveNext(); lRecordsCount++; } if (lRecordsCount > 0) { m_spRecordset->MoveFirst(); } SAFEARRAY *pSA; SAFEARRAYBOUND aDim[2]; aDim[0].lLbound = 0; aDim[0].cElements = lRecordsCount + 1; //Помимо строк заносим еще и имена полей, поэтому + 1 aDim[1].lLbound = 0; aDim[1].cElements = m_spRecordset->GetFields()->GetCount(); //По числу полей в наборе long l[2]; int i, j; _variant_t vt; //Создаем массив pSA = SafeArrayCreate(VT_VARIANT, 2, aDim); if (pSA) { //Заносим в первую строку массива имена полей из набора for (i = 0; i < m_spRecordset->GetFields()->GetCount(); i++) { l[0] = 0; l[1] = i; vt = m_spRecordset->GetFields()->GetItem((CComVariant)i)->GetName(); SafeArrayPutElement(pSA, l, &vt); } j = 1; //Пробегаем по всем записям и заносим их в массив while (!m_spRecordset->adoEOF) { for (i = 0; i < m_spRecordset->GetFields()->GetCount(); i++) { l[0] = j; l[1] = i; vt = m_spRecordset->GetFields()->GetItem((CComVariant)i)->GetValue(); SafeArrayPutElement(pSA, l, &vt); } j++; m_spRecordset->MoveNext(); } } else { throw; } //Удаляем набор данных (больше он не нужен, т.к. данные в массиве) m_spRecordset->Close(); m_spRecordset.Release(); //Пакуем массив в VARIANT V_VT(vtOutRecordsArray) = VT_ARRAY | VT_VARIANT; V_ARRAY(vtOutRecordsArray) = pSA; } else { //Возвращаем пустой указатель V_VT(vtOutRecordsArray) = VT_ARRAY | VT_VARIANT; V_ARRAY(vtOutRecordsArray) = NULL; //throw; } } ========================================================================= На клиенте: ========================================================================= void CCertificate::DrawCalculations(VARIANT *pvtArray) { HRESULT hr; SAFEARRAY *psa = NULL; LONG lLBound1, lUBound1, lLBound2, lUBound2; LONG lInd[2]; VARIANT vtValue; //Присваиваем указатель на SAFEARRAY в переменную psa из варианта psa = pvtArray->parray; //m_pIResponse->Write((_variant_t)"Определение границ массива...<BR>"); //Узнаем границы массива SafeArrayGetLBound(psa, 1, &lLBound1); SafeArrayGetUBound(psa, 1, &lUBound1); SafeArrayGetLBound(psa, 2, &lLBound2); SafeArrayGetUBound(psa, 2, &lUBound2); //m_pIResponse->Write((_variant_t)"Обход массива...<BR>"); //Производим отображение данных m_pIResponse->Write((_variant_t)"<TABLE border=2>"); for (LONG i = lLBound1; i <= lUBound1; i++) { m_pIResponse->Write((_variant_t)"<TR>"); for (LONG j = lLBound2; j <= lUBound2; j++) { lInd[0] = i; lInd[1] = j; hr = SafeArrayGetElement(psa, lInd, &vtValue); if (FAILED(hr)) _com_issue_error(hr); m_pIResponse->Write((_variant_t)"<TD>"); m_pIResponse->Write(vtValue); m_pIResponse->Write((_variant_t)"</TD>"); } m_pIResponse->Write((_variant_t)"</TR>"); } m_pIResponse->Write((_variant_t)"</TABLE>"); //m_pIResponse->Write((_variant_t)"Удаление массива...<BR>"); //Не забываем удалить массив (SmartADOComponent - создает, а здесь - удаляем) hr = SafeArrayDestroy(psa); if (FAILED(hr)) _com_issue_error(hr); } |
| Автор: arg 22.5.2003, 18:17 |
| Большое спасибо, все заработало. Интересно, а массивы объектов таким способом можно передавать? |
| Автор: Guest_tim 27.5.2003, 19:53 |
| Очень рад, что смог помочь На счет объектов не пробовал, может заработает... Тим |