Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Функция ReadFile (http://forum.oszone.net/showthread.php?t=51758)

DillerInc 17-07-2005 01:01 341607

Функция ReadFile
 
Здраствуйте!
Проблема заключается в том,что указанная функция походу возвращает False,и я не могу разобраться,почему так происходит.
Итак имеется следующая ситуация:
Код:

var
 hExe : HWND = 0;
{ Дескриптор получен с помощью CreateFileA с установкой флага GENERIC_READ и без каких-либо FILE_FLAG_NO_BUFFERING }
 MemPtr : Pointer = NIL;
{ Указатель получен с помощью VirtualAlloc }
 FileSize : DWORD;
{ Этот параметр получен от GetFileSize(hExe, NIL) }
 BytesRead : DWORD;
begin
 ReadFile(hExe, MemPtr, FileSize, BytesRead, NIL);
...

В итоге,как я уже говорил,функция возвращает False, по указателю MemPtr не наблюдается никаких считанных данных и переменная BytesRead не содержит кол-ва этих считанных байт.
Собственно,господа,какие будут соображения замечания по данному поводу ?

Savant 17-07-2005 01:09 341608

А мона кода побольше? Вот эти самые CreateFile() (без А), VirtualAlloc()... Кстати, что возвращает GetLastError() после ReadFile()? hEXE на всякий сделай типа HANDLE.

DillerInc 17-07-2005 02:04 341624

Savant
Цитата:

А мона кода побольше?
Код:

CreateFile(OpenDlgBox.lpstrFile, GENERIC_READ, 0, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
...кстати,почему без "А" - меняется ли от этого что-нибудь?
Код:

VirtualAlloc(NIL, MemSize, MEM_COMMIT, PAGE_READWRITE);
Параметр MemSize типа DWORD получен какими-то непонятными ухищрениями от значания параметра FileSize:
Код:

asm
 mov eax, [FileSize]    // Этот
 add eax, 00010000  // код
 and eax, 3FFF0000 //  не я придумал =]
 mov [MemSize], eax
end;

GetLastError в следующей конструкции:
Код:

if ReadFile(тра-ля-ля) = False then
 GetLastError;

...вроде бы возвращает значение 03Е6h = 998 = ERROR_NOACCESS (смотрел в отладчике), что возможно означает,что проблема в функции VirtualAlloc.
Цитата:

hEXE на всякий сделай типа HANDLE
...дык, Delphi начинает орать,что не знает такого идентификатора...

lehha 17-07-2005 14:18 341698

DillerInc
Цитата:

...кстати,почему без "А" - меняется ли от этого что-нибудь?
Все системы семейства вындос начиная с в2к работают только с уникодом, точнее они работают и с анси строками но с начала они их переведут в уникод сделают нужное преоброзование а затем результат вернут в анси, так что А это для работы с анси а W с уникодом -> с юникодом программа будет быстрее работать
Есть 2 функции CreateFile - это CreateFileA и CreateFileW разница между ними что А работает с анси кодировкой а W с уникодом, когда ты просто пишешь CreateFile компилятор сам определит с чем ты работаешь, вот кусок определеня критфайл из winbase.h
Код:

WINBASEAPI  HANDLE  WINAPI  CreateFileA(IN LPCSTR lpFileName,
 IN DWORD dwDesiredAccess,
 IN DWORD dwShareMode,
 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
 IN DWORD dwCreationDisposition,
 IN DWORD dwFlagsAndAttributes,
 IN HANDLE hTemplateFile      );
 WINBASEAPI  HANDLE  WINAPI  CreateFileW(IN LPCWSTR lpFileName,
 IN DWORD dwDesiredAccess,     
 IN DWORD dwShareMode,   
 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,   
 IN DWORD dwCreationDisposition,   
 IN DWORD dwFlagsAndAttributes,   
 IN HANDLE hTemplateFile      );
 #ifdef UNICODE
 #define CreateFile  CreateFileW
 #else
 #define CreateFile  CreateFileA
 #endif // !UNICODE

Такая схема у всех функций которые работают с файлами и со строками.


lehha 17-07-2005 14:19 341700

DillerInc
а файл вообще открылся???

DillerInc 17-07-2005 16:43 341721

lehha
Цитата:

CreateFile - это CreateFileA и CreateFileW
...значит выгоднее работать с функцией CreateFile ?
Цитата:

а файл вообще открылся???
...да,дескриптор файла возвратился нормальный,на его основе также нормально отработала функция GetFileSize,вернув размер открытого файла в байтах.

Мне кажется,что косяк кроется в работе функции VirtualAlloc,которая,если я правильно понял,должна инициализировать резервируемое пространство нулями.В моём случае,значение возвращаемое ею выглядит в отладчике как:
EAX=01490000
...если же посмотреть,что находится по этому смещению,то наблюдаешь одни знаки вопроса вместо нулей...разве так должно быть ?

Сейчас отлаживал в режиме ручной трассировки - наблюдал следующее:
Код:

;Значит зайдя внутрь функции ReadFile
;и очутившись в библиотеке Kernel32...
...
; в стек заносятся необходимые параметры и далее...
call [_imp_NtReadFile]
cmp eax, 00000103 ; а в EAX значение C0000005
jnz ...                  ; тут мы естественно прыгаем к чертям

Вот так вот,в EAX находится "любимое" значение C0000005 - STATUS_ACCESS_VIOLATION :( .
Как же быть тогда с этой VirtualAlloc - ведь получается,из-за неё тогда выходит такой бедлам ?

Savant 17-07-2005 23:16 341777

DillerInc
Хех, как все просто...... =) А сначала вообще в ступор я впал =) Даже весь код написать пришлось.
Код:

program rf;

{$APPTYPE CONSOLE}

uses
  Windows;

var
 hExe: Cardinal = 0;
 MemPtr: Pointer = nil;
 FileSize, BytesRead, MemSize: Cardinal;

begin
  hExe := CreateFile('c:\temp\test.txt', GENERIC_READ, 0, NIL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if hExe = INVALID_HANDLE_VALUE then WriteLn('CreateFile failed with code: ', GetLastError()) else WriteLn('CreateFile succeeded');
  FileSize := GetFileSize(hExe, nil);
  if FileSize = INVALID_FILE_SIZE then WriteLn('GetSize failed with code: ', GetLastError()) else WriteLn('GetSize succeeded, FileSize = ', FileSize);
  asm
    mov eax, [FileSize]  // FileSize -> eax
    add eax, $00010000  // +65536
    and eax, $3FFF0000  // выравнивание + ограничение по размеру
    mov [MemSize], eax  // eax -> MemSize
  end;
  MemPtr := VirtualAlloc(nil, MemSize, MEM_COMMIT, PAGE_READWRITE);
  if MemPtr = nil then WriteLn('VA failed with code: ', GetLastError()) else WriteLn('VA succeeded');
  if not ReadFile(hExe, MemPtr^, FileSize, BytesRead, NIL) then
    WriteLn('RF failed with code: ', GetLastError(), '. FileSize = ', FileSize, ', BytesRead = ', BytesRead, '.')
  else
    WriteLn('RF succeeded. FileSize = ', FileSize, ', BytesRead = ', BytesRead, '.');
  ReadLn;
  VirtualFree(MemPtr, 0, MEM_RELEASE);
  CloseHandle(hExe);
end.

Видно, что изменилось? ;)

DillerInc 17-07-2005 23:57 341782

Savant
Цитата:

Видно, что изменилось?
...кто бы мог подумать,что одна перевёрнутая галка,разыменовывающая указатель,может спасти "гиганта мысли"...
Ну,это называется - что я буду без тебя делать в своих инфотехнологических поползновениях :grin: .

Кстати,вот всё-таки хотелось бы подробнее узнать,чего мы добиваемся с помощью описанной ассемблерной вставки,в чём её суть ?

Savant 18-07-2005 07:45 341829

DillerInc
>>Кстати,вот всё-таки хотелось бы подробнее узнать,чего мы добиваемся с помощью описанной ассемблерной вставки,в чём её суть ?
Ну если я правильно понимаю, то:
Код:

  asm
// кладем значение FileSize в регистр eax процессора
    mov eax, [FileSize] 
// добавляем к значению FileSize (которое в регистре) число 10000h (65536)
    add eax, $00010000 
// выравниваем это значение на границу 10000h (т.е. делаем число кратным 10000h)
// и ограничиваем размерчик загребаемой памяти числом 3FFF0000h (1073676288 байт ~ 1 Гб)
    and eax, $3FFF0000
// кладем полученное значение в MemSize 
    mov [MemSize], eax 
  end;



Время: 10:01.

Время: 10:01.
© OSzone.net 2001-