Sharing data array between two applications in Delphi Sharing data array between two applications in Delphi arrays arrays

Sharing data array between two applications in Delphi


Scratched my head thinking of what a short-but-complete example of sharing memory between two applications might be. The only option is a console application, GUI applications require a minimum of 3 files (DPR + PAS + DFM). So I cooked up a small example where one integers array is shared using a memory mapped file (backed by the page file so I don't need to have a phisical file on disk for this to work). The console application responds to 3 commands:

  • EXIT
  • SET NUM VALUE Changes the value at index NUM in the array to VALUE
  • DUMP NUM displays the value in the array at index NUM
  • DUMP ALL displays the whole array

Of course, the command processing code takes up about 80% of the whole application. To test this compile the following console application, find the executable and start it twice. Go to the first window and enter:

SET 1 100SET 2 50

Go to the second console and enter this:

DUMP 1DUMP 2DUMP 3SET 1 150

Go to the first console and enter this:

DUMP 1

There you have it, you've just witnessed sharing memory between two applications.

program Project2;{$APPTYPE CONSOLE}uses  SysUtils, Windows, Classes;type  TSharedArray = array[0..10] of Integer;  PSharedArray = ^TSharedArray;var  hFileMapping: THandle; // Mapping handle obtained using CreateFileMapping  SharedArray: PSharedArray; // Pointer to the shared array  cmd, s: string;  num, value, i: Integer;  L_CMD: TStringList;function ReadNextCommand: string;begin  WriteLn('Please enter command (one of EXIT, SET NUM VALUE, DUMP NUM, DUMP ALL)');  WriteLn;  ReadLn(Result);end;begin  try    hFileMapping := CreateFileMapping(0, nil, PAGE_READWRITE, 0, SizeOf(TSharedArray), '{C616DDE6-23E2-425C-B871-9E0DA54D96DF}');    if hFileMapping = 0 then      RaiseLastOSError    else      try        SharedArray := MapViewOfFile(hFileMapping, FILE_MAP_READ or FILE_MAP_WRITE, 0, 0, SizeOf(TSharedArray));        if SharedArray = nil then          RaiseLastOSError        else          try            WriteLn('Connected to the shared view of the file.');            cmd := ReadNextCommand;            while UpperCase(cmd) <> 'EXIT' do            begin              L_CMD := TStringList.Create;              try                L_CMD.DelimitedText := cmd;                for i:=0 to L_CMD.Count-1 do                  L_CMD[i] := UpperCase(L_CMD[i]);                if (L_CMD.Count = 2) and (L_CMD[0] = 'DUMP') and TryStrToInt(L_CMD[1], num) then                  WriteLn('SharedArray[', num, ']=', SharedArray^[num])                else if (L_CMD.Count = 2) and (L_CMD[0] = 'DUMP') and (L_CMD[1] = 'ALL') then                  begin                    for i:= Low(SharedArray^) to High(SharedArray^) do                      WriteLn('SharedArray[', i, ']=', SharedArray^[i]);                  end                else if (L_CMD.Count = 3) and (L_CMD[0] = 'SET') and TryStrToInt(L_CMD[1], num) and TryStrToInt(L_CMD[2], value) then                  begin                    SharedArray^[num] := Value;                    WriteLn('SharedArray[', num, ']=', SharedArray^[num]);                  end                else                   WriteLn('Error processing command: ' + cmd);              finally L_CMD.Free;              end;              // Requst next command              cmd := ReadNextCommand;            end;          finally UnmapViewOfFile(SharedArray);          end;      finally CloseHandle(hFileMapping);      end;  except    on E: Exception do      Writeln(E.ClassName, ': ', E.Message);  end;end.


A Named File Mapping would be the easiest solution, here is some short example code.In this sample there is a main program that writes some data and reader(s) that only read from it.

Main:

type  TSharedData = record    Handle: THandle;  end;  PSharedData = ^TSharedData;const  BUF_SIZE = 256;var  SharedData: PSharedData;  hFileMapping: THandle;  // Don't forget to close when you're donefunction CreateNamedFileMapping(const Name: String): THandle;begin  Result := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0,    BUF_SIZE, PChar(Name));  Win32Check(Result > 0);  SharedData := MapViewOfFile(Result, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);  Win32Check(Assigned(SharedData));end;procedure TForm1.Button1Click(Sender: TObject);begin  hFileMapping := CreateNamedFileMapping('MySharedMemory');  Win32Check(hFileMapping > 0);  SharedData^.Handle := CreateHiddenWindow;end;

reader:

var  hMapFile: THandle;   // Don't forget to closefunction GetSharedData: PSharedData;begin  hMapFile := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'MySharedMemory');  Win32Check(hMapFile > 0);  Result := MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);  Win32Check(Assigned(Result));end;