![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как через TMemoryStream и IdTCPServer передать переменную Record [D7, XP]
oam333 © (2012-12-18 17:07:00)Есть переменная типа Record. В ней два параметра: типа Integer и типа TMemoryStream.
Как полученную переменную Record передать клиенту через IdTCPServer, чтобы на клиенте разобрать этот поток обратно в Record?
TPack = Record
block_num : integer;
pic_content : TMemoryStream;
end;
var stream_old: TPack;
procedure TForm1.Button1Click(Sender: TObject);
begin
stream_old.block_num := 10;
stream_old.pic_content := TMemoryStream.Create;
end;
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var strText: string;
i: integer;
ScreenCopy: TCanvas;
gr: TBitmap;
rcDest, rcSource: TRect;
PNG: TPNGObject;
begin
rcSource := Screen.DesktopRect; //исходный размер картинки
rcDest := Rect(0, 0, 100, 100); //конечный размер картинки
ScreenCopy := TCanvas.Create;
ScreenCopy.Handle := GetDC(0);
gr:= TBitmap.Create;
gr.Height := 100;
gr.Width := 100;
gr.Canvas.CopyRect(rcDest, ScreenCopy, rcSource);
PNG := TPNGObject.Create;
PNG.Assign(gr);
PNG.SaveToStream(stream_old.pic_content);
PNG.Free;
gr.Free;
AThread.Connection.WriteStream( stream_old, true, true);
end;
Вот как в предпоследней строке передать stream_old?
oam333 (2012-12-20 23:52:00) [1]брат Птибурдукова
ага, в этом был косяк. Только крышка ^ после memory нужна. Тогда работает.
Большое спасибо!
Ваяем дальше.
брат Птибурдукова (2012-12-20 23:31:00) [2]
> stream_new[i].pic_content: TMemoryStream
Тогда ms.Write(stream_new[i].pic_content.memory, stream_new[i].pic_content.Size);
oam333 (2012-12-20 23:08:00) [3]брат Птибурдукова
> ms.Write(Pointer(status)^, status_length*SizeOf(Char));
эта хрень мне точно выдает то, что мне нужно, а именно в данном случае слово "block". Здесь пишем указатель на строку statusдлиной "количество символов в строке * размер чара".
> pointer(stream_new[i].pic_content)^
> Да и это фигня какая-то. pic_content какого типа?
stream_new - это массив of Record
stream_new[i].pic_content: TMemoryStream
MBo
> позицию читаемого потока надо выставить (в 0, наверно)
попробовал после
stream.Read(Pointer(pic_content)^, pic_content_length);
добавить
pic_content.Position:=0;
и отладчик показал на этой добавленной строке: "Project Client.exe raised exception with message 'Priveleged instruction'. Process stopped. Use Step or Run to continue."
MBo (2012-12-20 18:41:00) [4]>Что за фиговина? Передавай @status[1] или PChar(status).
не, там var, а не указатель
>и вот тут Access Violation
позицию читаемого потока надо выставить (в 0, наверно)
брат Птибурдукова (2012-12-20 17:25:00) [5]
> ms.Write(Pointer(status)^
Что за фиговина? Передавай @status[1] или PChar(status).
> pointer(stream_new[i].pic_content)^
Да и это фигня какая-то. pic_content какого типа?
oam333 (2012-12-20 16:21:00) [6]Я, видимо, замучаю всех. Эти Access Violation меня в конец выбесят..
Теперь при чтении стрима, который лежит в pic_content
Передатчик:
ms:=TMemoryStream.Create;
try
status:='block'; //block
status_length:=Length(status);
ms.Write(status_length, SizeOf(status_length));
ms.Write(Pointer(status)^, status_length*SizeOf(Char));
ms.Write(stream_new[i].block_col, SizeOf(stream_new[i].block_col));
ms.Write(stream_new[i].block_row, SizeOf(stream_new[i].block_row));
pic_content_length:=stream_new[i].pic_content.Size; // размер картинки
ms.Write(pic_content_length, SizeOf(pic_content_length)); // пишем размер картинки
ms.Write(pointer(stream_new[i].pic_content)^, stream_new[i].pic_content.Size); //пишем саму картинку
AThread.Connection.WriteStream(ms, true, true); // отправляем
finally
ms.Clear;
// ms.Free;
end;
Приемник:
pic_content: TMemoryStream;
Fs: TFileStream;
IdTCPClient1.ReadStream(stream);
stream.Position := 0;
stream.Read(status_length, sizeof(status_length));
SetLength(status, status_length);
stream.Read(Pointer(status)^, status_length*SizeOf(Char));
if (status = 'block') then
begin
stream.Read(block_col, sizeof(integer));
stream.Read(block_row, sizeof(integer));
stream.Read(pic_content_length, sizeof(pic_content_length)); //читаем размер картинки
pic_content.Size:=pic_content_length; // выделяем переменной память
stream.Read(Pointer(pic_content)^, pic_content_length); // читаем картинку
Fs := TFileStream.Create('out.bin', fmCreate, fmShareDenyWrite);
Fs.CopyFrom(pic_content, pic_content.Size); // и вот тут Access Violation
Fs.Free;
Тяжело мне даются потоки... уже упарился...
брат Птибурдукова (2012-12-20 13:04:00) [7]
> status_length*sizeof(string)
Бред, отсюда и AV. status_length * SizeOf(Char). Ну или status_length * SizeOf(status[0])
oam333 (2012-12-20 12:54:00) [8]Нашел косяк.
В приемнике, где читаю саму строку вместо
stream.Read(status, status_length*sizeof(string));
нужно писать указать на status, а не саму переменную
stream.Read( Pointer(status )^, status_length*sizeof(string));
oam333 (2012-12-20 12:45:00) [9]Все равно вылетает Access Viaolation...
попробовал так:
передатчик:
status_length:=Length(status);
ms.Write(status_length, SizeOf(status_length));
ms.Write(PChar(status)^, Length(status)*SizeOf(status));
// ms.Write(PChar(status)^, Length(status); - так не прокатывает
// ms.Write(status[1], Length(status)*SizeOf(status)); - так не прокатывает
// ms.Write(status[1], Length(status)); - так не прокатывает
ms.Write(stream_new[i].block_col, SizeOf(stream_new[i].block_col));
ms.Write(stream_new[i].block_row, SizeOf(stream_new[i].block_row));
ms.Write(pointer(stream_new[i].pic_content)^, stream_new[i].pic_content.Size);
приемник:
IdTCPClient1.ReadStream(stream);
stream.Position := 0;
stream.Read(status_length, sizeof(status_length));
SetLength(status, status_length);
stream.Read(status, status_length*sizeof(string));
if (status = 'block') then //здесь снова Access Violation
<...>
Мышкой навожу на переменную statusв последней строке кода приемника (выше), пишет Inaccesible Value.
Скоро начну психовать...
MBo (2012-12-19 17:21:00) [10]строка status - указатель, sizeof(status) = 4, и в поток пишется не содержимое строки, а адрес, который приёмнику не нужен.
Нужно писать в поток сначала длину строки (Length), потом тело PChar(status)^
Германн (2012-12-19 17:19:00) [11]А так не пробовал?
ms.Write(status[1], Length(status));
oam333 (2012-12-19 17:05:00) [12]Опечатался немного выше.
Если в передатчике в блоке tryнаписано (как выше)
ms.Write(status, SizeOf(status));
то в приемнике в statusприлетает
#0#0#0#0
Если указано
ms.Write( Pointer(status )^, SizeOf(status));
то в приемнике вылетает в Access Violation на строке
if (status = 'block') then
oam333 (2012-12-19 16:44:00) [13]Блин, немного переделал, но вылетает Access Violation
передатчик:
TPack = Record
block_col : integer;
block_row : integer;
pic_content : TMemoryStream;
end;
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread); //отправка блоков
var stream_new: array of TPack;
status: string;
ms: TMemoryStream;
i: integer;
begin
<...>
// формирую все элементы stream_new
// что-то типа:
// stream_new[0...99].block_col:= 10...1000;
// stream_new[0...99].block_row:= 10...1000;
// stream_new[0...99].pic_content.LoadFromStream(какой-то стрим);
<...>
for i:=0 to 99 do
begin
ms:=TMemoryStream.Create;
try
status:='block';
ms.Write(status, SizeOf(status));
ms.Write(stream_new[i].block_col, SizeOf(stream_new[i].block_col));
ms.Write(stream_new[i].block_row, SizeOf(stream_new[i].block_row));
ms.Write(pointer(stream_new[i].pic_content)^, stream_new[i].pic_content.Size);
{ ms.WriteBuffer(stream_new[i].block_col, sizeof(stream_new[i].block_col));
ms.WriteBuffer(stream_new[i].block_row, sizeof(stream_new[i].block_row));
ms.WriteBuffer(stream_new[i].pic_content.memory^, stream_new[i].pic_content.Size); }
AThread.Connection.WriteStream(ms, true, true);
finally
ms.Clear;
// ms.Free;
end;
end;
приемник:
procedure TForm1.Button1Click(Sender: TObject);
var stream: TMemoryStream;
status: string;
begin
repeat
status:='';
IdTCPClient1.ReadStream(stream);
stream.Position := 0;
stream.Read(status, sizeof(status));
if (status = 'block') then // здесь вылетает Access Violation
begin
stream.Read(block_col, sizeof(integer));
stream.Read(block_row, sizeof(integer));
stream.Read(pic_content, pic_content.Size);
//дальше обработка полученных данных
<...>
end;
stream.Clear;
until status = 'end';
stream.Free;
end;
Anatoly Podgoretsky (2012-12-19 13:01:00) [14]> oam333 (19.12.2012 08:46:05) [5]
Хочешь узнать передавай в потоке
Сергей М. (2012-12-19 10:16:00) [15]передатчик:
ms := TMemoryStream.Create;
try
ms.WriteBuffer(stream_old.block_num, sizeof(block_num));
ms.WriteBuffer(stream_old.pic_content.memory^, stream_old.pic_content.Size);
AThread.Connection.WriteStream(ms, true, true);
finally
ms.Free;
free;
приемник:
pack.block_num := AThread.Connection.ReadInteger;
AThread.Connection.ReadStream(pack.pic_content, -1, true);
oam333 (2012-12-19 09:16:00) [16]Медвежонок Пятачок
> В смысле ты боишься, что не сможешь узнать длину интегера?
Как говорится, прозрение! Ведь block_num это ж integer. Меня почему-то переклинило, и я думал, что если block_num=5, то длина одна, а если block_num=1234, то длина другая. Почему-то подумал, что нужно считать каждую цифру в значении. Мда.. Переработал.
Сейчас чего-нибудь наваяем.
Сенкс!
Медвежонок Пятачок (2012-12-19 09:04:00) [17]Хотел именно за один прием (
За один прием можно, но не в твоем случае.
Откуда я узнаю длину block_num
В смысле ты боишься, что не сможешь узнать длину интегера?
oam333 (2012-12-19 08:46:00) [18]брат Птибурдукова
пост опубликовал и только потом понял смысл вопроса.
Да, именно в MemoryStream я бы и хотел запихнуть block_num, но нихрена понять не могу как. Много чего перечитал в гугле, но все равно не пойму. Понятно, что нужно пользоваться seek, но возникает вопрос:
если вставить в начало потока значение block_num, а вслед за ним значение pic_content, то как я потом смогу разобрать на клиенте этот поток обратно на block_num и pic_content? Откуда я узнаю длину block_num и длину pic_content, чтобы вытащить значения из потока?
oam333 (2012-12-19 08:38:00) [19]брат Птибурдукова
> ЗЫ. А зачем тут запись? Почему бы block_num не пихать в
> тот же MemoryStream?
Хотел именно за одинприем (за один WriteStream) передать все значения. Или такое все же невозможно?
oam333 (2012-12-19 08:36:00) [20]
> Вот так и передать.
> Но перед тем как, - встать в начало стрима
stream_oldтипа Record и не может быть передан в чистом виде как поток, т.к. не типа TMemoryStream.