Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Проблема с idHTTP [D7, WinXP]


DVladimir ©   (2005-08-03 03:15:00) 

Приветствую!

Возникла странная проблема:
взял кусок кода из модуля idHTTP, вставил в свою библиотеку - а он не работает. Кусок наипростейший, но тем не менее.

Чтобы было всё предельно понятно, привожу вызов неработающей функции и библиотеку, в которой функция описана:

--Вызов: ---

Var Content, buf: PChar;
TestProc: function: PChar;
DLLHandle: THandle;
......
 DLLHandle:=LoadLibrary('libTest');
 if(DLLHandle = 0) then Begin
   ShowMessage('Cannot load DDL');
   Application.Terminate;
 end;
 try
   @TestProc:=GetProcAddress(DLLHandle,PChar('GetURL'));
   try
     buf:=TestProc;
     //Предполагаю, что buf не nil (так оно есть) - проверку опущу
     GetMem(Content, Length(buf)+1);
     Content:=StrLCopy(Content,buf,Length(buf));
     ShowMessage(StrPas(Content));
   except
     ShowMessage('Error in GetURL'); //Вот эта ошибка вылетает
     Application.Terminate;
   end;
 finally
   FreeLibrary(DLLHandle);
 end;

--Библиотека: ---

library libTest;

uses
 SysUtils,
 Classes,
 Dialogs, //Just for ShowMessage()
 idHTTP;

{$R *.res}

function GetURL: PChar;
Var
 HTTP: TidHTTP;
 strResponse: TMemoryStream;
 b: String;
Begin
 HTTP:=TidHTTP.Create(nil);
 HTTP.Host:='localhost';
 HTTP.Port:=80;
 strResponse:=TMemoryStream.Create;
 {$H+} //For ANSI string...
 try
   HTTP.Connect(-1);
   HTTP.DoRequest(hmGet, ' http://localhost/test.html', nil, strResponse);
   if strResponse.Size > 0 then begin
     ShowMessage('Readed: '+IntToStr(a));
     try
       SetLength(b,strResponse.Size); //Вот тут если руками прописать около 1000 байт, ошибки не бывает
       Move(PChar(strResponse.Memory)^, b[1],strResponse.Size);
     except
       //Ни одно из перечисленных exception-ов не возникает.
       //Вернее блок exception вообще не выполняется
       on E: EOutOfMemory do ShowMessage('E: '+E.Message);
       on E: EInvalidPointer do ShowMessage('E: '+E.Message);
       on E: EAccessViolation do ShowMessage('E: '+E.Message)
       else ShowMessage('Unknown error');
     end;
   end;
   Result:=PChar(b);
 except
   Result:=PChar('Error: '+IntToStr(HTTP.ResponseCode));
 end;
 strResponse.Free;
 HTTP.Disconnect;
 HTTP.Destroy;
end;

exports
 GetURL;

begin
end.

Помогите найти ошибку!
Спасибо!


Slym   (2005-08-04 17:04:00) [1]

обнаруживаю, что Length(test) равно 3.
Мдя... Ацес Виолатион по тебе плачет...

GetMem(Buf,Response.Size+1); //+1 ли? - Именно!

с PChar так "Length(test)" не поступают


DVladimir   (2005-08-04 16:35:00) [2]

Ага, почти всё понял. Спасибо!

Возникла еще проблема :) Прошу извинения, если достал.

Я решил в функцию не передавать BufSize, т.к. реально его размер я не знаю до получения страницы. Сделал так:


   try
    HTTP:=TidHTTP.Create(nil);
    try
      HTTP.Get(' http://localhost/test.html', Response);
      if Response.Size>0 then
      begin
        ShowMessage('Readed: '+IntToStr(Response.Size));
        GetMem(Buf,Response.Size); //+1 ли?
        StrLCopy(Buf,Response.Memory,Response.Size-1);
      end else
      Buf^:=#0;
    finally
      HTTP.Free;
    end;
  finally
    Response.Free;
  end;


И после GetMem у меня размер Buf становится = 3, а после StrLCopy в нем какие-то странные 3 байта.

Я даже попробовал в этой функции объявить локальную
test: PChar, так и после
GetMem(test,Response.Size);
обнаруживаю, что Length(test) равно 3.

Что я опять не так делаю, в чем не прав?
Спасибо!


Slym   (2005-08-04 09:06:00) [3]

Для новичков ВСЕГДА имеет смысл.
Это "ручной" SafeCall - ДЛЛ должна сама обработать все ошибки! и в лучшем случае вернуть true/false в худшем код ошибки для дальнейшего анализа в программе


Digitman   (2005-08-04 08:38:00) [4]


> мне привычнее такое поведение


не путай.
это совсем другой случай.


> Имеет ли смысл вызов    
> Response:=TMemoryStream.Create;
> оборачивать в try ... except ?


исключение при конструировании этого объекта весьма маловероятно.
например, может возникнуть EOutOfMemory, если на этот момент ты опустошил кучу


DVladimir   (2005-08-03 17:44:00) [5]

Slym ©   (03.08.05 14:30) [4]

Да, всё четко и понятно.
Спасибо большое!

Только вопрос несколько уже офф-топик.
Имеет ли смысл вызов    
Response:=TMemoryStream.Create;
оборачивать в try ... except ?
Ну в смысле я не знаю какие могут исключения возникнуть...


DVladimir   (2005-08-03 17:09:00) [6]

Digitman ©   (03.08.05 13:21) [3]

Это-то да.
Не могу спорить, т.к. понимаю, что скорее всего не прав.
Скажу лишь в оправдание, что мне привычнее такое поведение:

sub MyProc {
 my $a = 'Some data';
 return \$a;
}

и после вызова
my $ref_a = MyProc();

я получу не мертвый указатель, а именно указатель на 'Some data';

Это на самом деле мой чуть ли не первый опыт на Delphi.
Тем не мнее спасибо большое!


Slym   (2005-08-03 14:30:00) [7]

function GetURL(Buf:PChar;SizeBuf:integer): LongBool;
Var
 Response: TMemoryStream;
 HTTP: TidHTTP;
Begin
 try
   Response:=TMemoryStream.Create;
   try
     HTTP:=TidHTTP.Create(nil);
     try
       HTTP.Get(' http://localhost/test.html', Response);
       if Response.Size>0 then
       begin
         ShowMessage('Readed: '+IntToStr(Response.Size));
         StrLCopy(Buf,Response.Memory,SizeBuf-1);
       end else
       if SizeBuf>0 then
       Buf^:=#0;
     finally
       HTTP.Free;
     end;
   finally
     Response.Free;
   end;
   result:=true;
 except
   on E:Exception do
   begin
     result:=false;
     StrLCopy(Buf,PChar(Format('Raised exception %s with message %s',[E.ClassName,E.Message])),SizeBuf-1);
   end;
 end;
end;


TestProc:=GetProcAddress(DLLHandle,PChar('GetURL'));
GetMem(Content, 1024);
try
 TestProc(Content, 1024);
 ShowMessage(StrPas(Content));
finally
 FreeMem(Content);
end;


Digitman   (2005-08-03 13:21:00) [8]


> DVladimir   (03.08.05 13:08) [2]
> Да нет.


да ДА!!

причем здесь "около 1000 байт" ?

время жизни лок.переменной процедуры равно времени жизни процедуры !


DVladimir   (2005-08-03 13:08:00) [9]

Да нет.
Т.е. если я пишу
SetLength(b,500); //Вот тут если руками прописать около 1000 байт, ошибки не бывает
Move(PChar(strResponse.Memory)^, b[1],500);

То вызывающая функция получает указатель на 500 байт полученного текста. И вот это
GetMem(Content, Length(buf)+1);
Content:=StrLCopy(Content,buf,Length(buf));
ShowMessage(StrPas(Content));

прекрасно отрабатывает.


Lamer@fools.ua   (2005-08-03 07:16:00) [10]

> Result:=PChar(b);

Это неправильно. После выхода из функции указатель станет невалидным.


Наверх

Титульная страница Поиск, карта сайта Написать письмо