Introduction
This article will explain implementing a quick client/server connection using DCOM.
Using the code
This article consists of two parts:
- Server side implementation
- Client side implementation
Let's start with server side implementation:
- Start 'New ATL COM Wizard project' with Visual Studio.
- Name it as TestServer.
- Select server type: Service.
- Insert new ATL object: Category-Objects, Objects-Simple Objects.
- Name the interface as
IHello
.
- Add method
Beep()
.
Now, we need to turn off the authentication of DCOM server. Open TestServer.rgs from Workspace window and add the following lines just before 'TestServer.EXE':
{
val AccessPermission = b '01000480300000004c000000000000001
400000002001c000100000000021400010000000101000000000001000000000
105000000000005150000007ceb240dfa4f0c2ff89fb474f2030000010500000
0000005150000007ceb240dfa4f0c2ff89fb47401020000'
val LaunchPermission = b '01000480300000004c000000000000001
400000002001c000100000000021400010000000101000000000001000000000
105000000000005150000007ceb240dfa4f0c2ff89fb474f2030000010500000
0000005150000007ceb240dfa4f0c2ff89fb47401020000'
}
Open testMonitor.cpp, locate Run()
function, and make it look like this:
void CServiceModule::Run()
{
_Module.dwThreadID = GetCurrentThreadId();
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
hr = CoInitializeSecurity( 0, -1, 0, 0,
RPC_C_AUTHN_LEVEL_NONE,
RPC_C_IMP_LEVEL_IDENTIFY, 0, 0, 0 );
hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER |
CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE);
..............
Finally, add the following line to Beep()
method and the server side is ready!!!
MessageBeep(MB_ICONEXCLAMATION);
Now, let's implement the client:
- Start 'New MFC App Wizard, dialog based, name it TestClient.
- Insert Resource, Custom, and name it exactly TYPELIB.
- ID of TYPELIB resource must be 1.
- Open property page for TYPELIB resource and specify path to file as TestServer.tlb.
- Add
#import "..//TestServer/testserver.tlb" no_namespace
line to stdafx.h.
- Add
include
s for Afxctl.h, objbase.h and initguid.h to stdafx.h.
- Add
_WIN32_DCOM
to preprocessor definitions.
Now, we need to add the actual connection code. Add the following Connect()
function to your app class:
IIHello* CTestClientApp::Connect(CString& strIPAddress, CString& strError)
{
CLSID libid;
CLSIDFromString (L"{55259785-1985-4DCB-B4BA-FCB7F968DFA4}", &libid);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), libid))
{
AfxMessageBox("Failed to register server's type library");
return NULL;
}
CLSID clsid;
const IID IID_IHELLO = {0xFB57F08C,0x0F91,0x4046,
{0x8E,0xF1,0x05,0xD8,0x90,0x4C,0x66,0xF0}};
MULTI_QI mqi = { &IID_IHELLO, 0, 0 };
CLSIDFromString (L"{C7B7C24F-5B72-49D0-962B-FFD650BFFA2B}", &clsid);
CoInitialize(0);
COAUTHINFO cai = { RPC_C_AUTHN_NONE,
RPC_C_AUTHZ_NONE,
0,
RPC_C_AUTHN_LEVEL_NONE,
RPC_C_IMP_LEVEL_IMPERSONATE,
0,
EOAC_NONE};
COSERVERINFO csi = { 0, strIPAddress.AllocSysString(), &cai, 0 };
HRESULT hr = CoCreateInstanceEx(clsid, NULL,
CLSCTX_REMOTE_SERVER, &csi, 1, &mqi);
if (FAILED(hr))
{
TCHAR szError[1024];
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
szError,
1024,
NULL);
strError = szError;
return FALSE;
}
return (IIHello*)(mqi.pItf);
}
From the code provided above, it can be seen that three GUIDs are needed: LIBID
, CLASSID
, and ITERFACEID
. All of them must be taken from testserver.idl. Our connection code example is a bit hard-coded, but it allows to run the client on any machine without any registration. Server has to be registered before use. Since this is a DCOM server, it can be registered as a service or as a local server. To register the server as a service, type:
testserver /Service
To register the server as a local server, type:
testserver /RegServer
And finally, let's execute Beep()
method on the remote server. To do that, let's just add a handler for the Beep button.
void CTestClientDlg::OnButtonBeep()
{
((CTestClientApp*)AfxGetApp())->m_pHello->Beep();
}
Hope this wasn't boring, but useful :-)
History
- 06/02/2005 - Initial document creation.