Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Passing data between apps

Status
Not open for further replies.

KempCGDR

Programmer
Jan 10, 2003
445
GB
Hi, I'm working on a program (actually set of programs) where copies need to send large amounts of data between themselves. I've decided that it'd probably be best to do this via shared memory for various reasons. I want to set it up so I can do this:

App1 and App2

App1 creates a chunk of shared memory, puts the data in it and sends a message to App2 with the address of the memory. App2 grabs the data and does whatever with it.

Now, I can do the messages fine, I've already got other parts working that rely on them. However, I have no idea how to go about doing the shared memory thing. Does anyone have any sample code or helpful links?

Thanks.
 
1) You can marshall your pointers using WM_COPYDATA (not really advisable for large chunks of data but fast to implement).

2) You can use mapped files. Take a look to CreateFileMapping, OpenFileMapping, MapViewOfFile and/or do a FTP search for MMAPFILE.ZIP (it is a ready to run filemapper delphi class with demo written for David Spies).

3) Pipes and sockets are possible tools too, but I beleve not the best ones in your case.

HTH.
buho (A).

 
The file mapping option looks promising, will try it out and get back to you.
 
Is this even vaguely right? I'm creating a file map (without the file, so just a memory map) like so:

Code:
   MemHandle := CreateFileMapping(
      ($FFFFFFFF),	// Use memory with no file
      nil,	// don't pass any security attributes
      PAGE_READWRITE,	// allow full access
      0,	// high-order 32 bits of object size
      (length(memText.Text) * 8),	// low-order 32 bits of object size
      PChar(memName) 	// name of file-mapping object
   );

   MapViewOfFile(
      MemHandle,	// Value returned above
      FILE_MAP_WRITE ,	// Full access (read as well as write)
      0,	// high-order 32 bits of file offset
      0,	// low-order 32 bits of file offset
      (length(memText.Text) * 8) 	// number of bytes to map
   );

The first function should create the area of memory to share, the second should allow my application to see it. Assume that memText.Text and memName are strings.

Then assuming that is right, I'm going to dump the contents of memText.Text in the memory and pass a message to the other app (using PostMessage) giving it the handle of the memory and its size and do the MapViewOfFile from there with the same parameters to read the string out.

If what I've said up to here won't kill my machine then I have a quick question : how do I read write that area of memory? I assume I could create a pointer and make it point to there and then use that, but I'm not too sure of the specifics of pointers.

Thanks in advance for any help.
 
1) About MapViewOfFile
MapViewOfFile of file returns a pointer to the memory space assigned to the file:
Code:
var
  S :AnsiString;
MapPointer := MapViewOfFile(...)
// Check for MapPointer <> nil
S := memText.Text;
Move(S[1], MapPointer^, Length(S));
will copy S into the file memory.

2) In the &quot;Primary app&quot; (the one which creates de mapping):
Use CreateFileMapping(,,,,,'MyMappedFile') and MapViewOfFile to get the pointer (as you are doing now, but keeping the pointer).

3) In the &quot;secondary app&quot;:
Use CreateFileMapping(,,,,,'MyMappedFile') -same name- or OpenFileMapping(,,,'MyMappedFile') and MapViewOfFile again.
Now the secondary app have a pointer to the same address space. No need to send pointers between apps.

4) Using:
Use the pointers to write/read the memory block, you can do anything you use to do with pointers (other than Dispose and FreeMem :). Avoid using ReadFile/WriteFile if you have a handle to a disk mapped file, Win9x will fail mixing map views and Read/Write on mapped disk files.

5) On closing mapped files:
The map handlers/pointers are reference-counted but do NOT close the file handle before unmapping the view. The right order is UnmapViewOfFile, CloseHandle. Closing the handle and keeping the pointer will cause problems in NT (cfr: Cohen and Woodring; &quot;Win32 Multithread Programming&quot;; O'Reilly; First Edition, p. 132). On the other way, being reference-counted you can unmap and close in one app and continue working with the object in the other one.

6) Synchronization and debug:
Probably you will not need interprocess synchronization other than the windows messages you are sending between apps. If Murphy Law pops, may be a mutex approach will be needed. With more than 2 apps the mutex is advisable (or a very well crafted messages protocol).

For debug purposes I use to work with a disk file, so i can have an eye on the data Im passing. After debugging I use to switch to memory-only files.

buho (A).


 
According to the help files, MapFileOfFile returns Void (ie nothing) and simply gives you access rights to the designated area of the map. CreateFileMapping returns a pointer to the start of the memory area.

Anyway, I'll look through the rest and see if I can patch something together.
 
With all due respect, you are wrong in both points. The SDK and D5 windows.pas file clearly states MapViewOfFile returning a pointer and CreateFileMapping returning a handle.

1) MapViewOfFile:

From the SDK:
Code:
[COLOR=red][b]LPVOID[/b][/color] MapViewOfFile(
  HANDLE hFileMappingObject,   // handle to file-mapping object
  DWORD dwDesiredAccess,       // access mode
  DWORD dwFileOffsetHigh,      // high-order DWORD of offset
  DWORD dwFileOffsetLow,       // low-order DWORD of offset
  SIZE_T dwNumberOfBytesToMap  // number of bytes to map
);

&quot;Return Values
If the function succeeds, the return value is the starting address of the mapped view.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.&quot;


It is LPVOID --> pointer in Delphi parlance, not VOID (nothing).

From D5 windows.pas:
Code:
function MapViewOfFile(
  hFileMappingObject: THandle; 
  dwDesiredAccess: DWORD;
  dwFileOffsetHigh, 
  dwFileOffsetLow, 
  dwNumberOfBytesToMap: DWORD): [COLOR=red][b]Pointer[/b][/color]; stdcall;

2) CreateFileMapping:

From the SDK:
Code:
[COLOR=red][b]HANDLE[/b][/color] CreateFileMapping(
  HANDLE hFile,                       // handle to file
  LPSECURITY_ATTRIBUTES lpAttributes, // security
  DWORD flProtect,                    // protection
  DWORD dwMaximumSizeHigh,            // high-order DWORD of size
  DWORD dwMaximumSizeLow,             // low-order DWORD of size
  LPCTSTR lpName                      // object name
);

&quot;If the function succeeds, the return value is a handle to the file-mapping object. If the object existed before the function call, the function returns a handle to the existing object (with its current size, not the specified size) and GetLastError returns ERROR_ALREADY_EXISTS.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.&quot;


From D5 windows.pas:
Code:
function CreateFileMappingA(hFile: THandle;
  lpFileMappingAttributes: PSecurityAttributes;
  flProtect, 
  dwMaximumSizeHigh, 
  dwMaximumSizeLow: DWORD; 
  lpName: PAnsiChar): [COLOR=red][b]THandle[/b][/color]; stdcall;
[code][/i]

3) How to use both:

var
    ffoFileHandle : THandle;
    ffoMaphandle  : THandle;
    ffoMapPointer : PChar;
    // I'm assigning the mapped mem to a PChar, only to
    // show the method versatility.
begin
    ffoFileHandle := CreateFile('FFTEST',
                                GENERIC_READ OR GENERIC_WRITE,
                                FILE_SHARE_READ OR FILE_SHARE_WRITE,
                                nil,
                                CREATE_ALWAYS,
                                FILE_FLAG_RANDOM_ACCESS,
                                0);
    if ffoFileHandle <> INVALID_HANDLE_VALUE
      then
        begin
          ffoMapHandle := CreateFileMapping(ffoFileHandle,
                                            nil,
                                            PAGE_READWRITE,
                                            0, 2 * 1024,
                                            'FFTEST');
          if ffoMapHandle <> 0 // Warning: zero
            then ffoMapPointer := MapViewOfFile(ffoMapHandle,
                                                FILE_MAP_WRITE,
                                                0, 0,
                                                0);
        end;
    // We have a PChar pointer to the mapped mem, so
    // lets use StrCopy.
    if ffoMapPointer <> nil
      then StrCopy(ffoMapPointer, PChar('Hello, my mapped file'));
    UnmapViewOfFile(ffoMapPointer);
    CloseHandle(ffoFileHandle);
    CloseHandle(ffoMapHandle);
end;

Now take a look at the disk file FFTEST.

buho (A).
 
Ah, k, why must they put void in the name of a data type that means something?

I'll keep working on this one and get back.
 
Oh... well... C, you know... :)

buho (A).



 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top