Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

BytesToRaw (Indy 10)

60K
22 июня 2010 года
MikeSoft
7 / / 22.06.2010
Добрый день, уважаемые коллеги.

Реализовывая передачу изображения по протоколу UDP столкнулся с проблемой перевода TBytes в TMemoryStream.

Для теста создал новый проект. На форму поместил два TImage, один TButton, TIdUDPClient и TIdUDPServer.
В Image1 поместил PNG изображение (153 байта)

Настраиваю компоненты:
 
Код:
UDPServer->DefaultPort = 2050;
UDPClient->Port = 2050;
UDPClient->Host = "127.0.0.1";
UDPServer->Active = true;


В событии OnClick для Button1 выполняю передачу объекта серверу:
Код:
TMemoryStream *msS = new TMemoryStream();

TPngImage *png = new TPngImage();
png->Assign(Image1->Picture);

png->SaveToStream(msS);
msS->Position = soFromBeginning;

TByteDynArray DynArray = RawToBytes(msS,msS->Size);

delete png, msS;
png = NULL, msS = NULL;

UDPClient->SendBuffer(DynArray);


Передача проходит на "ура". Теперь обрабатываю событие OnUDPRead:
Код:
void __fastcall TForm1::UDPServerUDPRead(TIdUDPListenerThread *AThread, TBytes AData,
                    TIdSocketHandle *ABinding)
{
  TMemoryStream *msR = new TMemoryStream();
  TPngImage *png = new TPngImage();

  BytesToRaw(AData,msR,AData.Length);  // проблемое место
  msR->Position = soFromBeginning;
  png->LoadFromStream(msR);
  Image2->Picture->Graphic = png;

  delete png, msR;
  png = NULL, msR = NULL;
}


Картинка появляется в Image2, но при закрытии формы возникает Access Violation.

Функция BytesToRaw в третьем параметре требует int Size. Я передаю ей размер полученных данных (AData.Length) получаю всё тот же AV.
Пробую передать размер TBytes (пробовал также для TByteDynArray):
 
Код:
BytesToRaw(AData,msR,sizeof(AData));

В этом случае поток msR имеет нулевую длину и ссылается в NULL

Пробовал работать с этой функцией без сетевой передачи (далее изменённый код OnClick для Button1):
Код:
TMemoryStream *msS = new TMemoryStream();

  TPngImage *png = new TPngImage();
  png->Assign(Image1->Picture);

  png->SaveToStream(msS);
  msS->Position = soFromBeginning;

  TByteDynArray DynArray = RawToBytes(msS,msS->Size);

  BytesToRaw(DynArray,msS,sizeof(DynArray));
  msS->Position = soFromBeginning;
  png->LoadFromStream(msS);
  mage2->Picture->Graphic = png;

  delete png, msS;
  png = NULL, msS = NULL;


Тогда ошибок не возникает.

Подскажите пожалуйста, что я делаю неправильно?
1
22 июня 2010 года
kot_
7.3K / / 20.01.2000
я думаю что ошибка в этом участке:
 
Код:
delete png, msR;
  png = NULL, msR = NULL;

вы по сути присваиваете указатель на объект, а потом его (объект и указатель на него) удаляете.
60K
22 июня 2010 года
MikeSoft
7 / / 22.06.2010
kot_, Спасибо за ответ.

Объявил объект png глобально. Проблема не исчезла.



Удаление объекта возможно, так как происходит копирование в Graphic и последующее отображение на канве.

Для примера можно выполнить такой код:
Код:
TFileStream *fs = new TFileStream("1.png",fmOpenRead);
TPngImage *png = new TPngImage();
png->LoadFromStream(fs);
Image1->Picture->Graphic = png;
png->LoadFromFile("2.png");
delete png;
png = NULL;
fs->Position = soFromBeginning;

Image1->Picture->Graphic->SaveToStream(fs);
Form1->Update();
Sleep(500);
Image1->Picture->Graphic->LoadFromStream(fs);
delete fs;
fs = NULL;

Объект был перезаписан, удалён и ссылка указывала в пустоту. Однако, поток fs по прежнему содержит 1.png
14
23 июня 2010 года
Phodopus
3.3K / / 19.06.2008
Что делает функция BytesToRaw() ?
60K
23 июня 2010 года
MikeSoft
7 / / 22.06.2010
Цитата: Phodopus
Что делает функция BytesToRaw() ?


Копирует бинарные значения из массива байт в нетипизированный буффер.

60K
23 июня 2010 года
MikeSoft
7 / / 22.06.2010
Проблема с приёмом/передачей решена.

Для преобразования TBytes в TStream необходимо использовать функцию WriteTIdBytesToStream (обратная ей функция - ReadTIdBytesFromStream).

Если кому-то пригодится (а точно пригодится), в верхнем исходнике необходимо заменить две строчки.

В событии OnClick меняем девятую строчку на:
 
Код:
TByteDynArray DynArray;
ReadTIdBytesFromStream(msS,DynArray,msS->Size);


А в событии OnUDPRead меняем седьмую строчку на:
 
Код:
WriteTIdBytesToStream(msR,AData,AData.Length,0);


:) Теперь необходимо только реализовать разбивку потока на максимально возможные пакеты (UDPClient->BufferSize)
14
23 июня 2010 года
Phodopus
3.3K / / 19.06.2008
Цитата: MikeSoft
Проблема с приёмом/передачей решена.


Цитата: MikeSoft
Копирует бинарные значения из массива байт в нетипизированный буффер.


конечно, ведь где тут

 
Код:
BytesToRaw(AData,msR,AData.Length);  // проблемое место

нетипизированный буфер?
60K
23 июня 2010 года
MikeSoft
7 / / 22.06.2010
Цитата: Phodopus
конечно, ведь где тут нетипизированный буфер?



msR->Memory я тоже пробовал.

14
23 июня 2010 года
Phodopus
3.3K / / 19.06.2008
Цитата: MikeSoft
msR->Memory я тоже пробовал.


Так и там он из ниоткуда не появится. См. метод SetSize(), и, возможно, нужно использовать *(msR->Memory) - я объявления BytesToRaw() не видел.

60K
23 июня 2010 года
MikeSoft
7 / / 22.06.2010
Цитата: Phodopus
Так и там он из ниоткуда не появится. См. метод SetSize(), и, возможно, нужно использовать *(msR->Memory) - я объявления BytesToRaw() не видел.


BytesToRaw обьявлена в IdGlobal.hpp

SetSize() - просто установит размер памяти потока, не возвращая указатель на выделенную память.

Я уже пробовал делать следующее:

 
Код:
msR->SetSize(AData.Length);
BytesToRaw(AData, msR->Memory,AData.Length);


Так же пробовал:
 
Код:
msR->SetSize(AData.Length);
msR->Write(&AData,msR->Size);


*(msR->Memory) - с этим потом вообще ничего не сделать.

А вот ReadTIdBytesFromStream и WriteTIdBytesToStream проблему решили полностью.
14
24 июня 2010 года
Phodopus
3.3K / / 19.06.2008
Цитата: MikeSoft

Я уже пробовал делать следующее:
 
Код:
msR->SetSize(AData.Length);
BytesToRaw(AData, msR->Memory,AData.Length);


и это по всем признакам должно было сработать

Цитата: MikeSoft

*(msR->Memory) - с этим потом вообще ничего не сделать.


разыменовывать void это я погорячился, конечно :)

60K
24 июня 2010 года
MikeSoft
7 / / 22.06.2010
Цитата: Phodopus
и это по всем признакам должно было сработать



Вот и я так думал... Но увы, результат был печальным.

Меня вообще удивила проблема использования:

 
Код:
BytesToRaw(AData,msR,AData.Length);

Данные копируются в поток, после этого корректно отображаются на канве TImage. И только при вызове деструктора формы проявляется AV.

Я сначала грешил на то, что передаю неправильный размер (кстати, так и непонятно, почему без сетевой передачи приведеный выше код работает корректно)... Возможно, Indy всё-таки грешит.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог