Issues with COM DLL calling WCF Service

1

I have a WCF Service which has a contract like this: (the operation contract is OneWay)

[ServiceContract()]
public interface IEmpUpdate
{
    [OperationContract(IsOneWay = true)]
    void SendEmpUpdate(int _empid);
}

I have to call this SendEmpUpdate method from a COM DLL. I searched in the web and found some examples but that was for vb. My COM component was developed in C++. I followed the same steps for doing it in C++.

The Link which I followed:

http://pieterderycke.wordpress.com/2010/10/05/using-the-wcf-service-moniker-to-communicate-between-legacy-com-applications-and-new-net-applications/

This link explains about two ways of doing it:

1.Consuming a WCF service using a typed contract 2.Consuming a WCF service using a MEX endpoint

I tried in both ways: (C++)

The 2nd way (Consuming a WCF service using a MEX endpoint) please see the below code:

The 2nd way works fine if I change OperationContract IsOneWay to false for SendEmpUpdate. If its true the Invoke method is failing with HRESULT value 0x80131502 (it seems to be like a ArgumentOutOfRangeException uses the HRESULT COR_E_ARGUMENTOUTOFRANGE)


//Importing the tlb:

#import "Employee.tlb" no_namespace named_guids

//Creating the moniker string:

LPTSTR moniker = L"service:mexaddress=net.tcp://localhost:11234/Employee/mex, "
             L"address=net.tcp://localhost:11234/Employee, "
             L"contract=IEmpUpdate, "
             L"binding=nettcpEmpUpdate, ";

//Get the Object:

HRESULT hr = S_FALSE;
IDispatch* objWsc;

hr = CoGetObject(moniker, NULL, IID_IDispatch, (void**)&objWsc);

if (FAILED(hr))
{
    Message(TEXT("Client: CoGetObject"), hr);
    return(hr);
}

DISPID dispid;
BSTR pOperation = L"SendEmpUpdate";

hr = objWsc->GetIDsOfNames(
    IID_NULL,
    &pOperation,
    1,
    LOCALE_SYSTEM_DEFAULT,
    &dispid);

if (FAILED(hr))
{
    Message(TEXT("Client: GetIDsOfNames"), hr);
    return(hr);
}

DISPPARAMS empIDs;
VARIANTARG varData[1];
empIDs.rgvarg = &varData[0];

VariantInit(&empIDs.rgvarg[0]);
empIDs.rgvarg[0].vt = VT_I4;
empIDs.rgvarg[0].lVal = 564234; 

empIDs.cArgs = 1;
empIDs.cNamedArgs = 0;
empIDs.rgdispidNamedArgs = NULL;

VARIANT result;
//VariantInit(&result);
UINT argErr = 0;

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

hr = objWsc->Invoke(
    dispid,
    IID_NULL,
    LOCALE_SYSTEM_DEFAULT,
    DISPATCH_METHOD,
    &empIDs, &result, &pExcepInfo, &argErr);

if (FAILED(hr))
{
    Message(TEXT("Client: Invoke"), hr);
    return(hr);
}

The 1st method (Consuming a WCF service using a typed contract) please see the below code:

In the 1st method CoGetObject is failing objEmp is null.


//Importing the tlb:

#import "Employee.tlb" no_namespace named_guids

//Creating the moniker string:

LPTSTR moniker = L"address=net.tcp://localhost:11234/Employee, "
             L"contract={52DEEE76-0BAF-31D8-A48B-DA2C50FA2753}, "
             L"binding=nettcpEmpUpdate ";

//Get the Object:

HRESULT hr = S_FALSE;
IEmpUpdate* objEmp;

hr = CoGetObject(moniker, NULL, __uuidof(IEmpUpdate), (void**)&objEmp);

if (FAILED(hr))
{
    Message(TEXT("Client: CoGetObject"), hr);
    return(hr);
}

Questions:

  1. If I set IsOneWay to true in the 2nd way, it's failing, how to fix this issue?
  2. Why CoGetObject is failing in the 1st way how to fix it?
  3. If any one way works 1st or 2nd it would be really helpful. There are no example in the web.
c#
wcf
com
asked on Stack Overflow Mar 30, 2011 by Joboy • edited Mar 30, 2011 by John Saunders

2 Answers

5

First off...sorry your dealing with COM!

We had the occasion recently to consume a 4.0 WCF service (via httpBinding, though that shouldn't matter much, depending on version of .NET) from both C++ and VB6. I came across the same article(s) you probably did, and frankly, the COM Moniker goop is for the birds. I was never successful in getting it working in a reliable fashion. Could be I'm just ignorant.

Unfortunately, there is a pooh ton of 'legacy' code out there that is built on COM.

Instead, we were very successful in creating a .NET assembly with a facade to the actual WCF service proxy. We exposed the facade via .NET COM Interop and then delegated to the internal proxy clas, which was generated by Add Service Reference wizard. Beyond a little duplicated code, it worked like a champ while allowing downlevel clients to consume a SOAP based endpoint over HTTP.

Check out MSDN Example COM Class for how to decorate your facade class that will be exposed via COM Interop. It describes the magic sprinkle of attributes your types will need to be exposed to a COM aware client.

Basic outline is

  1. Build your .NET assembly, which is just a facade to your .NET service proxy and exposes your types
  2. Call Regasm.exe with /TLB flag to generate the typelib that will make life easy from COM clients such as C++/VB6
  3. Reference that TLB (via #import) from the client, in your case I believe C++. You'll have strong types (e.g. MyClassPtr) which can be used to invoke your service, via your .NET COM Interop facade.
  4. Be sure to call CoInitialize to get COM ready and CoUninitialize to tear it down when your done.

You might need to completely borrow tips from Reading WCF Configuration from a Custom Location on how to load up binding, and endpoint, configuration that might not be in the expected mayapp.exe.config if you don't 'own' the host.

Not exactly the answer your looking for, hopefully someone with the this experience will post.

Z

answered on Stack Overflow Mar 30, 2011 by Zach Bonham • edited Mar 30, 2011 by Zach Bonham
0

Possible answer to question 2: your moniker is missing its scheme prefix "service:" in this case.

answered on Stack Overflow Mar 30, 2011 by Chris Dickson

User contributions licensed under CC BY-SA 3.0