Re: Передача данных TClientDataset через стандартные потоки
От Dmytry Ginzburg (2:461/48.125) к Vladimir Ulchenko
В ответ на Заголовок предыдущего сообщения в треде (Имя Автора)
Здравствуйте, о моногоуважаемый(ая), Vladimir!
Вот.. Hабил письмецо.. А вот, что из этого вышло:
Как-то, Среда, Сентябрь 23 2009, в 17:34, Vladimir Ulchenko приехал к Dmytry Ginzburg на белом лимузине, да как заорёт _"Re: Передача данных TClientDataset через стандартные потоки"_
DG>> При чём ProviderEOF равен true. И соответственно я предположил, что
DG>> проблема
VU> ProviderEOF означает что данные у провайдера закончились и данный пакет
VU> последний
Понял. Спасибо за информацию, теперь буду знать.
DG>> именно в концевом символе, который по какой-то причине при передаче
DG>> через
DG>> стандартный поток вывода, замкнутый на пайп запортился, т.к. длина
DG>> передаваемого и получаемого пакета через пайп одинаковая.
VU> вместо того чтобы выдумывать какие-то чуднЫе причины мог бы просто тупо
VU> сравнить содержимое двух текстовых файлов
А вот эта тоже хорошая идея. Ещё раз спасибо. Я ей воспользовался.
DG>> Hу и где ж её надо тогда искать?
VU> проблема либо в содержимом твоего пакета (по какой-то причине
VU> сторона-приемник не распознала его, например версии мидаса разные с двух
VU> сторон) либо в самом мидасе ибо он славен своими глюками которых в нем
VU> ахулиард
VU> можешь попробовать прочесть свой пакет прям на стороне генерации в другой
VU> cds можешь сменить формат на бинарный можешь свой пакет тут опубликовать,
VU> вдруг нелениво окажется на него посмотреть можешь перепробовать разные
VU> версии мидаса если выяснишь что именно в нем жопа
Всё оказалось гораздо проще. Я уже на это напарывался, но урок не извлёк. Дело в том, что есть необходимость иногда использовать Delphi вместо эхотага, а там часто в API функции нужно передавать не указатели, а сами переменные. В данном случае в функции ReadFile надо было просто разыменовать указатель. Hо самое интересное то, что главную проблему я так и не решил. Вкратце суть проблемы выглядит так: есть компьютеры под управлением WinXP (ноутбуки). Имеется COM-сервер на компьютерах под управлением или Win2k или Win2k3. А общение с сервером происходит через COM-объекты из клиентской библиотеки, т.к. их интерфейсы более удобные для сложного проектирования. Hо программа должна также общаться с БД MSSQL. А в борландовских средах разработки с данной БД можно работать только через ADO или DBExpress (в обоих случаях используется oledb). Так вот в чём возникла проблема. В моей программе начали сыпаться AV в системных библиотеках на выполнении SQL запросов, которые возвращают наборы данных. Причём это происходило только, если сервер работал под Win2k. И, к сожалению, такая ситуация у заказчика. Я сначала грешил на конфликт между этой библиотекой и oledb, но после недавнего эксперимента оказалось, что проблема более серьёзная. Я вынес обращение к БД за пределы моей программы, а у себя подгружал данные через пайпы в TClientDataSet. Hо данный класс тоже инкапсулирует в себя определённые COM-объекты из библиотеки midas.dll. Таким образом при корректном выполнении запроса во внешнем приложении (проверялось на программе без использования проблемного COM-объекта) при выполнении LoadFromStream метода вываливается AV в midas.dll. Таким образом получается, что вышеупомянутый COM-объект конфликтует со всеми другими COM-объектами и каким-то образом портит память, распределяемую менеджером COM, поскольку мидас не имеет ничего общего с oledb, кроме менеджера памяти. Разведение объектов по разным однопоточным аппартментам не помогло. Соответственно, для решения проблемы нужно найти способ общаться с БД, используя все возможности борланда, но при этом не замыкаться на COM. Про возможность работы с MSSQL минуя COM из борланда я не знаю, если кто знает, подскажите (bde не предлагать). Другой вариант рассматривался, как воспользоваться вместо TClientDataSet TMemoryDataSet из библиотеки Rx. Hо он не умеет себя стримировать. Третий вариант, который я сейчас рассматриваю заключается вот в чём. Как я видел, объект конфликтует только с внутрипроцессными COM-объектами. Про внепроцессные COM-объекты я пока ничего не знаю, но если бы удалось работать с внешним COM-объектом, то можно было бы создать оболочку из интерфейсов над TDataSet, которые бы жили в отдельном процессе, но которые бы без проблем можно было вызывать в моём приложении. Hо для этого нужно написать внепроцессный сервер. Я попытался создать один такой на базе TRemoteDataModule (просто эксперимента ради). Hо оказалось, что Borland ведёт себя в этом плане очень интересно. Мой сервер не нуждается в окне, более того я хочу использовать модель Free, т.к. она работает быстрее. Hо делфи не разрешает создавать COM-сервера в консольных приложениях. Эхотаг не так привередлив, поэтому я создал приложение с функцией WinMain, которую хочу реализовать сам. При добавлении к такому приложению COM-объекта создаётся bpf-файл, в котором создаётся модуль ATL. Hо по непонятной мне причине в консольных приложениях этот содержимое этого файла не исполняется. Hо это не беда, я перетащил эти описания в файл с расширением cpp, где находиться функция WinMain. Как нас учит Дональд Бокс при модели Free в главном потоке петлю сообщений реализовывать нет необходимости, а можно просто поставить Wait-функцию, которая будет удерживать главный поток в режиме ожидания, пока существует хотя бы одна ссылка на интерфейс COM-объекта. Поэтому делал так
_!--==> А тута Windows Clipboard начинается... <==--!_
//---------------------------------------------------------------------------
TComModule _ProjectModule(0 /*InitATLServer*/);
TComModule &_Module = _ProjectModule;
// The ATL Object map holds an array of _ATL_OBJMAP_ENTRY structures that
// described the objects of your OLE server. The MAP is handed to your
// project's CComModule-derived _Module object via the Init method.
//
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_MyServer, TMyServerImpl)
END_OBJECT_MAP()//Это всё скопировано из bpf-файла, он корректно выполнился, т.к. объект зарегистрировался.
#pragma argsused
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{if(!strstr(lpCmdLine,"regserver")&&(!strstr(lpCmdLine,"unregserver")))WaitForS ingleObject(hEvent,INFINITE);
return 0;
}
_!--==> А тута Windows Clipboard заканчивается... <==--!_
Всё вроде бы просто. Hо при попытке подключиться к такому серверу через DCOMConnection клиент намертво подвешивается, да и сервер похоже тоже. Пробовал вместо Wait-функции ставить петлю сообщений. Эффект был тот же самый. Объясните мне кто-нибудь в чём я не прав.
Желаю Вам всего наилучшего, Vladimir.Дмитрий.
--- Вот такой вот наглый Дед со стажем в 3.0.1-asa9 SR1 лет!
* Origin: Default ORIGIN (FidoNet 2:461/48.125)
Ответы на это письмо:
From: Username
Заголовок следующего сообщения в треде может быть длинным и его придется перенести на новую строку
From: Username
Или коротким