Level Extreme platform
Subscription
Corporate profile
Products & Services
Support
Legal
Français
VFP MTDLL COM object -- persistence questions
Message
General information
Forum:
Visual FoxPro
Category:
COM/DCOM and OLE Automation
Miscellaneous
Thread ID:
01061515
Message ID:
01062867
Views:
41
This message has been marked as the solution to the initial question of the thread.
Hi Mark,

Processes (or tasks as they were called years ago <g>) run in its own memory space. To read memory from a different process, you don't only have to call a dedicated API function, but you also need the debug privilege which, by default, only Administrators have.

Threads are different. All threads of a process run in the same memory space as the process. There's no way to protect memory from one thread against the other. Even TLS doesn't separate memory, it merely maintains a list of memory pointers and thread ids to return thread specific pointers. That means, no matter what address you have, another thread would be able to read it.

You could use any of the various memory functions like GlobalAlloc, LocalAlloc or HeapAlloc. Any of these functions returns process specific memory from the same heap. The difference is more in some capabilities provided by the set of functions, not the memory itself. The difference was only relevant for 16-bit Windows. In other words, you wouldn't need shared memory with a DLL, you could use regular memory like this:
	Local lnProcessHeap, lnAddress
	Declare Long GetProcessHeap in Win32API
	Declare Long HeapAlloc in Win32API Long, Long, Long
	lnProcessHeap = GetProcessHeap()
	If m.lnProcessHeap == 0
		lnAddress = 0
	Else
		lnAddress = HeapAlloc( m.lnProcessHeap, 0, m.tnBytesToAllocate )
	EndIf 
If you can share lnAddress across all threads, any thread can use SYS(2600) to access this memory. The problem, though, is sharing the address. In a C++ DLL you would simply use a static pointer and it would be stored in a single memory location known to all threads executing code in the DLL. In VFP we don't have something like this, AFAIK (one might have luck with the _VFP reference, or so, to find proeprties stored in the global DLL memory area and not in the TLS section).

That's where shared nemory joins the party. Usually, shared memory is used in inter-process communication. It's memory that is available to all processes that open a handle to the shared memory object. Because in VFP we can't create DLL wide variables, for us, each thread is much like a process.

You can assign a name to shared memory. You use this name to open a handle to the memory object from any thread or process. One difficulty, though, is that the name is global to all processes running on a machine. That means, to make it process specific, you should add _VFP.ProcessID to the name. Otherwise multiple instances of your application would share the same memory block.

What makes shared or named memory hard to discover in the API documentation is that it's called "FileMapping", because you can use the same API call to map a file in memory. To create a file mapping, you use code like this:
	Declare Long CreateFileMapping in Win32API Long, String, Long, Long, Long, String
	Declare Long MapViewOfFile in Win32API Long, Long, Long, Long, Long
	Declare Long GetLastError in Win32API
	lnHandle = CreateFileMapping( -1, NULL, 4, 0, lnSize, "Local\MyMemory" )
	If lnHandle > 0
		lnLastError = GetLastError()
		llNew = (m.lnLastError == 0)
		lnMemory = MapViewOfFile( lnHandle, 6, 0, 0, lnSize )
		If lnMemory == 0
			Declare CloseHandle in Win32API Long
			CloseHandle(lnHandle)
		EndIf 
	EndIf 
A few words about the parameters of CreateFileMapping. The second parameter is the security descriptor. If you pass a NULL, this means that the current user only can access this memory mapping. For in-process communication that's just fine. The third parameter is 4, indicating read/write access to memory. 0 and lnSize belong together and indicate the size of the memory block. Just using the second parameter gives you 4 GB which should be enough. However, you should pick this value carefully. You can't change it after the memory object has been created. Also, all threads trying to open the shared memory object have to pass the same size, otherwise the call would fail.

Name is important. This name identifies the block of memory to other threads. On Windows 2000 and higher, you should precede this with "Local\". This is important on Terminal Services. With "Local\", the named memory is only available to the current user, with "Global\" it's available to all terminal server sessions on the machine (if you ever want to share data across all TS sessions, that's how). On NT4, however, this syntax causes an error. Here you must not use this suffix. OS() helps you to distiguish the operating system if you still have to support NT4.

Using GetLastError() you can find out if you were the one creating the object, or if you opened an existing mapping. This can be important if you need to initialize memory.

CreateFileMapping just provides the object. Now you need to allocate memory. That's what MapViewOfFile does. 6 again means read and write access. Now you can use SYS(2600,m.lnMemory) to access this shared memory.

When you are done, you have to close the object. In a multi-threading environment this is even more important, because Windows otherwise releases resources not until the process terminates. In case of a web application this means, you would increase resource usage until you restart the web server. To close a shared memory object, you use:
	Declare UnmapViewOfFile in Win32API Long
	Declare CloseHandle in Win32API Long
	UnmapViewOfFile( lnMemory)
	CloseHandle(lnHandle)
--
Christof
Previous
Next
Reply
Map
View

Click here to load this message in the networking platform