{ 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.
//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.