avinashse
avinashse

Reputation: 1460

use virtual function as callback in solace for topic subscriber

I am trying to use Solace c API through C++ classes.

There is already framework created in the existing project with reference to Base and Derived class, where derived virtual functions are called accordingly to the object referenced as run time.

My final task to implement Solace as "subscribing the topic" where I will be using same virtual function as call back method of existing base class.

In order to do that, I divided the task into stepd and in first step I created simple class and trying to use member function as callback methond, but I am getting the error. Please suggest what should be approach I should follow.

In below code, sessionMessageReceiveCallback is callback method, whenever messaged is published to TestTopic, sessionMessageReceiveCallback is called.

I need to call virtual method in below line of code:

sessionFuncInfo.rxMsgInfo.callback_p = sessionMessageReceiveCallback;
sessionFuncInfo.rxMsgInfo.user_p = NULL;

Below is the full code:

os.h

#pragma once

/** @example Intro/os.h
 */

 /*
  * OS-specific methods for abstracting.
  * Copyright 2008-2019 Solace Corporation. All rights reserved.
  */

#ifndef ___OS_H_
#define ___OS_H_

#ifdef __cplusplus
extern          "C"
{
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


#ifdef WIN32
#define _WIN32_WINNT 0x400      /* Require Windows NT5 (2000, XP, 2003) for SignalObjectAndWait */
#include <winsock2.h>
#include <windows.h>
#include <winbase.h>

#define SLEEP(sec)  Sleep ( (sec) * 1000 )
#define strcasecmp (_stricmp)
#define strncasecmp (_strnicmp)
#else
#include <unistd.h>

#define SLEEP(sec) sleep ( (sec) )
#endif



#ifdef __cplusplus
}
#endif
#endif

TopicSubscr.h

#include "os.h"
#include "solclient/solClient.h"
#include "solclient/solClientMsg.h"

class TopicSubscr
{
private :
    solClient_rxMsgCallback_returnCode_t
        sessionMessageReceiveCallback(solClient_opaqueSession_pt opaqueSession_p, 
                                      solClient_opaqueMsg_pt msg_p, void* user_p);
public :
    solClient_opaqueSession_pt session_p;
    static int msgCount;
    explicit TopicSubscr();
     ~TopicSubscr();
     
};

TopicSubscr.cpp

#include "TopicSubscr.h"

  /* Message Count */
static int msgCount = 0;

/*****************************************************************************
 * sessionMessageReceiveCallback
 *
 * The message callback is invoked for each Direct message received by
 * the Session. In this sample, the message is printed to the screen.
 *****************************************************************************/
solClient_rxMsgCallback_returnCode_t
TopicSubscr::sessionMessageReceiveCallback(solClient_opaqueSession_pt opaqueSession_p, solClient_opaqueMsg_pt msg_p, void* user_p)
{
    printf("Received message:\n");
    solClient_msg_dump(msg_p, NULL, 0);
    printf("\n");

    //msgCount++;

    return SOLCLIENT_CALLBACK_OK;
}

/*****************************************************************************
 * sessionEventCallback
 *
 * The event callback function is mandatory for session creation.
 *****************************************************************************/
void
sessionEventCallback(solClient_opaqueSession_pt opaqueSession_p,
    solClient_session_eventCallbackInfo_pt eventInfo_p, void* user_p)
{
}

TopicSubscr::TopicSubscr()
{
    /* Context */
    solClient_opaqueContext_pt context_p;
    solClient_context_createFuncInfo_t contextFuncInfo = SOLCLIENT_CONTEXT_CREATEFUNC_INITIALIZER;

    /* Session */
    
    solClient_session_createFuncInfo_t sessionFuncInfo = SOLCLIENT_SESSION_CREATEFUNC_INITIALIZER;

    /* Session Properties */
    const char* sessionProps[25] = { 0, };
    int             propIndex = 0;

    /*************************************************************************
     * Initialize the API (and setup logging level)
     *************************************************************************/

     /* solClient needs to be initialized before any other API calls. */
    solClient_initialize(SOLCLIENT_LOG_DEFAULT_FILTER, NULL);
    printf("TopicSubscriber initializing...\n");

    /*************************************************************************
     * Create a Context
     *************************************************************************/

     /*
      * Create a Context, and specify that the Context thread be created
      * automatically instead of having the application create its own
      * Context thread.
      */
    solClient_context_create(SOLCLIENT_CONTEXT_PROPS_DEFAULT_WITH_CREATE_THREAD,
        &context_p, &contextFuncInfo, sizeof(contextFuncInfo));

    /*************************************************************************
     * Create and connect a Session
     *************************************************************************/

     /* Configure the Session function information. */
    sessionFuncInfo.rxMsgInfo.callback_p = sessionMessageReceiveCallback;
    sessionFuncInfo.rxMsgInfo.user_p = NULL;
    sessionFuncInfo.eventInfo.callback_p = sessionEventCallback; // <-- Error here
    sessionFuncInfo.eventInfo.user_p = NULL;

    /* Configure the Session properties. */
    propIndex = 0;

    sessionProps[propIndex++] = SOLCLIENT_SESSION_PROP_HOST;
    sessionProps[propIndex++] = "127.0.0.1:55555";

    sessionProps[propIndex++] = SOLCLIENT_SESSION_PROP_VPN_NAME;
    sessionProps[propIndex++] = "default";

    sessionProps[propIndex++] = SOLCLIENT_SESSION_PROP_USERNAME;
    sessionProps[propIndex++] = "admin";

    sessionProps[propIndex++] = SOLCLIENT_SESSION_PROP_PASSWORD;
    sessionProps[propIndex++] = "admin";

    /* Create the Session. */
    solClient_session_create(sessionProps,
        context_p,
        &session_p, &sessionFuncInfo, sizeof(sessionFuncInfo));

    /* Connect the Session. */
    solClient_session_connect(session_p);

    /*************************************************************************
     * Subscribe
     *************************************************************************/

    solClient_session_topicSubscribeExt(session_p,
        SOLCLIENT_SUBSCRIBE_FLAGS_WAITFORCONFIRM, "TestTopic");


    /*************************************************************************
     * Wait for message
     *************************************************************************/

    printf("Waiting for message......\n");
    fflush(stdout);
    while (true) {
        SLEEP(1);
    }

    printf("Exiting.\n");

}


TopicSubscr::~TopicSubscr()
{
    /*************************************************************************
     * Unsubscribe
     *************************************************************************/

    solClient_session_topicUnsubscribeExt(session_p,
        SOLCLIENT_SUBSCRIBE_FLAGS_WAITFORCONFIRM,
        "TestTopic");

    /*************************************************************************
     * Cleanup
     *************************************************************************/

     /* Cleanup solClient. */
    solClient_cleanup();
}

Main.cpp

#include "TopicSubscr.h"
int main()
{
    TopicSubscr subsc;

    return 0;
}

Compilation error I am getting :

>    C:\SolaceCCode\solace-samples-c-master\build\intro\win\VS2008\TopicSubscriber\TopicSubscr.cpp(76,73): error C3867: 'TopicSubscr::sessionMessageReceiveCallback': non-standard syntax; use '&' to create a pointer to member
2>    C:\SolaceCCode\solace-samples-c-master\build\intro\win\VS2008\TopicSubscriber\TopicSubscr.cpp(76,73): error C2440: '=': cannot convert from 'solClient_rxMsgCallback_returnCode_t (__thiscall TopicSubscr::* )(solClient_opaqueSession_pt,solClient_opaqueMsg_pt,void *)' to 'solClient_session_rxMsgCallbackFunc_t'
2>    C:\SolaceCCode\solace-samples-c-master\build\intro\win\VS2008\TopicSubscriber\TopicSubscr.cpp(76,44): message : There is no context in which this conversion is possible

Reference to solclient.h :

Reference to solClientMsg.h :

Example I used for reference :

Upvotes: 0

Views: 204

Answers (1)

Pan P
Pan P

Reputation: 84

The main problem here is that you can't use a pointer to member function where a function pointer is expected. The error is about sessionMessageReceiveCallback.

What you can do here for example:

  1. Create a static member function with the callback signature.
  2. Set that user_p to this when setting callbacks. Note that it will be given back to you as one of the callback arguments.
  3. Call your desired member callback via the user_p pointer inside the static callback.
class TopicSubscr
{
private :
    static solClient_rxMsgCallback_returnCode_t
    sessionMessageReceiveCallback(solClient_opaqueSession_pt opaqueSession_p, solClient_opaqueMsg_pt msg_p, void* user_p)
    {
        static_cast<TopicSubscr*>(user_p)->myCallback(msg_p);
    }

    void myCallback(solClient_opaqueMsg_pt msg_p)
    {
        //now you are back inside your object
    }
...

And when you set up the callbacks, you can use the name of the static function.

sessionFuncInfo.rxMsgInfo.callback_p = sessionMessageReceiveCallback;
sessionFuncInfo.rxMsgInfo.user_p = this; // <-- Here you set the object on which you'll call the callback method from the static function

Upvotes: 0

Related Questions