Функция ReadFile

Ответить
Аватара пользователя
DillerInc

Функция ReadFile

Сообщение DillerInc »

Здраствуйте!

Проблема заключается в том,что указанная функция походу возвращает 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

Re: Функция ReadFile

Сообщение Savant »

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

Re: Функция ReadFile

Сообщение DillerInc »

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 начинает орать,что не знает такого идентификатора...
Аватара пользователя
DillerInc

Re: Функция ReadFile

Сообщение DillerInc »

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

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

Re: Функция ReadFile

Сообщение DillerInc »

DillerInc

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

Re: Функция ReadFile

Сообщение DillerInc »

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

Re: Функция ReadFile

Сообщение Savant »

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

Re: Функция ReadFile

Сообщение DillerInc »

Savant


Цитата:



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



...кто бы мог подумать,что одна перевёрнутая галка,разыменовывающая указатель,может спасти "гиганта мысли"...

Ну,это называется - что я буду без тебя делать в своих инфотехнологических поползновениях Изображение .



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

Re: Функция ReadFile

Сообщение Savant »

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;
Ответить

Вернуться в «Программирование и базы данных»