www.pudn.com > mfc资源大全1.rar > atl_Conexe.shtml
ATL - Converting Connect Sample to a Local Server
Download the CONEXE example project.
The CONNECT sample included with Microsoft Visual C++ 5.0 is an example of how
to use connection points with ATL. The in-process server is implemented in connect.dll and
the client is a simple dialog based application called MDrive. It's intended to be an example of
using connection points within a single process boundary. However, the first thing you may
want to do with connection points is use them between different processes.
I couldn't find an example of how to do this so I had to improvise.
What follows is an example of how to convert the CONNECT sample to a local server.
First I converted the in-process server DLL to a server EXE. The fastest way to do this is
to create a new application using the ATL COM AppWizard. I called the new application
"Conexe" to differentiate it from the original project. The boilerplate code in conexe.cpp
for the new app is ready to use without modifcation. Retain the use of CoInitialize
in _tWinMain rather than CoInitializeEx.
Then I used the ClassView right click menu to create a new interface called IRandexe.
I then copied the IDL interface related lines over from the IRandom interface in CONNECT.
Finally, I just copied all the functions in the original Random.cpp and definitions in
Random.h to complete the new interface. The result is a new interface that works just
like IRandom, but with a new name and IID.
Also, I added this line to Stdafx.h:
#define _ATL_FREE_THREADED
Now for the really interesting parts. I tried quite a few threading designs
in creating this project and this is the only one that seems to work properly.
In the local server version I had to add a call to CoInitialize in the RandomSession thread. So each thread that's created via a
client request will get it's own private single threaded apartment. (It's not really
clear to me why the in-process version does not require this.)
DWORD WINAPI RandomSessionThreadEntry(void* pv)
{
// Need to call CoInitialize on this thread to create a single
// threaded apartment. If you don't do this you will get the
// "CoInitialize has not been called." error.
CoInitialize(NULL); // new line
CRandexe::RandomSessionData* pS = (CRandexe::RandomSessionData*)pv;
CRandexe* p = pS->pRandom;
while (WaitForSingleObject(pS->m_hEvent, 0) != WAIT_OBJECT_0)
p->Fire(pS->m_nID);
CoUninitialize(); // new line
return 0;
}
The next problem is related to interface marshalling between threads. The
local server version won't work when events are fired since the interface
was marshalled by COM on a different thread. Now we get to use those really
long API calls, CoMarshalInterThreadInterfaceInStream and
CoGetInterfaceAndReleaseStream.
// broadcast to all the objects
HRESULT CRandexe::Fire(long nID)
{
IConnectionPointImpl
The client MDrive project was simply copied over to a new subdirectory and only modified slightly to
use the new server. Multiple instances of MDrive can be launched and they all have access to the
Conexe.exe local server. One thing to note is that the local server version is a lot slower
as seen by the pixel drawing rate in MDrive. I'm fairly new to COM and
ATL programming, and if I've made any errors please let me know.
I'd really like to know if I've created needless inefficiencies with the constant inter-thread
interface marshalling; if there's a better way, tell me. I also created a version of this
project that uses IUnknown instead of IDispatch and it also seems to work correctly.
Last updated: 11 June 1998
| Goto HomePage |
|
Contact me: zafir@home.com
|