{*******************************************************}
{                                                       }
{       Tocsg.CommonData                                }
{                                                       }
{       Copyright (C) 2022 kku                          }
{                                                       }
{*******************************************************}

unit Tocsg.CommonData;

interface

uses
  Tocsg.Obj, System.SysUtils, Winapi.Windows;

type
  TTgFileMapping<T> = class(TTgObject)
  protected
    hMap_: THandle;
    nAllocSize_: Integer;
    bFreeData_: Boolean;
  public
    Data: ^T;

    Constructor Create(const sMapFileName: String; const nShareSize: Integer = -1);
    Destructor Destroy; override;

    function IsAvailable: Boolean;

    property AllocSize: Integer read nAllocSize_;
    property LastError;
    property DoFreeData: Boolean write bFreeData_;
  end;

implementation

Constructor TTgFileMapping<T>.Create(const sMapFileName: String; const nShareSize: Integer = -1);
var
  pSd: PSecurityDescriptor;
  sa: TSecurityAttributes;
  bInit: Boolean;
begin
  Inherited Create;

  hMap_ := 0;
  Data := nil;
  bFreeData_ := true;

  if nShareSize > 0 then
    nAllocSize_ := nShareSize // 크기를 지정 해줄수 있도록 옵션 추가 14_1027 16:05:05 kku 
  else
    nAllocSize_ := SizeOf(T);

  bInit := false;
  hMap_ := OpenFileMapping(FILE_MAP_WRITE or FILE_MAP_READ, false, PChar(sMapFileName));
  if hMap_ = 0 then
  begin
    New(pSd);
    try
      if not InitializeSecurityDescriptor(pSd, SECURITY_DESCRIPTOR_REVISION) then
      begin
        nLastError_ := GetLastError;
        exit;
      end;

      if not SetSecurityDescriptorDacl(pSd, true, nil, false) then
      begin
        nLastError_ := GetLastError;
        exit;
      end;

      sa.nLength := SizeOf(sa);
      sa.lpSecurityDescriptor := pSd;
      sa.bInheritHandle := TRUE;

      hMap_ := CreateFileMapping(THandle(-1),
                                 @sa,
                                 PAGE_READWRITE,
                                 0,
                                 nAllocSize_,
                                 PChar(sMapFileName));
      bInit := true;
    finally
      Dispose(pSd);
    end;
  end;

  if hMap_ <> 0 then
  begin
    Data := mapViewOfFile(hMap_,
                          FILE_MAP_ALL_ACCESS,
                          0,
                          0,
                          nAllocSize_);

    if Data = nil then
    begin
      nLastError_ := GetLastError;
      CloseHandle(hMap_);
      hMap_ := 0;
    end else begin
      if bInit then
        ZeroMemory(Data, nAllocSize_);
      nLastError_ := ERROR_SUCCESS;
    end;
  end else
    nLastError_ := GetLastError;
end;

Destructor TTgFileMapping<T>.Destroy;
begin
  if (Data <> nil) and bFreeData_ then
  begin
    UnmapViewOfFile(Data);
    Data := nil;
  end;

  if hMap_ <> 0 then
  begin
    CloseHandle(hMap_);
    hMap_ := 0;
  end;

  Inherited;
end;

function TTgFileMapping<T>.IsAvailable: Boolean;
begin
  Result := Data <> nil;
end;

end.
