How to call COM+ remotely with anonymous user

 

The purpose of this tutorial is to give you an idea on how to call the COM+ server remotely. I’m not going to go into the depths of COM+ details or how to develop COM+, this tutorial is designed to show 3 ways on how to call COM+ server with VC++.

Environment: Windows 2000 for server side, Windows XP for client side

Step 1: Setting COM+ security on server side

If the client and server are in same domain, we only need to grant “Access” and “Launch” permissions to Domain Users. Now we hope to call the COM+ component out of domain, this could be anonymous access.

1. Configure the COM+ security

1) Uncheck "Enforce access checks for this application"

2) Check "Perform access checks only at the process level......"

3) "Authentication level for calls: None"

4) "Impersonation level: Anonymous"

Call_COM_01

2. Enable “guest” account for windows.

Call_COM_02

Step 2: Call the COM+ remotely

Method 1: Export proxy from server side and then install it on client side

1. On the server side, in “Component Services”, right click your COM+ application and select “Export…”

2. In the “COM Application Export Wizard”, select type as “Application proxy”, it will produce a *.msi file.

3. Install the *.msi file on the client side

Then, you can call this COM+ just as installed on localhost. Here’s the sample code.

void main(void)

{

// Declare and HRESULT and a pointer to the Simple_ATL interface

HRESULT hr;

ISimpleClass *IS = NULL;

// Now we will intilize COM

hr = CoInitialize(0);

// Use the SUCCEDED macro and see if we can get a pointer to

// the interface

if(SUCCEEDED(hr))

{

hr = CoCreateInstance( CLSID_SimpleClass, NULL, CLSCTX_REMOTE_SERVER, IID_ISimpleClass, (void**) &IS);

if(SUCCEEDED(hr))

{

BSTR ReturnValue;

hr = IS->HelloWorld(&ReturnValue);

char* pValue=_com_util::ConvertBSTRToString(ReturnValue);

cout << pValue << endl;

hr = IS->Release();

}

else

{

printf("CreateInstance Error!Error Code:%x\n",hr);

}

}

// Uninitialize COM

CoUninitialize();

}

Method 2: Register the COM+ dll on client side with “RemoteServername”

1. Register the dll as DCOM: regsvr32 <yourcom.dl>

2. Search the DCOM component in registry, find the CLSID of your COM dll

3. Under the CLSID , Create a Key named "AppID", and set the value as same as the value of CLSID

4. Delete the value of CLSID\InprocServer32

5. Add the AppID of step 3 under HKEY_CLASSES_ROOT\AppID

6. Add "RemoteServerName" to the to HKEY_CLASSES_ROOT\AppID\{YourAppID}, the value is the remote server's name

Here’s the example of the registry key settings.

---------------------------------------------------------------------------

 Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\AppID\{23F55D14-50A5-45E1-B8EA-FBE3E789BA97}]
@="TestCom.SimpleClass"
"RemoteServerName"="zx-win2k02"

[HKEY_CLASSES_ROOT\CLSID\{23F55D14-50A5-45E1-B8EA-FBE3E789BA97}]
@="SimpleClass Class"
"AppID"="{23F55D14-50A5-45E1-B8EA-FBE3E789BA97}"

[HKEY_CLASSES_ROOT\CLSID\{23F55D14-50A5-45E1-B8EA-FBE3E789BA97}\InprocServer32]
@=""
"ThreadingModel"="Apartment"

-------------------------------------------------------------

The source code is as same as Method 1.

Method 3: Call the COM+ remotely with CoCreateInstanceEx

 

1. Register the dll as DCOM: regsvr32 <yourcom.dl>

2. Write the source code with CoCreateInstanceEx, and specify the remote server name in source code. Here’s the example.

void main(void)

{

      HRESULT hr;

      ISimpleClass *pI=NULL;

     

      COSERVERINFO sin,*sinptr;

      MULTI_QI mqi;

      mqi.pIID=&IID_ISimpleClass;

      mqi.hr=0;

      mqi.pItf=0;

      COAUTHINFO authInfo;

      authInfo.dwAuthnSvc = RPC_C_AUTHN_NONE;

      authInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE;

……

      sin.dwReserved1=0;

      sin.dwReserved2=0;

      sin .pwszName=L"zx-win2k02";//define the remote server name here

      sin.pAuthInfo=&authInfo;

      sinptr=&sin;

     

      hr=CoInitialize(0);

      if(SUCCEEDED(hr))

      {

           

            hr=CoCreateInstanceEx(CLSID_SimpleClass,

                                          NULL,

                                          CLSCTX_REMOTE_SERVER,

                                          sinptr,

                                          1,

                                          &mqi

                                          );

            if(SUCCEEDED(hr))

            {

            pI=(ISimpleClass*)mqi.pItf;

            BSTR bsReturnValue;

     

            pI->HelloWorld(&bsReturnValue);

     

            char* pValue=_com_util::ConvertBSTRToString(bsReturnValue);

            printf("%s\n",pValue);

            delete pValue;

     

            }

            else

            {

                  printf("CreateInstance Error!Error Code:%x\n",hr);

            }

      }

References

 

Client/Server connection using DCOM, with anonymous access: https://www.codeproject.com/KB/COM/clientserverwithdcom.aspx

DCOM Architecture: https://msdn.microsoft.com/en-us/library/ms809311.aspx

COM+ (Component Services) : https://msdn.microsoft.com/en-us/library/ms685978(VS.85).aspx

CoCreateInstanceEx Function: https://msdn.microsoft.com/en-us/library/ms680701(VS.85).aspx

CoCreateInstance Function: https://msdn.microsoft.com/en-us/library/ms686615(VS.85).aspx

 

Regards,

Zhixing Lv