Geeks With Blogs

News





INauseous() Shawn Cicoria - Solution Architect, Craftsman and Artisan - INauseous() - Main Blog Here: www.Cicoria.com

A little while back Martin sent me a question on some of the examples in Chapter 10 of our book (Pro WCF).  The point of the question was how to dynamically consume a WCF services (late bind) from C++ using COM.

The root of the capability lies in the moniker implementation, which is provided for inside of System.ServiceModel.ComIntegration.  There's a series of types, attribute type as well, that the ServiceModel framework will build up the COM client along with the interfaces based upon a "GetObject" call from VB or even C++.

The thing with VB is it makes things so much easier.  So, I finally got around to fiddling with it.  I did end up with an issue, but the jist is easy to follow. 

The source code link here has a couple of samples that dynamically call a COM interface - one using the "script" moniker which is for Windows Scripting Host Components (built a whole site based upon that years ago) and WCF.

Let's take a look at calling a Scripting Component using C++ COM.  Note that the CoGetObject is a call that combines 3 distinct calls into 1 convenient method.  Take a look at the attached sample wsc file to see the inners of the component.

The script moniker is the key.  Just as we'll see in a bit the service moniker.  Both are defined in the registy under HKCR\script and HKCR\service as to which COM component implements the moniker (IMoniker) interface.

The main steps are: 1) Initialize COM, 2) GetObject, 3) Get Dispatch Interface for method, 4) Invoke interface

Sample Solution

    1 int CallWscComponent()

    2 {

    3     HRESULT hr;

    4     IDispatch* objWsc;

    5 

    6     hr = CoGetObject(L"script:D:\\Data\\Projects\\CallingWcf\\test.wsc",

    7         NULL,

    8         IID_IDispatch,

    9         (void**)&objWsc);

   10 

   11     if (FAILED(hr))

   12     {

   13         Message(TEXT("Client: CoGetObject"), hr);

   14         return(hr);

   15     }

   16 

   17 

   18     DISPID dispid;

   19     CString strFxName = "methodname";

   20     OLECHAR * szMember2 = strFxName.AllocSysString();

   21 

   22     hr = objWsc->GetIDsOfNames(

   23         IID_NULL,

   24         &szMember2,

   25         1,

   26         LOCALE_SYSTEM_DEFAULT,

   27         &dispid);

   28 

   29     if (FAILED(hr))

   30     {

   31         Message(TEXT("Client: GetIDsOfNames"), hr);

   32         return(hr);

   33     }

   34 

   35     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};

   36 

   37     hr = objWsc->Invoke(

   38         dispid,

   39         IID_NULL,

   40         LOCALE_USER_DEFAULT,

   41         DISPATCH_METHOD,

   42         &dispparamsNoArgs, NULL, NULL, NULL);

   43 

   44     if (FAILED(hr))

   45     {

   46         Message(TEXT("Client: Invoke"), hr);

   47         return(hr);

   48     }

   49 

   50 }

 

Now, here's an example of using an untyped proxy and Mex discovery.

The first thing is to do is build the moniker:

LPTSTR moniker = L"service:mexAddress=\"http://localhost:8899/WebService/Service.svc/mex\",\

                  address=\"http://localhost:8899/WebService/Service.svc\",\

                  contract=IMyService, \

                  contractNamespace=http://tempuri.org/,binding=BasicHttpBinding_IMyService, \

                  bindingNamespace=http://tempuri.org/";

Now, here's a quick walk-through of calling WCF through COM. 

    1 void CallWcf()

    2 {

    3     HRESULT hr;

    4     IDispatch* objWsc;

    5 

    6     hr = CoGetObject(moniker,

    7         NULL,

    8         IID_IDispatch,

    9         (void**)&objWsc);

   10 

   11     if (FAILED(hr))

   12     {

   13         Message(TEXT("Client: CoGetObject"), hr);

   14         return(hr);

   15     }

   16 

   17     DISPID dispid;

   18     CString strFxName = "MyOperation3";

   19     OLECHAR * szMember2 = strFxName.AllocSysString();

   20 

   21     hr = objWsc->GetIDsOfNames(

   22         IID_NULL,

   23         &szMember2,

   24         1,

   25         GetUserDefaultLCID(),

   26         &dispid);

   27 

   28     if (FAILED(hr))

   29     {

   30         Message(TEXT("Client: GetIDsOfNames"), hr);

   31         return(hr);

   32     }

   33 

   34     DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};

   35     EXCEPINFO pExcepInfo;

   36     memset(&pExcepInfo, 0, sizeof(EXCEPINFO));

   37 

   38 

   39     hr = objWsc->Invoke(

   40         dispid,

   41         IID_NULL,

   42         GetUserDefaultLCID(),

   43         DISPATCH_METHOD,

   44         &dispparamsNoArgs, NULL, NULL, NULL);

   45 

   46     if (FAILED(hr))

   47     {

   48         Message(TEXT("Client: Invoke"), hr);

   49         return(hr);

   50     }

   51 

   52 }

Posted on Tuesday, August 28, 2007 9:28 PM .NET , WCF (Indigo) | Back to top


Comments on this post: Consuming WCF Services from COM using C++

Comments are closed.
Comments have been closed on this topic.
Copyright © Shawn Cicoria | Powered by: GeeksWithBlogs.net