Re: Передача данных TClientDataset через стандартные потоки
От Dmytry Ginzburg (2:461/48.125) к Vladimir Ulchenko
В ответ на Заголовок предыдущего сообщения в треде (Имя Автора)
Здравствуйте, о моногоуважаемый(ая), Vladimir!
Вот.. Hабил письмецо.. А вот, что из этого вышло:
Как-то, Понедельник, Сентябрь 21 2009, в 09:28, Vladimir Ulchenko приехал к Dmytry Ginzburg на белом лимузине, да как заорёт _"Re: Передача данных TClientDataset через стандартные потоки"_
VU> From: "Vladimir Ulchenko" <vavan@santel.ru>
VU> Hello, Dmytry!
VU> You wrote to Vladimir Ulchenko on Sat, 19 Sep 2009 00:01:11 +0400:
DG>> ровно такое количество байтов, которое и должно, но то, что я получил из
DG>> пайпа, я не могу загрузить в датасет, т.к. получаю ошибку Datatype
DG>> mismatch или что-то в этом роде. Я прошёлся отладчиком и обнаружил, что
DG>> эту ошибку возвращает интерфейс датасета при параметре FProviderEof=true.
DG>> И тогда я предположил, что дело именно в этом символе Eof, который
DG>> некорректно прошёл через пайп. Hо вот
VU> никакого специального "символа завершения датасета" в мидасе нет. судя по
VU> первоначальному примеру датасет ты берешь в формате xml, т.е. пакет идет в
VU> галимом текстовом формате, в чем ты можешь убедиться сохранив пакеты с
VU> обеих сторон и сравнив содержимое, уверен они будут совпадать
Ещё раз привожу код клиента и сервера. Hадеюсь, модераторы возражать не будут против кода клиента на Delphi
Вот сервер, который должен выполнить запрос и отдать результат клиенту. Его код простой
_!--==> А тута Windows Clipboard начинается... <==--!_
//---------------------------------------------------------------------------
TMemoryStream *str=new TMemoryStream();;
#pragma argsused
int main(int argc, char* argv[])
{AnsiString s="Begin of main";
OutputDebugString(s.c_str());
char c[65535];
char c2;
int t=1;
if(IsDebuggerPresent())s="I'm under debugger";else s="I am not under debugger";
OutputDebugString(s.c_str());
try{try{CoInitialize(0);
s="I've executed CoInititalize";
OutputDebugString(s.c_str());
DataModule2=new TDataModule2(0);
s="I've created DataModule2";
OutputDebugString(s.c_str());
if(!gets(c))s="I haven't got any string because of error";else{
s=c;
s="I've got connection string. It's "+s;}
OutputDebugString(s.c_str());
DataModule2->ADOQuery1->ConnectionString=c;
s="I've put connection string to ADOQuery";
OutputDebugString(s.c_str());
if(!gets(c)){s=errno;s="I haven't got any string because of error"+s;}else{
s=c;
s="I've got query for database. It's "+s;}
OutputDebugString(s.c_str());
DataModule2->ADOQuery1->SQL->Add(c);
s="I've put my query to ADOQuery";
OutputDebugString(s.c_str());
DataModule2->ADOQuery1->Open();
DataModule2->ClientDataSet1->Open();
s="I've executed query";
OutputDebugString(s.c_str());
t=DataModule2->ClientDataSet1->DataSize;
s=t;
s="DataSize is "+s;
OutputDebugString(s.c_str());
s="I've put DataSize to cout";
OutputDebugString(s.c_str());
DataModule2->ClientDataSet1->SaveToStream(str,dfXML);//Пробовал и двоичный и xml формат
t=str->Size;
char *p=(char *)&t;
//for(int i=0;i<4;cout<<*p,p++,i++);
s=str->Size;
s="I've saved query result to stream It has size "+s;
//gets(&c2);
OutputDebugString(s.c_str());
char *c1=(char *)str->Memory;
s="I've got the stream's address";
OutputDebugString(s.c_str());
//cout<<str->Size<<'\n';
for(int i=0;i<str->Size;cout<<*c1,c1++,i++);//Вот здесь я выливаю в поток cout.
s="I've sent stream to cout";
OutputDebugString(s.c_str());
}
__finally{
if(DataModule2)DataModule2->Free();
if(str)str->Free();
CoUninitialize();
}}
catch(Exception *e){OutputDebugString(e->Message.c_str());
cout<<e->Message.c_str();}
return 0;
}
_!--==> А тута Windows Clipboard заканчивается... <==--!_
Теперь показываю клиента. Для получения отладочной информации процесс стартую из отдельного потока в режиме отладчика
_!--==> А тута Windows Clipboard начинается... <==--!_
procedure TDebugForm.Button2Click(Sender: TObject);
var l,c,q,l1,e:cardinal;
b:boolean;
p,p1:Pointer;
str:TMemoryStream;
Thread:TDebugThread;
c1:^cardinal;
s:string;
i:integer;
w:char;
begin
DataSource1.DataSet:=ClientDataSet1;
Thread:=TDebugThread.Create(false);
while Thread.info1.hprocess=0 do Application.ProcessMessages;//Жду, пока будет запущен дочерний процесс (сервер).
begin
//ShowMessage('Дочерний процесс создан');
{while not(PeekNamedPipe(Thread.Hinwr,nil,0,nil,@l,nil)and(l>0))do
begin
q:=GetLastError;
StatusBar1.SimpleText:=IntToStr(q);
Application.ProcessMessages;
end;
GetMem(p2,l);
b:=ReadFile(Thread.Hinwr,p2,l,l1,nil);
if b then
begin
s:=string(p2);
ShowMessage(s);
end;}
p1:=PChar(Edit1.Text+#13+#10);
c:=length(Edit1.Text)+2;
b:=WriteFile(Thread.houtr,p1^,c,l,nil);
Application.ProcessMessages;
if not b then
begin
q:=GetLastError;
StatusBar1.SimpleText:='Ошибка записи с кодом '+IntToStr(q);
end;
if b then
begin
{
GetMem(p2,l);
b:=ReadFile(Thread.Hinwr,p2^,l,l1,nil);
if b then
for i:=0 to l1-1 do
begin
s:=s+p2^;
Inc(p2);
end;}
p1:=PChar(Edit2.Text+#13+#10);
e:=length(Edit2.Text)+2;
b:=WriteFile(Thread.houtr,p1^,e,l,nil);
c:=c+e;
Application.ProcessMessages;
if b then
begin
while not(PeekNamedPipe(Thread.Hinwr,nil,0,nil,@l,nil)and(l>0))do
begin
q:=GetLastError;
StatusBar1.SimpleText:=IntToStr(q);
Application.ProcessMessages;
end;
GetMem(p,l);//Вот в этом месте я выделяю память под получение данных. Переменная l имеет то же значение, что и видная в окне отладки длина стрима
b:=ReadFile(Thread.Hinwr,p^,l,l1,0);
if b then
begin
str:=TMemoryStream.Create;
str.Write(p,l);
str.Position:=0;
ClientDataSet1.LoadFromStream(str);//Вот тут я получаю ошибку Mismatch in DataPacket
str.Free;
FreeMem(p);
end;
end;
end;
end;
end;
_!--==> А тута Windows Clipboard заканчивается... <==--!_
Также собрав проект с отладочными dcu, я обнаружил, что ошибка возникает при выполнении метода OpenCursor датасета на такой строке
_!--==> А тута Windows Clipboard начинается... <==--!_
Check(FDSBase.AppendData(DataPacket, ProviderEOF));
_!--==> А тута Windows Clipboard заканчивается... <==--!_
При чём ProviderEOF равен true. И соответственно я предположил, что проблема именно в концевом символе, который по какой-то причине при передаче через стандартный поток вывода, замкнутый на пайп запортился, т.к. длина передаваемого и получаемого пакета через пайп одинаковая.
VU> так что проблему ты ищешь совсем не там
Hу и где ж её надо тогда искать?
VU> зы. если будешь описывать ошибки как "что-то в этом роде" ты вероятно
VU> и
VU> ответы будешь получать в виде "где-то там и как-то так" :)
Hу вот я описал подробно ситуацию. Идеи какие-нибудь есть, куда ткнуться, чтобы разрешить проблему.
Желаю Вам всего наилучшего, Vladimir.Дмитрий.
--- Вот такой вот наглый Дед со стажем в 3.0.1-asa9 SR1 лет!
* Origin: Default ORIGIN (FidoNet 2:461/48.125)
Ответы на это письмо:
From: Username
Заголовок следующего сообщения в треде может быть длинным и его придется перенести на новую строку
From: Username
Или коротким