⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 excmemmap.pas

📁 一个异常处理的类
💻 PAS
字号:
unit ExcMemMap;

interface

uses
  Windows, SysUtils, Classes;

type
  EMMFileError = class( Exception );

  TMMFileStream = class( TStream )
  private
    FFile     : THandle;
    FMode     : Dword;
    FFileSize : Dword;
    FCurOffset: Dword;
    FMapping  : THandle;
    FView     : Pointer;
    FViewOfs  : Dword;
    FViewSize : Dword;
    FGranula  : Dword;
    FMaxView  : Dword;
    FReviews  : Dword;
    procedure ReView(DesiredOffset,DesiredDataSize: Dword );
    function  GetRawData(Offset: Dword): Pointer;
    property  RawData[Offset: Dword]: Pointer read GetRawData;

  public
    constructor Create( FileName: String; Mode: Longint; MapName: String );
    destructor  Destroy; override;

    function    MapData( Offset,Size: Dword ): Pointer;
    procedure   UnMapData;

    function    ReadByte: Byte;
    function    ReadWord: Word;
    function    ReadDword: Dword;
    function    ReadPointer: Pointer;

  public
    function Read(var Buffer; Count: Longint): Longint; override;
    function Write(const Buffer; Count: Longint): Longint; override;
    function Seek(Offset: Longint; Origin: Word): Longint; override;
  end;

implementation

uses ExcMagicUtils;

const
  VIEW_SIZE = 1; // in granulas (each granula on all current win32 platforms = 64K)

{ TMMFileStream }

constructor TMMFileStream.Create( FileName: String; Mode: Longint; MapName: String );
const
  AccessMode: array[0..2] of DWord = (
    GENERIC_READ,
    GENERIC_WRITE,
    GENERIC_READ or GENERIC_WRITE
  );
  ShareMode: array[0..4] of DWord = (
    0,
    0,
    FILE_SHARE_READ,
    FILE_SHARE_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE
  );
  MapProtect: array[0..2] of Dword = (
    PAGE_READONLY,
    0,
    PAGE_READWRITE
  );
var
  si: TSystemInfo;
begin
  inherited Create;

  if (Mode and 3) = fmOpenWrite then
    raise EMMFileError.Create( 'Invalid file mode: fmOpenWrite' );

  GetSystemInfo( si );
  FGranula := si.dwAllocationGranularity;
  FMode    := Mode;
  FMaxView := 0;
  FReviews := 0;
{$IFDEF EXCMAGIC_DEBUG}
  DebugMsg( Format('MMF: granula 0x%X, viewsize 0x%X, creating %s',[FGranula,FGranula*VIEW_SIZE,FileName]) );
{$ENDIF}

  FFile := CreateFile( PChar(FileName),
                       AccessMode[Mode and 3],
                       ShareMode[(Mode and $F0) shr 4],
                       nil,
                       OPEN_EXISTING,
                       0,
                       0 );
  if FFile <> INVALID_HANDLE_VALUE then
    begin
      FFileSize := GetFileSize( FFile, nil );
      FCurOffset:= 0;
{$IFDEF EXCMAGIC_DEBUG}
      DebugMsg( Format('MMF: F_handle %X, mapping %s',[FFile,MapName]) );
{$ENDIF}
      FMapping  := CreateFileMapping( FFile,
                                      nil,
                                      MapProtect[Mode and 3],
                                      0,
                                      0,
                                      PChar(StrChar2Char(MapName,'\','_')) );
      if FMapping = 0 then
        begin
          CloseHandle( FFile );
          raise EMMFileError.Create( 'Can''t create file mapping for ' +
            FileName + ': ' + SysErrorMessage(GetLastError) );
        end;
{$IFDEF EXCMAGIC_DEBUG}
      DebugMsg( Format('MMF: M_handle %X, result %X',[FMapping,GetLastError]) );
{$ENDIF}
    end
  else
    raise EMMFileError.Create( 'Can''t open file ' +
      FileName + ': ' + SysErrorMessage(GetLastError) );
end;

destructor TMMFileStream.Destroy;
begin
{$IFDEF EXCMAGIC_DEBUG}
  DebugMsg( Format('MMF: destroying. file %X, map %X, view %p',[FFile,FMapping,FView]) );
  DebugMsg( Format('     stat: maxviewsize %d, reviews %d', [FMaxView,FReviews]) );
{$ENDIF}
  if FView <> nil then UnmapViewOfFile( FView );
  CloseHandle( FMapping );
  CloseHandle( FFile    );
  inherited;
end;

procedure TMMFileStream.ReView( DesiredOffset,DesiredDataSize: Dword );
const
  DesiredAccess: array[0..2] of Dword = (
    FILE_MAP_READ,
    FILE_MAP_WRITE,
    FILE_MAP_WRITE
  );
begin
  if (FView <> nil) and
     (DesiredOffset >= FViewOfs) and
     (DesiredOffset + DesiredDataSize <= FViewOfs + FViewSize) then Exit;
{
               view offset
             /
 |     |     |     |     |     |     |
 |     |     |     |     |     |     |
                 |###|
                 |###|
                 ^
                 desired offset and size
}

  UnMapData;
  { move left to nearest granula }
  FViewOfs  := (DesiredOffset div FGranula) * FGranula;
  { }
  FViewSize := ((DesiredOffset + DesiredDataSize - FViewOfs) div (FGranula*VIEW_SIZE) + 1) * (FGranula*VIEW_SIZE);
  if Dword(FViewOfs + FViewSize) > FFileSize then FViewSize := FFileSize - Dword(FViewOfs);

  // some statistics
  if FViewSize > FMaxView then FMaxView := FViewSize;
  Inc( FReviews );

  FView := MapViewOfFile( FMapping,
                          DesiredAccess[FMode and 3],
                          0,
                          FViewOfs,
                          FViewSize
                          );
  if FView = nil then
    begin
      raise EMMFileError.Create( 'Can''t create file view: ' + SysErrorMessage(GetLastError) );
    end;
end;

function TMMFileStream.GetRawData(Offset: Dword): Pointer;
begin
  Result := Pointer( Dword(FView) + Offset - FViewOfs );
end;

function TMMFileStream.MapData(Offset,Size: Dword): Pointer;
begin
  ReView( Offset, Size );
  Result := RawData[Offset];
end;

procedure TMMFileStream.UnMapData;
begin
  if FView <> nil then UnmapViewOfFile( FView );
  FView := nil;
end;

function TMMFileStream.Seek(Offset: Integer; Origin: Word): Longint;
begin
  case Origin of
    soFromBeginning : FCurOffset := Offset;
    soFromCurrent   : FCurOffset := Longint(FCurOffset) + Offset;
    soFromEnd       : FCurOffset := Longint(FFileSize)  + Offset;
  end;
  Result := FCurOffset;
end;

function TMMFileStream.Write(const Buffer; Count: Integer): Longint;
begin
  Inc( FCurOffset, Count );
  Result := Count;
end;

function TMMFileStream.Read(var Buffer; Count: Integer): Longint;
begin
  ReView( FCurOffset, Count );
  Move( RawData[FCurOffset]^, Buffer, Count );
  Inc( FCurOffset, Count );
  Result := Count;
end;

function TMMFileStream.ReadByte: Byte;
begin
  ReView( FCurOffset, SizeOf(Byte) );
  Result := PByte( RawData[FCurOffset] )^;
  Inc( FCurOffset, SizeOf(Byte) );
end;

function TMMFileStream.ReadDword: Dword;
begin
  ReView( FCurOffset, SizeOf(Dword) );
  Result := PDword( RawData[FCurOffset] )^;
  Inc( FCurOffset, SizeOf(Dword) );
end;

function TMMFileStream.ReadPointer: Pointer;
type
  PPointer = ^Pointer;
begin
  ReView( FCurOffset, SizeOf(Pointer) );
  Result := PPointer( RawData[FCurOffset] )^;
  Inc( FCurOffset, SizeOf(Pointer) );
end;

function TMMFileStream.ReadWord: Word;
begin
  ReView( FCurOffset, SizeOf(Word) );
  Result := PWord( RawData[FCurOffset] )^;
  Inc( FCurOffset, SizeOf(Word) );
end;


end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -