Friday, November 28, 2008

Client Side


The client presented in the first installment of this series has the benefits of clarity and compactness. However, it contains little error-checking code and that makes it insufficient in a real application. Let's review that code, however, because it is so simple and it shows the exact steps that you must take to create a successful client:


void main()

{

HRESULT hr; // COM error code

IBeepDllObj *IBeep; // pointer to interface

hr = CoInitialize(0); // initialize COM

if (SUCCEEDED(hr)) // macro to check for success

{

hr = CoCreateInstance(

clsid,// COM class id

NULL, // outer unknown

CLSCTX_INPROC_SERVER, // server INFO

iid, // interface id

(void**)&IBeep ); // pointer to interface

if (SUCCEEDED(hr))

{

hr = IBeep-Beep(800); // call method

hr = IBeep-Release(); // release interface

}

CoUninitialize(); // close COM

}


The call to CoInitialize and CoCreateInstance initializes COM and gets a pointer to the necessary interface. Then you can call methods on the interface. When you are done calling methods you release the interface and call CoUninitialize to finish with COM. That's all there is to it. That would be all there is to it, that is, if things always worked as planned. There are a number of things that can go wrong when a COM clienttries to start a COM server. Some of the more common problems include:


l The client could not start COM

l The client could not locate the requested server

l The client could locate the requested server but it did not start properly

l The client could not find the requested interface

l The client could not find the requested method

l The client could find the requested method but it failed when called

l The client could not clean up properly


In order to track these potenital problems, you have to check things every step of the way by looking at HRESULT values. The above code does the checking, but it is difficult to tell what has gone wrong because the code is completely silent if an error occurs. The following function remedies that situation:


// This function displays detailed

// information contained in an HRESULT.

BOOL ShowStatus(HRESULT hr)

{

// construct a _com_error using the HRESULT

_com_error e(hr);

// The hr as a decimal number

cout << "hr as decimal: " <<>

// show the 1st 16 bits (SCODE)

cout << "SCODE: " <<>

// Show facility code as a decimal number

cout << "Facility: " <<>

// Show the severity bit

cout << "Severity: " <<>

// Use the _com_error object to format a message string.

// This is much easier then using ::FormatMessage

cout << "Message string: " <<>

return TRUE;

}


This function dismantles an HRESULT and prints all of its components, including the extremely useful English ErrorMessage value. You can call

it any time with this function call:


// display HRESULT on screen

ShowStatus( hr );

Figure 1. MFC Dialog example

To fully explore the different error modes of a simple COM program, the client in the following

demonstration code uses an MFC dialog application to let you control a number of possible errors

and see the effect they have on the HRESULT. When the client runs it will look like Figure 1.

You can see that the radio buttons on the left let you experiment with a lack of a CoInitialize

function, a bad class ID, and a bad interface ID. If you click the Run button the area on the right will

show the effect of the different errors on the HRESULT returned by different functions in the client.

When you explore the client code in this example, you will find that it is a somewhat more robust

version of the standard client code we used above. It also allows remote connections through

DCOM. For example, it sets default security using the CoInitializeSecurity function to introduce you

to that function, and it also makes use of the CoCreateInstanceEx function so that remote servers on other machines can be called. Walk

through the code, look up those two functions in the documentation and you will be amazed to find how easy it is to understand now that you

know something about COM!

0 comments: