Возникла нужда быстро набросать код для загрузки файла в память. Решил взять код ms-rem'a отсюда : http://wasm.ru/article.php?article=apihook_2 НО почему-то при загрузке некоторых файлов я получаю ошибку 216. Т.е. где-то идет обращение к несуществующей памяти. Почему так? Какая может быть здесь зависимость от типа загружаемых данных? Вот эта функция: Код (Text): Function DownloadFile(Address: PChar; var ReturnSize: dword): pointer; var Buffer: pointer; BufferLength: dword; BufferUsed: dword; Bytes: integer; Header: PChar; Site: PChar; URL: PChar; FSocket: integer; SockAddrIn: TSockAddrIn; HostEnt: PHostEnt; Str: PChar; WSAData: TWSAData; hHeap: dword; begin Result := nil; hHeap := GetProcessHeap(); WSAStartup(257, WSAData); Site := MyCopy(Address, 1, MyPos('/', Address) - 1); URL := MyCopy(Address, MyPos('/', Address), lstrlen(Address) - MyPos('/', Address) + 1); Buffer := HeapAlloc(hHeap, 0, 1024); try BufferLength := 1024; BufferUsed := 0; FSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); SockAddrIn.sin_family := AF_INET; SockAddrIn.sin_port := htons(80); SockAddrIn.sin_addr.s_addr := inet_addr(Site); if SockAddrIn.sin_addr.s_addr = INADDR_NONE then begin HostEnt := gethostbyname(Site); if HostEnt = nil then Exit; SockAddrIn.sin_addr.s_addr := Longint(PLongint(HostEnt^.h_addr_list^)^); end; if Connect(FSocket, SockAddrIn, SizeOf(SockAddrIn)) = -1 then Exit; Str := HeapAlloc(hHeap, 0, 1024); lstrcpy(Str, 'GET '); lstrcat(Str, URL); lstrcat(Str, ' HTTP/1.0'#10#13'Host: '); lstrcat(Str, Site); lstrcat(Str, #13#10'Connection: close'#13#10#13#10); send(FSocket, Str^, lstrlen(Str), 0); HeapFree(hHeap, 0, Str); repeat if BufferLength - BufferUsed < 1024 then begin Inc(BufferLength, 1024); Buffer := HeapReAlloc(hHeap, 0, Buffer, BufferLength); end; Bytes := recv(FSocket, pointer(dword(Buffer) + BufferUsed)^, 1024, 0); if Bytes > 0 then Inc(BufferUsed, Bytes); until (Bytes = 0) or (Bytes = SOCKET_ERROR); Header := MyCopy(Buffer, 1, MyPos(#13#10#13#10, Buffer) + 3); ReturnSize := BufferUsed - lstrlen(header); Result := VirtualAlloc(nil, ReturnSize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE); if Result = nil then Exit; MyCopyMemory(Result, pointer(dword(Buffer) + lstrlen(header)), ReturnSize); finally HeapFree(hHeap, 0, Buffer); end; end; Ошибка возникает где-то здесь: Код (Text): repeat if BufferLength - BufferUsed < 1024 then begin Inc(BufferLength, 1024); Buffer := HeapReAlloc(hHeap, 0, Buffer, BufferLength); end; Bytes := recv(FSocket, pointer(dword(Buffer) + BufferUsed)^, 1024, 0); if Bytes > 0 then Inc(BufferUsed, Bytes); until (Bytes = 0) or (Bytes = SOCKET_ERROR); Потому-что , после этого кода при обращении к Buffer идет ошибка
Runtime error 216 Это вроде не правильное обращение к памяти. Функция как-то не правильно работает с памятью кучи имхо. Вот мне интересно что именно не правильно. Ошибка возникает только при обращении к Buffer , например MessageBox(0,Buffer,'',0);
Во-первых, тебе все-таки стоит пользоваться отладчиком. "Примерно здесь" - это расплывчатое понятие. А экстрасенсы все уехали на телепередачу. Во-вторых, функция HeapReAlloc имеет свойство падать при очень частом ее вызове. У меня такая же ситуация была с GlobalReAlloc. Но, если мне ни скем не изменяет память, моя функция является просто переходником к твоей. Мой тебе совет: а) сделай проверку дескриптора после вызова HeapReAlloc на валидность. Выводи мессаджбок с кодом ошибки, если такая произошла б) сделай самопальную функцию перевыделения памяти - я в свое время так решил эту же проблему. Почему происходит падение, мне никто так объяснить и не смог, в сети я упоминаний не нашел. А вот HeapAlloc, MoveData (имя просто придумал, чтобы порядок показать), HeapFree - и будет тебе счастье
тогда почему HeapAlloc выделяет нужный размер памяти, а ReAlloc падает? По сути, в обоих случаях происходит выделение памяти, копирование данных, освобождение старой памяти. Но почему виндовый менеджер падает, а мой работает - мне непонятно
MSoft без понятия. у меня не падал. вы б показали код на котором падает? впрочем, <новый адрес> = реаллок(<старый адрес>, ...); новый адрес может быть равным старому адресу, а может и измениться. при этом старый адрес станет невалидным (реаллок с него упадет), хотя сама страница и старое содержимое по нему, скорей всего останутся доступными и не изменятся. может этот момент ^
нет, проблема именно в возвращаемом указателе - функция возвращала ошибку, а не указатель на память. Т.е. не было креша, просто в еах был 0 (ну или что там апишка при ошибке возвращает). Я уже не помню, где код был и для чего я его писал.
MSoft это надо смотреть конкретный код. но хипер выни вполне может быть не лучшим. почему нет? например, может аллоцировать строго из наибольшей области или следующей по адресу. или у вас реаллоки перемежались с аллоками (с классами такой фокус можно поиметь запросто) пока области нужного размера не осталось.