Delphi Memory-Mapped File의 간단한 예

10157 단어 Delphi
{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}

unit MainFrm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

const
  FName = 'test.txt';

type

  TMainForm = class(TForm)
    btnUpperCase: TButton;
    memTextContents: TMemo;
    lblContents: TLabel;
    btnLowerCase: TButton;
    procedure btnUpperCaseClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnLowerCaseClick(Sender: TObject);
  public
    UCase: Boolean;
    procedure ChangeFileCase;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.DFM}

procedure TMainForm.btnUpperCaseClick(Sender: TObject);
begin
  UCase := True;
  ChangeFileCase;
end;

procedure TMainForm.btnLowerCaseClick(Sender: TObject);
begin
  UCase := False;
  ChangeFileCase;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  memTextContents.Lines.LoadFromFile(FName);
  // Change to upper case by default.
  UCase := True;
end;

procedure TMainForm.ChangeFileCase;
var
  FFileHandle: THandle; // Handle to the open file.
  FMapHandle: THandle;  // Handle to a file-mapping object
  FFileSize: Integer;   // Variable to hold the file size.
  FData: PByte;         // Pointer to the file's data when mapped.
  PData: PChar;         // Pointer used to reference the file data.
begin

  { First obtain a file handle to the file to be mapped. This code
    assumes the existence of the file. Otherwise, you can use the
    FileCreate() function to create a new file. }

  if not FileExists(FName) then
    raise Exception.Create('File does not exist.')
  else
    FFileHandle := FileOpen(FName, fmOpenReadWrite);

  // If CreateFile() was not successful, raise an exception
  if FFileHandle = INVALID_HANDLE_VALUE then
    raise Exception.Create('Failed to open or create file');

  try
    { Now obtain the file size which we will pass to the other file-
      mapping functions. We'll make this size one byte larger as we
      need to append a null-terminating character to the end of the
      mapped-file's data.}
    FFileSize := GetFileSize(FFileHandle, Nil);

   { Obtain a file-mapping object handle. If this function is not
      successful, then raise an exception. }
    FMapHandle := CreateFileMapping(FFileHandle, nil,
       PAGE_READWRITE, 0, FFileSize, nil);

    if FMapHandle = 0 then
      raise Exception.Create('Failed to create file mapping');
  finally
    // Release the file handle
    CloseHandle(FFileHandle);
  end;

  try
    { Map the file-mapping object to a view. This will return a pointer
      to the file data. If this function is not successful, then raise
      an exception. }
    FData := MapViewOfFile(FMapHandle, FILE_MAP_ALL_ACCESS, 0, 0, FFileSize);

    if FData = Nil then
      raise Exception.Create('Failed to map view of file');

  finally
    // Release the file-mapping object handle
    CloseHandle(FMapHandle);
  end;

  try
    { !!! Here is where you would place the functions to work with
    the mapped file's data. For example, the following line forces
    all characters in the file to uppercase }
    PData := PChar(FData);
    // Position the pointer to the end of the file's data
    inc(PData, FFileSize);

    // Append a null-terminating character to the end of the file's data
    PData^ := #0;

    // Now set all characters in the file to uppercase
    if UCase then
      StrUpper(PChar(FData))
    else
      StrLower(PChar(FData));

  finally
    // Release the file mapping.
    UnmapViewOfFile(FData);
  end;
  memTextContents.Lines.Clear;
  memTextContents.Lines.LoadFromFile(FName);
end;

end.

Using a DLL with Shared Memory
//ShareLib.dpr
{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}

library ShareLib;

uses
  ShareMem,
  Windows,
  SysUtils,
  Classes;
const

  cMMFileName: PChar = 'SharedMapData';

{$I DLLDATA.INC}

var
  GlobalData : PGlobalDLLData;
  MapHandle  : THandle;

{ GetDLLData will be the exported DLL function }
procedure GetDLLData(var AGlobalData: PGlobalDLLData); StdCall;
begin
  { Point AGlobalData to the same memory address referred to by GlobalData. }
  AGlobalData := GlobalData;
end;

procedure OpenSharedData;
var
   Size: Integer;
begin
  { Get the size of the data to be mapped. }
  Size := SizeOf(TGlobalDLLData);

  { Now get a memory-mapped file object. Note the first parameter passes
    the value $FFFFFFFF or DWord(-1) so that space is allocated from the system's
    paging file. This requires that a name for the memory-mapped
    object get passed as the last parameter. }

  MapHandle := CreateFileMapping(DWord(-1), nil, PAGE_READWRITE, 0, Size, cMMFileName);

  if MapHandle = 0 then
    RaiseLastWin32Error;
  { Now map the data to the calling process's address space and get a
    pointer to the beginning of this address }
  GlobalData := MapViewOfFile(MapHandle, FILE_MAP_ALL_ACCESS, 0, 0, Size);
  { Initialize this data }
  GlobalData^.S := 'ShareLib';
  GlobalData^.I := 1;
  if GlobalData = nil then
  begin
    CloseHandle(MapHandle);
    RaiseLastWin32Error;
  end;
end;

procedure CloseSharedData;
{ This procedure un-maps the memory-mapped file and releases the memory-mapped
  file handle }
begin
  UnmapViewOfFile(GlobalData);
  CloseHandle(MapHandle);
end;

procedure DLLEntryPoint(dwReason: DWord);
begin
  case dwReason of
    DLL_PROCESS_ATTACH: OpenSharedData;
    DLL_PROCESS_DETACH: CloseSharedData;
  end;
end;

exports
  GetDLLData;

begin
  { First, assign the procedure to the DLLProc variable }
  DllProc := @DLLEntryPoint;
  { Now invoke the procedure to reflect that the DLL is attaching
    to the process }
  DLLEntryPoint(DLL_PROCESS_ATTACH);
end.

App1:
//App1.dpr
{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}

unit MainFrmA1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls, ExtCtrls, Mask;

{$I DLLDATA.INC}

type

  TMainForm = class(TForm)
    edtGlobDataStr: TEdit;
    btnGetDllData: TButton;
    meGlobDataInt: TMaskEdit;
    procedure btnGetDllDataClick(Sender: TObject);
    procedure edtGlobDataStrChange(Sender: TObject);
    procedure meGlobDataIntChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  public
    GlobalData: PGlobalDLLData;
  end;

var
  MainForm: TMainForm;

{ Define the DLL's exported procedure }
procedure GetDLLData(var AGlobalData: PGlobalDLLData); StdCall External 'SHARELIB.DLL';

implementation

{$R *.DFM}

procedure TMainForm.btnGetDllDataClick(Sender: TObject);
begin
  { Get a pointer to the DLL's data }
  GetDLLData(GlobalData);
  { Now update the controls to reflect GlobalData's field values }
  edtGlobDataStr.Text := GlobalData^.S;
  meGlobDataInt.Text  := IntToStr(GlobalData^.I);
end;

procedure TMainForm.edtGlobDataStrChange(Sender: TObject);
begin
  { Update the DLL data with the changes }
  GlobalData^.S := edtGlobDataStr.Text;
end;

procedure TMainForm.meGlobDataIntChange(Sender: TObject);
begin
  { Update the DLL data with the changes }
  if meGlobDataInt.Text = EmptyStr then
    meGlobDataInt.Text := '0';
  GlobalData^.I := StrToInt(meGlobDataInt.Text);
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  btnGetDllDataClick(nil);
end;

end.

App2:
//App2.dpr
{
Copyright ?1999 by Delphi 5 Developer's Guide - Xavier Pacheco and Steve Teixeira
}

unit MainFrmA2;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, StdCtrls;

{$I DLLDATA.INC}

type

  TMainForm = class(TForm)
    lblGlobDataStr: TLabel;
    tmTimer: TTimer;
    lblGlobDataInt: TLabel;
    procedure tmTimerTimer(Sender: TObject);
  public
    GlobalData: PGlobalDLLData;
  end;

{ Define the DLL's exported procedure }
procedure GetDLLData(var AGlobalData: PGlobalDLLData); StdCall External 'SHARELIB.DLL';

var
  MainForm: TMainForm;

implementation

{$R *.DFM}

procedure TMainForm.tmTimerTimer(Sender: TObject);
begin
  GetDllData(GlobalData);  // Get access to the data
  { Show the contents of GlobalData's fields.}
  lblGlobDataStr.Caption := GlobalData^.S;
  lblGlobDataInt.Caption := IntToStr(GlobalData^.I);
end;

end.

  

좋은 웹페이지 즐겨찾기