Introduction
Co-operate library can be used to start another process, and then it provides a way to transfer data between processes.
Background
Co-operate library is to let 2 programs co-operate with each other. One program can start the other program, and then any one of them can transfer data to the other, and then one can detect whether the other program has exited.
I write this library because I want to allow my 2 programs to co-operate, like Photoshop and ImageReady do, that one image can be passed from Photoshop to Imageready to be edited continuously.
This library is also useful if you want to let your program co-operate with someone else's program.
Using the Code
This co-operate library provides a set of stdcall
APIs, to start process, to send data, to detect whether the other program exited, to set a callback function which will be called when data arrives from the other program.
There are no classes or complex types defined in the header file. This library can be used not only by Visual C++, but also by Visual Basic, Delphi, etc.
Interface Reference - coopframe.h
Type Definition
DECLARE_HANDLE(HCOOPSESSION);
typedef VOID (CALLBACK* COOPPROC)(LPCVOID pData, UINT nSize, LPVOID pParam);
API
HCOOPSESSION STDCALL GetCoopSession(COOPPROC fnCoopProc, LPVOID pParam);
HCOOPSESSION STDCALL StartCoopSession
(COOPPROC fnCoopProc, LPVOID pParam, LPCTSTR szPath, LPCVOID pData, UINT nSize);
VOID STDCALL SetCoopSessionProc
(HCOOPSESSION hCoopSession, COOPPROC fnCoopProc, LPVOID pParam);
BOOL STDCALL IsCoopSessionValid(HCOOPSESSION hCoopSession);
VOID STDCALL CloseCoopSession(HCOOPSESSION hCoopSession);
VOID STDCALL SendToCoopSession(HCOOPSESSION hCoopSession, LPCVOID pData, UINT nSize);
Steps of Co-operate
Step 1: Detect whether this program is started by co-operator
m_hCoopSession = GetCoopSession(CoopCallbackProc, param);
The return value of GetCoopSession()
is not NULL
if this program is started by another program with StartCoopSession()
. This step is necessary if this program is started by co-operator, or the call of StartCoopSession()
will be blocked for a long time.
The first argument is a callback function, and the second is a parameter, which will be passed back to the callback function when callback is called.
The callback, CoopCallbackProc()
will be called the first time before GetCoopSession()
returns, with the data which is passed into StartCoopSession()
in the other program.
Step 2: Start the other program if there is no session with co-operator
if(!IsCoopSessionValid(m_hCoopSession))
{
CloseCoopSession(m_hCoopSession);
m_hCoopSession = StartCoopSession
(CoopCallbackProc, param, "other_program.exe", pData, length_of_data);
}
If the session is NULL
or if the other program has exited, the IsCoopSessionValid()
will return FALSE
. Then, use StartCoopSession()
to start the other program and it will return the handle of session.
The data will be transferred to the newly started program's callback function, which is passed into GetCoopSession()
in the started program.
Step 3: Pass data to the other program if the session is still valid
if(IsCoopSessionValid(m_hCoopSession))
{
SendToCoopSession(m_hCoopSession, pData, length_of_data);
}
The data will be passed to the callback function of the other program.
Step 4: Process data's arrival
VOID CALLBACK CoopCallbackProc(LPCVOID pData, UINT nSize, LPVOID param)
{
}
When data arrives from the other program, this callback function will be called.
Step 5: Close session handle when program exits or stops to co-operate
CloseCoopSession(m_hCoopSession);
m_hCoopSession = NULL;
Technical Points
- I used
CreateProcess()
to create a new process. - I used
CreateFileMapping()
to share memory between processes. - I used
DuplicateHandle()
to pass process handle and event handle from one process to the other. - I used
GetProcessTimes()
to determine whether the other process has exited. - I used a thread to monitor event of data arrival.
Explanation of Visual Basic's Multi-Thread
When I was writing the demo program for Visual Basic, I encountered a problem that I could not do anything about in callback function, such as MsgBox
or CopyMemory
to an array. I tried to find out the problem for days, and finally I found that Multi-Thread caused the problem.
I create a new thread in 'Visual C++' to monitor event of data arrival, but this thread has no necessary context for 'current Visual Basic program', so within the callback function, we cannot use anything in Visual Basic.
There is a complex mechanism to build context for a new thread in Visual Basic, so I chose to use SendMessage()
to send the address to the main window to get the content of data.