Проблемы с загрузкой файла по http. Функция ms-rem

Тема в разделе "WASM.BEGINNERS", создана пользователем Selah, 18 окт 2010.

  1. Selah

    Selah New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2007
    Сообщения:
    258
    Возникла нужда быстро набросать код для загрузки файла в память. Решил взять код ms-rem'a отсюда : http://wasm.ru/article.php?article=apihook_2

    НО почему-то при загрузке некоторых файлов я получаю ошибку 216. Т.е. где-то идет обращение к несуществующей памяти. Почему так? Какая может быть здесь зависимость от типа загружаемых данных?

    Вот эта функция:

    Код (Text):
    1. Function DownloadFile(Address: PChar; var ReturnSize: dword): pointer;
    2. var
    3.   Buffer: pointer;
    4.   BufferLength: dword;
    5.   BufferUsed: dword;
    6.   Bytes: integer;
    7.   Header: PChar;
    8.   Site: PChar;
    9.   URL: PChar;
    10.   FSocket: integer;
    11.   SockAddrIn: TSockAddrIn;
    12.   HostEnt: PHostEnt;
    13.   Str: PChar;
    14.   WSAData: TWSAData;
    15.   hHeap: dword;
    16. begin
    17.   Result := nil;
    18.   hHeap := GetProcessHeap();
    19.   WSAStartup(257, WSAData);
    20.   Site := MyCopy(Address, 1, MyPos('/', Address) - 1);
    21.   URL  := MyCopy(Address, MyPos('/', Address), lstrlen(Address) - MyPos('/', Address) + 1);
    22.   Buffer := HeapAlloc(hHeap, 0, 1024);
    23.   try
    24.     BufferLength := 1024;
    25.     BufferUsed := 0;
    26.     FSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    27.     SockAddrIn.sin_family := AF_INET;
    28.     SockAddrIn.sin_port := htons(80);
    29.     SockAddrIn.sin_addr.s_addr := inet_addr(Site);
    30.     if SockAddrIn.sin_addr.s_addr = INADDR_NONE then
    31.        begin
    32.         HostEnt := gethostbyname(Site);
    33.         if HostEnt = nil then Exit;
    34.         SockAddrIn.sin_addr.s_addr := Longint(PLongint(HostEnt^.h_addr_list^)^);
    35.        end;
    36.     if Connect(FSocket, SockAddrIn, SizeOf(SockAddrIn)) = -1 then Exit;
    37.     Str := HeapAlloc(hHeap, 0, 1024);
    38.     lstrcpy(Str, 'GET ');
    39.     lstrcat(Str, URL);
    40.     lstrcat(Str, ' HTTP/1.0'#10#13'Host: ');
    41.     lstrcat(Str, Site);
    42.     lstrcat(Str, #13#10'Connection: close'#13#10#13#10);
    43.     send(FSocket, Str^, lstrlen(Str), 0);
    44.     HeapFree(hHeap, 0, Str);
    45.     repeat
    46.       if BufferLength - BufferUsed < 1024 then
    47.         begin
    48.          Inc(BufferLength, 1024);
    49.          Buffer := HeapReAlloc(hHeap, 0, Buffer, BufferLength);
    50.         end;
    51.       Bytes := recv(FSocket, pointer(dword(Buffer) + BufferUsed)^, 1024, 0);
    52.       if Bytes > 0 then Inc(BufferUsed, Bytes);
    53.     until (Bytes = 0) or (Bytes = SOCKET_ERROR);
    54.     Header := MyCopy(Buffer, 1, MyPos(#13#10#13#10, Buffer) + 3);
    55.     ReturnSize := BufferUsed - lstrlen(header);
    56.     Result := VirtualAlloc(nil, ReturnSize, MEM_COMMIT or
    57.                            MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    58.     if Result = nil then Exit;
    59.     MyCopyMemory(Result, pointer(dword(Buffer) + lstrlen(header)), ReturnSize);
    60.   finally
    61.     HeapFree(hHeap, 0, Buffer);
    62.   end;
    63. end;
    Ошибка возникает где-то здесь:

    Код (Text):
    1. repeat
    2.       if BufferLength - BufferUsed < 1024 then
    3.         begin
    4.          Inc(BufferLength, 1024);
    5.          Buffer := HeapReAlloc(hHeap, 0, Buffer, BufferLength);
    6.         end;
    7.       Bytes := recv(FSocket, pointer(dword(Buffer) + BufferUsed)^, 1024, 0);
    8.       if Bytes > 0 then Inc(BufferUsed, Bytes);
    9.     until (Bytes = 0) or (Bytes = SOCKET_ERROR);
    Потому-что , после этого кода при обращении к Buffer идет ошибка
     
  2. Selah

    Selah New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2007
    Сообщения:
    258
    Данные - текст размером в ~500 кб
     
  3. ptr

    ptr New Member

    Публикаций:
    0
    Регистрация:
    14 мар 2009
    Сообщения:
    130
    а отладчиком воспользоваться религия не позволяет?
     
  4. Selah

    Selah New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2007
    Сообщения:
    258
    исключения в отладчике мне ничего не говорят...
     
  5. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Это печально.
     
  6. Selah

    Selah New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2007
    Сообщения:
    258
    ага. по делу есть что сказать?)
     
  7. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Selah
    Что есть ошибка ?
     
  8. Selah

    Selah New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2007
    Сообщения:
    258
    Runtime error 216

    Это вроде не правильное обращение к памяти. Функция как-то не правильно работает с памятью кучи имхо. Вот мне интересно что именно не правильно. Ошибка возникает только при обращении к Buffer , например MessageBox(0,Buffer,'',0);
     
  9. Selah

    Selah New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2007
    Сообщения:
    258
    Или подскажите как правильно загружать большие файлы фрагментами как сделано здесь
     
  10. Selah

    Selah New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2007
    Сообщения:
    258
    без вининет
     
  11. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    А Delphi случайно не 2010? А то там в связи с тотальной юникодизацией местами так весело бывает :)
     
  12. Selah

    Selah New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2007
    Сообщения:
    258
    не. делфи7
     
  13. ptr

    ptr New Member

    Публикаций:
    0
    Регистрация:
    14 мар 2009
    Сообщения:
    130
    эмм.. GetLastError, Клерку нужен)
     
  14. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    Во-первых, тебе все-таки стоит пользоваться отладчиком. "Примерно здесь" - это расплывчатое понятие. А экстрасенсы все уехали на телепередачу.
    Во-вторых, функция HeapReAlloc имеет свойство падать при очень частом ее вызове. У меня такая же ситуация была с GlobalReAlloc. Но, если мне ни скем не изменяет память, моя функция является просто переходником к твоей.

    Мой тебе совет:
    а) сделай проверку дескриптора после вызова HeapReAlloc на валидность. Выводи мессаджбок с кодом ошибки, если такая произошла
    б) сделай самопальную функцию перевыделения памяти - я в свое время так решил эту же проблему. Почему происходит падение, мне никто так объяснить и не смог, в сети я упоминаний не нашел. А вот HeapAlloc, MoveData (имя просто придумал, чтобы порядок показать), HeapFree - и будет тебе счастье
     
  15. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    MSoft
    память фрагментируется. при частых реаллоках надо свой менеджер мутить, что вы и сделали
     
  16. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    тогда почему HeapAlloc выделяет нужный размер памяти, а ReAlloc падает? По сути, в обоих случаях происходит выделение памяти, копирование данных, освобождение старой памяти. Но почему виндовый менеджер падает, а мой работает - мне непонятно
     
  17. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    MSoft
    без понятия. у меня не падал. вы б показали код на котором падает?

    впрочем,

    <новый адрес> = реаллок(<старый адрес>, ...);

    новый адрес может быть равным старому адресу, а может и измениться. при этом старый адрес станет невалидным (реаллок с него упадет), хотя сама страница и старое содержимое по нему, скорей всего останутся доступными и не изменятся.

    может этот момент ^
     
  18. MSoft

    MSoft New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2006
    Сообщения:
    2.854
    нет, проблема именно в возвращаемом указателе - функция возвращала ошибку, а не указатель на память. Т.е. не было креша, просто в еах был 0 (ну или что там апишка при ошибке возвращает). Я уже не помню, где код был и для чего я его писал.
     
  19. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    MSoft
    это надо смотреть конкретный код. но хипер выни вполне может быть не лучшим. почему нет?
    например, может аллоцировать строго из наибольшей области или следующей по адресу. или у вас реаллоки перемежались с аллоками (с классами такой фокус можно поиметь запросто) пока области нужного размера не осталось.
     
  20. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    или еще такой вариант- случайно превысили размер аллоцированного буфера и затерли разметку хипа.