This is a mirror of official site: http://jasper-net.blogspot.com/

Use Named Pipes and Shared Memory for inter process communication with a child process or two

| Tuesday, April 13, 2010
I wanted to inject some very low impact code that would run in any “parent” process, like Notepad or Excel or Visual Studio. I wanted to have some User Interface for the data that my injected code gathered about the parent process, and that would work best in a different “child” process, preferably using WPF.

In the old days, I could call a COM server to handle the job. A DLL server would be in process, but it could be made out of process by making it a COM+ application (see Blogs get 300 hits per hour: Visual FoxPro can count. and Create multiple threads from within your application).

.Net Remoting seemed to be a little heavyweight for Parent->Child process communication.

About 5 years ago, I wrote this: Use Named Pipes to communicate between processes or machines, so I thought I’d use a combination of Named Pipes and Shared Memory. Luckily .Net 3.5 added support for Named Pipes making the child process pretty simple.

Pipes could be used to send messages, and the lion’s share of data movement could be in the Shared memory.

Synchronization and lifetime management are a little tedious. We want the parent process to continue optionally if the child process terminates, but we want the child to terminate automatically when the parent terminates for any reason. Similarly, the child process should terminate if the parent has gone.

This sample shows a parent process in C++ and 2 child processes in C# and VB. The parent spins off a thread to use to service incoming requests from the children. Events are used to synchronize communication. A timer in each child process fires off requests to the parent.

I was using Visual Studio 2010: you can use VS 2008, but you’ll have to adjust for some of the new features I use, especially in the VB code.

Start Visual Studio. File->New->Project->C++ Win32 Project->Windows Application. In the wizard, Click Add common header files for ATL Now hit F5 to build and see it execute: there’s a window and a couple menus.

Now add a second EXE project to your solution: choose File->Add->New Project->VB WPF Application.  (Repeat to add a 3rd project for C# !)

Fiddle with the Project->Properties->Compile->Build Output path so it builds into the same folder as the parent exe (for me, it was” ..\Debug\”)

Paste in the VB code below into MainWindow.Xaml.Vb

Somewhere inside the _tWinMain of your CPP project, add these 2 lines to instantiate a class that calls the WpfApplication as a child process, with a shared memory size of 2048 (make sure to change the name of the EXE to match your VB and C# EXEs):

   CreateChildProcess opCreateChildProcessCS(_T("NamedPipesCS.exe"),2048, 1);
   CreateChildProcess opCreateChildProcessVB(_T("NamedPipesVB.exe"),2048, 2);


Paste the CPP code below before the _tWinMain. F5 will show both processes launched. You can alt-tab between the 2: they behave like independent processes. Try terminating one of them.
If you uncomment the MsgBox, then hit F5, you can actually use VS to attach to a child process before it does too much. Try attaching to all 3!  

See also:

<C++ Code>

// CreateChildProcess : class in parent process to instantiate and communicate with a child process
// usage:    CreateChildProcess opCreateChildProcess(_T("WpfApplication1.exe"),2048);

class CreateChildProcess
{
   HANDLE m_hChildProcess;// handle to the child process we create
   HANDLE m_hNamedPipe;    // handle to the named pipe the paren process creates
   HANDLE m_hEvent;
   HANDLE m_hThread; // thread in parent process to communicate with child
   LPVOID m_pvMappedSection;
   DWORD m_cbSharedMem;

public:

   CreateChildProcess(TCHAR* szChildExeFileName,DWORD cbSharedMemSize, int ChildNo )
   {
       m_cbSharedMem = cbSharedMemSize;
       TCHAR szPipeName[1000];
       TCHAR szEventName[1000];
       swprintf_s(szPipeName, L"Pipe%d_%d", ChildNo, GetCurrentProcessId()); //make the names unique per child and per our (parent) process
       swprintf_s(szEventName,L"Event%d_%d", ChildNo, GetCurrentProcessId()); //
     
       SECURITY_ATTRIBUTES SecurityAttributes = {
           sizeof( SECURITY_ATTRIBUTES ),  // nLength
           NULL,                           // lpSecurityDescriptor. NULL = default for calling process
           TRUE                            // bInheritHandle
       };

Read more: Calvin Hsia's WebLog

Posted via email from jasper22's posterous

0 comments: