Download the Step 5 Files - 30.9 KB
Introduction
Welcome to Step 5 of our DCOM tutorial. In this series, I will strip the mystique, the headache, and confusion from DCOM by giving you a comprehensive tutorial with a straightforward example. OK, no promises -- but I will give it a good try.
If you want to follow along with this tutorial and add code and use the Visual C++ Wizards as we go along, that's great. In fact, I very very highly recommend that, because otherwise this tutorial is a big waste of electronic ink (?). However, I follow along exactly with the tutorial myself, as I write it, and develop the code and use the Visual C++ wizards just as I say you should. The screenshots, in fact, are from my development of the files for each step! To download this already-developed code to compare with your own, simply click the 'Download the Step n Files - n KB" links at the top of each step. There's also an archive of the files for all the steps at the Questions and Answers page for this tutorial. I still recommend that you follow along with us as we go; this way, you can learn while you code. If you ever have problems along the way with this tutorial, feel free to:
Connection Points Demystified
Before we plunge in with Step 5 of our tutorial, let's just take a moment for me to rip the shrouds of mystery off of Connection Points. Figure 1 below shows a generic scenario which is true for COM, DCOM, and even function call backs, for goodness' sake.
Figure 1. A source and a sink.
This involves two objects, a "source" and a "sink". Think of the "source" like the water faucet of the kitchen sink at home. You turn a handle, and stuff comes out of it (hopefully water). Where does it go? If nothing's backed up, this water flows down into the bottom and goes into the drain (which can be thought of as the "sink"). OK, so things flow from the source, to the sink. In the kitchen sink analogy above, this is water. However, I've never seen a computer network system run with water flowing across the wires, so obviously something else is at work in DCOM.
In DCOM, there is a "client," somewhere on the network, and there is a "server," also somewhere on the network. Without the use of connection points, things flow only one way: method calls replace our water, the client replaces our faucet, and the server replaces the drain. This is way oversimplifying things, but the user "turns a handle" (that is, clicks a button, for example), and "stuff" (that is, method calls) "comes out of" the client. This "stuff that comes out" then "flows" over the network using DCOM. These calls "flow" to the server, which then collects them and acts like the "drain", or our sink. Here's Figure 2, which is almost exactly like Figure 1, but puts the client in place of the "source" and the server in place of the "sink," with the network in between:
Figure 2. Our client and server as the source and the sink.
OK, so now we have method calls flowing like water; wonderful. However, when the client calls methods, the server does all kinds of things that might be interesting to clients. So the server fires events all over the place. If our client doesn't care if the server fires events, it will just ignore them. However, if it cares, it will Advise() the server. Then the source-sink relationship of Figure 2 can be thought of in reverse:
Figure 3. The reverse of Figure 2.
Connection points come in when you have the following happening:
- The client is the source of a method call,
- The server sinks (that is, acts as the sink for) the method call.
- An "event call" comes out of the now-server-as-source.
- The client sinks the event call and does something.
As you can see, this is a round-trip. A method call goes from the client to the server, and then an event call goes from the server, to the client, as seen in Figure 4.
Figure 4. A round-trip.
The Advise() step is done before item number 1 above, and the Unadvise() step (where the client goes back to being aloof) happens after item number 4. The points of contact on both the client and server and the Advise()ing and Unadvise()ing that happens all together form...
A CONNECTION POINT!!
Whew... what a revelation... Let's start Step 5 before I get too carried away...
Step 5: Add the OnSayHello Event to the Event Source Interface DHelloWorldEvents
Let's plunge in, shall we? To add an event to the source, it's really, really easy. Just use the Visual C++ Wizards! Open up ClassView, and right-click the DHelloWorldEvents icon, and then click Add Method. The Add Method to Interface dialog box appears. Type OnSayHello in the Method Name box, and type [in] BSTR bstrHost in the Parameters box, as shown in Figure 5, below.
Figure 5. Adding the OnSayHello() event to the DHelloWorldEvents event interface.
Once you're done, click OK. ClassView should resemble Figure 6 below. Now click FileView, and find the HelloServ.idl file, under the Source Files folder. Right-click that baby, and then choose Compile. Watch the compiler work away in the Output window, and wait until the build is complete.

Figure 6. ClassView after adding the OnSayHello event.
Once the build has been finished, click on ClassView. Right-click the CHelloWorld class, and then click Implement Connection Point. The Implement Connection Point dialog box appears. If you haven't compiled the IDL file yet like I told you to, Visual C++ will prompt you to do so. Figure 7, below, shows you how to select that you want to make the server able to fire off its OnSayHello event:
Figure 7. Specifying that we want to implement Connection Points for the DHelloWorldEvents event interface.
When everything looks like Figure 7, click OK. The Visual C++ IDE will now generate all the server-side code you need for Connection Points. Each time you change an event in the DHelloWorldEvents event interface, you need to do the (1) compile the IDL, (2) right-click CHelloWorld and choose Implement Connection Point, (3) check the box by DHelloWorldEvents, and (4) click OK steps.
Notes From the Rear
The final part of Step 5 which we have to take care of is firing the event. Remember, we declared the OnSayHello() event in the IDL file as:
HRESULT OnSayHello(BSTR bstrHost);
Listing 1. The declaration of the OnSayHello() event.
To fire the event from any CHelloWorld member function, just call Fire_OnSayHello(). It's a member function of a new base class, CProxyDHelloWorldEvents< > that the Implement Connection Points dialog box just added for us.
To this end, let's add code to the CHelloWorld::SayHello() function to fire the event to the client:
STDMETHODIMP CHelloWorld::SayHello()
{
USES_CONVERSION;
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerName(szComputerName, &dwSize))
return E_FAIL;
Fire_OnSayHello(T2OLE(szComputerName));
return S_OK;
}Listing 2. Code to add to finish the CHelloWorld::SayHello() member function.
That's it! We're finished with Step 5. Click Next to go on to Step 6, or click Back to step back to Step 4 if you're browsing through the tutorial. If you have any questions, try clicking on Questions and Answers to go to the page with the good stuff, and then e-mail me at brian@harttechservices.com if you're still stuck.
<< Back | Next >>
Questions and Answers
| You must Sign In to use this message board. |
|
|
 |
|
|
 |
|
 |
Dear Readers: Thank you so much for reading my DCOM tutorial. Can you believe I wrote it in August 2000 and I still get messages and questions? Gosh, now that's staying power And keep those questions coming!
The Code Downloads Are Not Meant to Be Compiled As Is! They Are There So You Can See What I am Doing ONLY
I do very much enjoy answering your questions, and I am here to help. If I may ask a small favor though. It seems that the usual practice for people is to skip straight to Step 6 of the tutorial, and then download the code, and then skip to Step 7, and then download the code. Then you try to compile it and, lo and behold, Question Time!
If the Downloaded Code Works, Great! If Not, Try This Before Asking A Question:
May I please make a suggestion, and that is, if you do the above and have problems, perhaps it might be better to simply go to Step 1 [^] and simply follow along with me in Visual C++ as you go from Step to Step.
This is also because there are slight differences between Visual C++ Service Pack versions and the one I used to write this stuff. If you follow along, you're sure to generate code with the Wizards etc. that is compatible with your setup. Remember to do ALL the steps, in order, 1 through 7. Thank you!
Sincerely Yours, Brian Hart Department of Physics and Astronomy University of California, Irvine
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
After using the implement connection point wizard, I had the same problem as others in that CONNECTION_POINT_ENTRY(DIID_DHelloWorldEvents) was incorrectly generated as CONNECTION_POINT_ENTRY(IID_DHelloWorldEvents)
I also discovered that the CProxyDHelloWorldEvents was created but with no Fire_OnSayHello method inside.
Running the connection point implementation wizard a second time seems to have solved the problem.
Hmmm, I think I will stick to Linux for my upcoming project until the windows tools have reached a more mature level of reliability for commercial use.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Kza Wah wrote: Hmmm, I think I will stick to Linux for my upcoming project until the windows tools have reached a more mature level of reliability for commercial use.
Huh. when will *that* happen?
Sincerely Yours, Brian Hart Department of Physics and Astronomy University of California, Irvine
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Kza Wah wrote: After using the implement connection point wizard, I had the same problem as others in that CONNECTION_POINT_ENTRY(DIID_DHelloWorldEvents) was incorrectly generated as CONNECTION_POINT_ENTRY(IID_DHelloWorldEvents)
Yeah its a known issue... I saw this COM/ATL book by Andrew Troelsen. It should cover the basics...
Kza Wah wrote: I also discovered that the CProxyDHelloWorldEvents was created but with no Fire_OnSayHello method inside.
Running the connection point implementation wizard a second time seems to have solved the problem.
Again from the same book, you should have saved the project atleast once before implementing connection points...
think fast, be brave and dont stop.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
For some odd reason, Micro$oft has chosen not to include the xmldom.idl in the Core SDK (from the Platform SDK distribution). It is odd, since the included msxml.idl file _does_ reference it, giving the infamous error "xmldom.idl is missing".
The solution to this is to install the Internet Explorer SDK (from the Platform SDK distribution) because this is where the xmldom.idl file is.
Nice eh?
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
|
 |
|
 |
VC++ 6.0 SP 5 produced an error on this line because it doesn't know what T2OLE is.
Fire_OnSayHello(T2OLE(szComputerName));
so I did this instead:
wchar_t tbuf[MAX_COMPUTERNAME_LENGTH + 1]; mbstowcs(tbuf,szComputerName,MAX_COMPUTERNAME_LENGTH + 1); Fire_OnSayHello(tbuf);
|
| Sign In·View Thread·PermaLink | 5.00/5 |
|
|
|
 |
|
 |
Did you used the macro USES_CONVERSION before calling T2OLE???? as it's fine on my machine(am also using MSVC 6 SP 5 only). If yes, then I am sorry, otehrwise...that's it 
Omkar Shukla HCL-Tech-Europe
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Nope USE_CONVERSION, doesn't do the thing. I also have to use
wchar_t tbuf[MAX_PATH + 1]; mbstowcs(tbuf,strExportFolder,MAX_PATH + 1);
Adrian
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
How to use USE_CONVERSION ,can you get a sample to me? thanks, I also had to use mbstowcs! So i want know how to use USE_CONVERSION!
thanks again?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
sanangel wrote: How to use USE_CONVERSION ,can you get a sample to me? thanks, I also had to use mbstowcs! So i want know how to use USE_CONVERSION!
Look in Listing 2 above (at http://www.codeproject.com/com/hellotutorial5.asp).
Sincerely Yours, Brian Hart Department of Physics and Astronomy University of California, Irvine
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
When I try to do the compile in this step I get an error: C:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\msxml.idl(52) : fatal error C1083: Cannot open include file: 'xmldom.idl': No such file or directory
Where do I get this file?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
elderdo wrote: When I try to do the compile in this step I get an error: C:\Program Files\Microsoft Visual Studio\VC98\INCLUDE\msxml.idl(52) : fatal error C1083: Cannot open include file: 'xmldom.idl': No such file or directory
Where do I get this file?
I couldn't locate a xmldom.idl file on my computer, and I have the latest VC6 installed. Make sure your copy of VC6 is updated with the latest Service Packs. The latest for VC6 is the "Visual Studio 6.0 Service Pack 5." Perhaps this may change out the file for the latest version. You can find them at the following link:
Visual Studio 6.0 Service Pack 5.0 Download[^]
If that doesn't work, remove the line
#include 'msxml.idl'
from the HelloServ.idl file and see if that works.
Sincerely Yours, Brian Hart Department of Physics and Astronomy University of California, Irvine
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
I found the files in a .Net include directory. So, I copied them to MSVC++'s include directory and it compiled!
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
|
 |
|
 |
what do i do whith the fire event
Fire_OnSayHello(T2OLE(szComputerName));
where should i implement this method ?
|
| Sign In·View Thread·PermaLink | 1.00/5 |
|
|
|
 |
|
|
 |
|
 |
when i implement Connection Points (i.g. DHelloWorldEvents in this case) the wizard creates the entry in the HelloWorld.h
CONNECTION_POINT_ENTRY(IID_DHalloWeltEvents)
when i try to compile that i get an error that IID_DHalloWeltEvents is unknown an thats correct because it should be DIID_DHalloWeltEvents
CONNECTION_POINT_ENTRY(DIID_DHalloWeltEvents)
when i add the "D" everything gets compiled and works fine
is that a bug in VC++ or am i doing something wrong
i use vc++ 6.0 sp5 with w2k
thanks Ben
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Sorry, I can't answer to your question.
I will only say that I have exactly the same problem. I made the same changes (IID to DIID) and it works.
Martin
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
It seems to be a bug in VC++: if you implement connection points (that is right-click on "CHelloWorld", select "Implement Connection Point..." etc.) again, the wizard seems to be OK this time and adds a new, correct entry just below the wrong one, so you have:
... BEGIN_CONNECTION_POINT_MAP(CHelloWorld) CONNECTION_POINT_ENTRY(IID_DHelloWorldEvents) CONNECTION_POINT_ENTRY(DIID_DHelloWorldEvents) END_CONNECTION_POINT_MAP() ...
Of course, the first entry has to be deleted manually anyway. --Horia
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Benjamin Danzer wrote: when i try to compile that i get an error that IID_DHalloWeltEvents is unknown an thats correct because it should be DIID_DHalloWeltEvents
DIID_DHalloWeltEvents is the correct identifier -- it's due to a stupid (!) bug in VC++ not you...
So the solution is merely to do a 'Replace' to change the ID...
Sincerely Yours, Brian Hart Department of Physics and Astronomy University of California, Irvine
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
 | Yo, Yo!  Philip Patrick | 21:55 2 Jun '02 |
|
 |
Thanx for great articles! Really, made me quick introduction and startup to DCOM, unlike all those books where too much theory and less practice. I'm not saying theory is bad, but theory is nothing without a real work.
So thanx again
Philip Patrick Web-site: www.stpworks.com "Two beer or not two beer?" Shakesbeer
Need Web-based database administrator? You already have it!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Philip Patrick wrote: Thanx for great articles! Really, made me quick introduction and startup to DCOM, unlike all those books where too much theory and less practice. I'm not saying theory is bad, but theory is nothing without a real work.
So thanx again
No problem Glad to be of help. This was the goal of my writing this tutorial -- enough theory, let's actually sit down at the computer and get some code done.
Sincerely Yours, Brian Hart Department of Physics and Astronomy University of California, Irvine
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
What would happen in the Sayhello method, started a thread with a beginthredex call, and passed this as the param. 5 seconds later the thread fired the Fire_SayHello connection point?
I suspect this would work, but could get into trouble if the com oject was pooled?
Giles
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|