calling WCF services from native C++

I'm having some trouble connecting to a WCF service from my MFC(VS2010) application and hoping that someone here can point me in the right direction again.

The service is a .NET4.5 Forms Application with a WCF service.

the WCF service provides 3 methods, SubscribeDLIClient(String clientName); UnsubscribeDLIClient(); SendDataToClient();

SendDataToClient() is a callback that will call my client asynchronously when it has data for me.

unfortunately i'm falling at the first hurdle, calling SubscribeDLIClient("MFCClient");

I'm using Windows Web Services API, I have no access to the source code of the service i'm attempting to connect to, but have used wsutil.exe to generate some c/h files for my project.




In the code below, CdliClientDlg::OnBnClickedButtonConnect() attempts to call WsSendMessage() to connect and subscribe for data at line 67 in the third code block.

The WsSendMessage() call triggers the CdliClientDlg::ReceiverThread()which promptly fails at the call to WsReceiveMessage() at line 39 in the second code block.

The HRESULT is 0x80d30003 "The operation is not allowed due to the current state of the object."

My code is below, It's a fair size for posting (the largest I've posted anyway) but i wanted it to be complete so here it is.

Thanks for looking, I can post more if needed.

1
2
3
4
5
6
7
// the receiver thread, a static member function to call my instance.

DWORD WINAPI CdliClientDlg::StaticReceiverThread(void* pParam)
{
    CdliClientDlg* pThis = static_cast<CdliClientDlg*>(pParam);
    return pThis->ReceiverThread();
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// the actual receiver thread.
DWORD CdliClientDlg::ReceiverThread()
{
    HRESULT hr(S_OK);
    WS_ERROR* pError(nullptr);
    WS_HEAP* pHeap(nullptr);

    void* callbackBody(nullptr);
    ULONG index(ULONG_MAX);

    const WS_MESSAGE_DESCRIPTION* messageDescriptions[] = {
        &my_dli_dliservice_wsdl.messages.IDliWcfContract_SubscribeDLIClient_OutputMessage,
        &my_dli_dliservice_wsdl.messages.IDliWcfContract_UnsubscribeDLIClient_OutputMessage,
        &my_dli_dliservice_wsdl.messages.IDliWcfContract_SendDataToClient_OutputCallbackMessage
    };

    hr = WsCreateError(NULL, 0, &pError);
    if (FAILED(hr))
    {
        PrintError("WsCreateError()",hr,pError);
        return 0;
    }

    hr = WsCreateHeap(200, 0, NULL, 0, &pHeap, pError);
    if (FAILED(hr))
    {
        PrintError("WsCreateHeap()",hr,pError);
        WsFreeError(pError);
        return 0;
    }

    for (;;)
    {
        callbackBody = NULL;
        index = ULONG_MAX;

        try
        {
            hr = WsReceiveMessage(m_pChannel,m_pMessage,messageDescriptions,WsCountOf(messageDescriptions),
                                WS_RECEIVE_OPTIONAL_MESSAGE,WS_READ_REQUIRED_POINTER,pHeap,&callbackBody,sizeof(callbackBody),&index,NULL,pError);
        }
        catch (std::exception& e)
        {
            std::string s = e.what();
            int i = hr;
        }
        if (FAILED(hr) || WS_S_END == hr)
        {
            PrintError("WsReceiveMessage()",hr,pError);
        }

        switch(index)
        {
            case 0:
                // IDliWcfContract_SubscribeDLIClient_OutputMessage
            case 1:
                //IDliWcfContract_UnsubscribeDLIClient_OutputMessage
                break;
            case 2:
                //IDliWcfContract_SendDataToClient_OutputCallbackMessage
                break;
        }

        hr = WsResetMessage(m_pMessage, pError);
        if (FAILED(hr))
        {
            PrintError("WsResetMessage()",hr,pError);
        }

        // Reset heap
        hr = WsResetHeap(pHeap, pError);
        if (FAILED(hr))
        {
            PrintError("WsResetHeap()",hr,pError);
        }
    }

    WsFreeHeap(pHeap);
    WsFreeError(pError);

    return 0;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// the connect code
void CdliClientDlg::OnBnClickedButtonConnect()
{
    // Create a TCP duplex session channel
    HRESULT hr;
    WS_ERROR* pError = nullptr;
    m_pChannel = nullptr;
    m_pMessage = nullptr;

    WS_ENDPOINT_ADDRESS address;
    address.url.chars = L"net.tcp://localhost:14000/DLI";
    address.url.length = (ULONG)::wcslen(address.url.chars);
    address.headers = nullptr;
    address.extensions = nullptr;
    address.identity = nullptr;

    hr = WsCreateError(NULL, 0, &pError);
    if (FAILED(hr))
    {
        PrintError("WsCreateError()",hr,pError);
        return;
    }

    hr = WsCreateChannel(WS_CHANNEL_TYPE_DUPLEX_SESSION,WS_TCP_CHANNEL_BINDING,NULL,0,NULL,&m_pChannel, pError);
    if (FAILED(hr))
    {
        PrintError("WsCreateChannel()",hr,pError);
        WsFreeError(pError);
        return;
    }

    // Open channel to address

    hr = WsOpenChannel(m_pChannel,&address,NULL,pError);
    if (FAILED(hr))
    {
        PrintError("WsOpenChannel()",hr,pError);
        WsFreeError(pError);
        return;
    }

    // Create a thread to receive callback messages

    HANDLE receiverThreadHandle = CreateThread(NULL, 0, StaticReceiverThread, (void*)this, 0, NULL);
    if (receiverThreadHandle == NULL)
    {
        hr = HRESULT_FROM_WIN32(GetLastError());
        
        PrintError("CreateThread()",hr,pError);
        WsFreeError(pError);
        return;
    }


    // subscribe for DLI data
    hr = WsCreateMessageForChannel(m_pChannel,NULL,0,&m_pMessage,pError);
    if (FAILED(hr))
    {
        PrintError("WsCreateMessageForChannel()",hr,pError);
        WsFreeError(pError);
        return;
    }


    _SubscribeDLIClient subscribeDLIClient = {L"MFCClient"};

    hr = WsSendMessage(m_pChannel, m_pMessage, &my_dli_dliservice_wsdl.messages.IDliWcfContract_SubscribeDLIClient_InputMessage
                      ,WS_WRITE_REQUIRED_VALUE, &subscribeDLIClient, sizeof(subscribeDLIClient), NULL, pError);
    if (FAILED(hr))
    {
        PrintError("WsSendMessage()",hr,pError);
        WsFreeError(pError);
        return;
    }
}



Last edited on
Topic archived. No new replies allowed.