The article discusses how to get offers in C++.
    There are two ways to get offers in your C++ application.
The first way is to use table listener. In this case you should:
  Create a session, a session status listener, subscribe the status listener to the session status
(see this article).
 
  Implement the IO2GTableListener interface
in a table listener class:
class TableListener : public IO2GTableListener {...}
 
  Allow the use of table manager (it should be done before the login):
session->useTableManager(::Yes, NULL);
 
  Log in (see this article).
 
  Get table manager:
IO2GTableManager *tableManager = session->getTableManager();
 
  Wait for TablesLoaded status of IO2GTableManager.
while (tableManager->getStatus() != TablesLoaded && tableManager->getStatus() != TablesLoadFailed) 
    uni::Sleep(50);
 
  Get "Offers" table:
IO2GOffersTable *offersTable = (IO2GOffersTable *)tableManager->getTable(::Offers);
 
  The table can be processed to get information about offers:
IO2GOfferTableRow *offerRow = NULL;
IO2GTableIterator tableIterator = {0, 0, NULL};
while (offersTable->getNextRow(tableIterator, offerRow))
{
    printf("Instrument: %s, Bid = %f, Ask = %f\n", offerRow->getInstrument(), offerRow->getBid(), offerRow->getAsk());
    offerRow->release();
}
 
  To capture updates of "Offers" table create table listener and subscribe it to "Update" event of "Offers" table:
TableListener * tableListener = new TableListener();
offersTable->subscribeUpdate(Update, tableListener);
 
  Process table updates in "onChanged" event of IO2GTableListener:
void TableListener::onChanged(const char *rowID, IO2GRow *row)
{
    IO2GOfferRow *offerRow = static_cast<IO2GOfferRow *>(row);
    if (offerRow!=NULL)
        printf("Instrument: %s, Bid = %f, Ask = %f\n", offerRow->getInstrument(), offerRow->getBid(), offerRow->getAsk());
}
 
  Unsubscribe from table listener when you are done:
offersTable->unsubscribeUpdate(Update, tableListener);
delete tableListener;
offersTable->release();
 
  Log out (see this article).
 
  Get offers example [hide]
  
main.cpp
#include <string>
#include <map>
#include "../../../../../../include/ForexConnect.h"
#include "sessionstatus.h"
#include "responselistener.h"
 
int main(int argc, char *argv[])
{
    const char *user = 0;
    const char *password = 0;
    const char *url = 0;
    const char *connection = 0;
    const char *subsession = 0;
    const char *pin = 0;
    if (argc < 3)
    {
        printf("usage: GetOffers.exe user password url connection [subsession] [pin]\n");
        return -1;
    }
 
    user = argv[1];
    password = argv[2];
    if (argc >= 4)
        url = argv[3];
    else
        url = "http://www.fxcorporate.com/Hosts.jsp";
    if (argc >= 5)
        connection = argv[4];
    else
        connection = "Demo";
 
    IO2GSession *session = CO2GTransport::createSession();
    SessionStatusListener *status_listener = new SessionStatusListener(session, true, subsession, pin);
    ResponseListener *response_listener = new ResponseListener(session);
    session->subscribeSessionStatus(status_listener);
    session->subscribeResponse(response_listener);
    status_listener->resetError();
    printf("connecting...\n");
    session->login(user, password, url, connection);
 
    bool connected = false;
 
    while (true)
    {
        uni::WaitForSingleObject(status_listener->getEvent(), 250);
        if (status_listener->getStatusCode() == IO2GSessionStatus::Connected)
        {
            connected = true;
            break;
        }
        if (status_listener->wasError())
        {
            printf("Connection failed: %s", status_listener->getError());
            break;
        }
    }
 
    if (connected)
    {
        printf("connected\n");
 
        //subscribe for offer updates if offers aren't subscribed automatically
        IO2GLoginRules *rules = session->getLoginRules();
        if (!rules->isTableLoadedByDefault(Offers))
        {
            //subscribe
            IO2GRequestFactory *factory = session->getRequestFactory();
            IO2GRequest *request = factory->createRefreshTableRequest(Offers);
            session->sendRequest(request);
            request->release();
            factory->release();
        }
        else
        {
            //process response in case the offers are already subscribed
            IO2GResponse *response = rules->getTableRefreshResponse(Offers);
            response_listener->onRequestCompleted("", response);
            response->release();
        }
 
        //do nothing 10 seconds, lets all work
        Sleep(10000);
 
        session->logout();
        printf("disconnecting...\n");
        while (true)
        {
            uni::WaitForSingleObject(status_listener->getEvent(), 250);
            if (status_listener->getStatusCode() == IO2GSessionStatus::Disconnected)
                break;
        }
        printf("disconnected\n");
    }
 
    session->unsubscribeResponse(response_listener);
    response_listener->release();
    session->unsubscribeSessionStatus(status_listener);
    status_listener->release();
    session->release();
}
 
 
 Offer.h
#include "../../../../../../include/ForexConnect.h"
!
/** class to keep offers. */
class Offer
{
 private:
    std::string mID;            //!< offer identifier
    std::string mInstrument;    //!< instrument
    int mPrecision;             //!< offer precision
    DATE mTime;                 //!< date and time of the offer change
    double mPipSize;            //!< offer pipsize
    double mBid;                //!< offer bid
    double mAsk;                //!< offer ask
 public:
    /** Constructor. */
    Offer(const char *id, const char *instrument, int precision, double pipsize, double date, double bid, double ask);
 
    /** Update bid. */
    void setBid(double bid);
 
    /** Update ask. */
    void setAsk(double ask);
 
    /** Update date. */
    void setTime(DATE date);
 
    /** Get id. */
    const char *getID() const;
 
    /** Get instrument. */
    const char *getInstrument() const;
 
    /** Get precision. */
    int getPrecision() const;
 
    /** Get pipsize. */
    double getPipSize() const;
 
    /** Get bid. */
    double getBid() const;
 
    /** Get ask. */
    double getAsk() const;
 
    /** Get date. */
    DATE getTime() const;
};
 
 offer.cpp
#include <string>
#include <vector>
#include <map>
#include "offer.h"
 
/** Constructor. */
Offer::Offer(const char *id, const char *instrument, int precision, double pipsize, DATE date, double bid, double ask)
{
    mID = id;
    mInstrument = instrument;
    mPrecision = precision;
    mPipSize = pipsize;
    mTime = date;
    mBid = bid;
    mAsk = ask;
}
 
/** Update bid. */
void Offer::setBid(double bid)
{
    mBid = bid;
}
 
/** Update ask. */
void Offer::setAsk(double ask)
{
    mAsk = ask;
}
 
 
/** Update date. */
void Offer::setTime(DATE date)
{
    mTime = date;
}
 
/** Get id. */
const char *Offer::getID() const
{
    return mID.c_str();
}
 
/** Get instrument. */
const char *Offer::getInstrument() const
{
    return mInstrument.c_str();
}
 
/** Get precision. */
int Offer::getPrecision() const
{
    return mPrecision;
}
 
/** Get pipsize. */
double Offer::getPipSize() const
{
    return mPipSize;
}
 
/** Get bid. */
double Offer::getBid() const
{
    return mBid;
}
 
/** Get ask. */
double Offer::getAsk() const
{
    return mAsk;
}
 
/** Get date. */
DATE Offer::getTime() const
{
    return mTime;
}
 
 
/** Constructor. */
OfferCollection::OfferCollection()
{
}
 
/** Destructor. */
OfferCollection::~OfferCollection()
{
    clear();
}
 
/** Add offer to collection. */
void OfferCollection::addOffer(Offer *offer)
{
    std::map<std::string, Offer *>::const_iterator iter = mIndex.find(offer->getID());
    if (iter != mIndex.end())
    {
        for (int i = 0; i < (int)mOffers.size(); i++)
        {
            if (mOffers[i] == offer)
            {
                delete mOffers[i];
                mOffers.erase(mOffers.begin() + i);
                break;
            }
        }
    }
    mOffers.push_back(offer);
    mIndex[offer->getID()] = offer;
}
 
/** Find offer by id. */
Offer *OfferCollection::findOfferForUpdate(const char *id) const
{
    std::map<std::string, Offer *>::const_iterator iter = mIndex.find(id);
    if (iter == mIndex.end())
        return 0;
    else
        return iter->second;
}
/** Find offer by id. */
const Offer *OfferCollection::findOffer(const char *id) const
{
    std::map<std::string, Offer *>::const_iterator iter = mIndex.find(id);
    if (iter == mIndex.end())
        return 0;
    else
        return iter->second;
}
 
/** Get number of offers. */
int OfferCollection::size() const
{
    return (int)mOffers.size();
}
 
/** Get offer by index. */
const Offer *OfferCollection::get(int index) const
{
    return mOffers[index];
}
 
void OfferCollection::clear()
{
    int i;
    for (i = 0; i < (int)mOffers.size(); i++)
        delete mOffers[i];
    mOffers.clear();
    mIndex.clear();
}
 
sessionstatuslistener.h
#pragma once
 
#include <stdio.h>
#include <string.h>
#include "../../../../threadlib/include/threadlib.h"
#ifdef WIN32
 #pragma warning (disable : 4996)
#else
  #define Sleep(A) sleep((A) / 1000)
#endif
 
/** Status listener for the sessions. */
 
class SessionStatusListener : public IO2GSessionStatus
{
 private:
    long mRefCount;
    /** Sub session identifier. */
    std::string mSubSessionID;
    /** Pin code. */
    std::string mPin;
    /** The last session status code received. */
    IO2GSessionStatus::O2GSessionStatus mStatusCode;
    /** Flag indicating what error happened. */
    bool mHasError;
    /** Error. */
    std::string mError;
    /** Flag indicating whether sessions must be printed. */
    bool mPrintSubsessions;
    /** Session object. */
    IO2GSession *mSession;
    /** Event handle. */
    HANDLE mEvent;
 protected:
    /** Destructor. */
    ~SessionStatusListener();
 
 public:
    /** Constructor.
 
        @param session          Session to listen
        @param printSubsessions Print sub sessions
        @param subSessionID     Identifier of the subsession or NULL in case
                                no subsession selector is expected
        @param pin              Pin code or NULL in case no pin code request is expected
      */
    SessionStatusListener(IO2GSession *session, bool printSubsessions, const char *subSessionID = 0, const char *pin = 0);
 
    /** Increase reference counter. */
    virtual long addRef();
 
    /** Decrease reference counter. */
    virtual long release();
 
    /** Callback called when login has been failed. */
    virtual void  onLoginFailed (const char *error);
 
    /** Callback called when session status has been changed. */
    virtual void  onSessionStatusChanged(IO2GSessionStatus::O2GSessionStatus status);
 
    /** Get the session status. */
    IO2GSessionStatus::O2GSessionStatus getStatusCode() const;
 
    /** Check whether error happened. */
    bool wasError() const;
 
    /** Reset error information (use before login). */
    void resetError();
 
    /** Get error. */
    const char *getError() const;
 
    /** Get event handle to monitor the status. */
    HANDLE getEvent() const;
};
 
sessionstatuslistener.cpp
#include <string>
#include "../../../../../../include/ForexConnect.h"
#include "sessionstatus.h"
 
/** Constructor. */
SessionStatusListener::SessionStatusListener(IO2GSession *session, bool printSubsessions, const char *subSessionID, const char *pin)
{
    if (subSessionID != 0)
        mSubSessionID = subSessionID;
    else
        mSubSessionID = "";
    if (pin != 0)
        mPin = pin;
    else
        mPin = "";
    mSession = session;
    mSession->addRef();
    mHasError = false;
    mError = "";
    mPrintSubsessions = printSubsessions;
    mRefCount = 1;
    mStatusCode = IO2GSessionStatus::Disconnected;
    mEvent = uni::CreateEvent(0, FALSE, FALSE, 0);
}
 
/** Destructor. */
SessionStatusListener::~SessionStatusListener()
{
    mSession->release();
    mSubSessionID.clear();
    mPin.clear();
    mError.clear();
    uni::CloseHandle(mEvent);
}
 
/** Increase reference counter. */
long SessionStatusListener::addRef()
{
    return InterlockedIncrement(&mRefCount);
}
 
/** Decrease reference counter. */
long SessionStatusListener::release()
{
    long rc = InterlockedDecrement(&mRefCount);
    if (rc == 0)
        delete this;
    return rc;
}
 
/** Callback called when login has been failed. */
void SessionStatusListener::onLoginFailed(const char *error)
{
    mHasError = true;
    mError = error;
    uni::SetEvent(mEvent);
}
 
/** Callback called when session status has been changed. */
void SessionStatusListener::onSessionStatusChanged(IO2GSessionStatus::O2GSessionStatus status)
{
    switch (status)
    {
    case    IO2GSessionStatus::Disconnected:
            printf("status::disconnected\n");
            break;
    case    IO2GSessionStatus::Connecting:
            printf("status::connecting\n");
            break;
    case    IO2GSessionStatus::TradingSessionRequested:
            printf("status::trading session requested\n");
            break;
    case    IO2GSessionStatus::Connected:
            printf("status::connected\n");
            break;
    case    IO2GSessionStatus::Reconnecting:
            printf("status::reconnecting\n");
            break;
    case    IO2GSessionStatus::Disconnecting:
            printf("status::disconnecting\n");
            break;
    case    IO2GSessionStatus::SessionLost:
            printf("status::session lost\n");
            break;
    }
 
    if (status == IO2GSessionStatus::TradingSessionRequested)
    {
        IO2GSessionDescriptorCollection *descriptors = mSession->getTradingSessionDescriptors();
        bool found = false;
        if (descriptors != 0)
        {
            if (mPrintSubsessions)
                printf("descriptors available:\n");
            int i;
            for (i = 0; i < descriptors->size(); i++)
            {
                IO2GSessionDescriptor *descriptor = descriptors->get(i);
 
                if (mPrintSubsessions)
                    printf("  id:='%s' name='%s' description='%s' %s\n", descriptor->getID(), descriptor->getName(), descriptor->getDescription(), descriptor->requiresPin() ? "requires pin" : "");
 
                if (strcmp(mSubSessionID.c_str(), descriptor->getID()) == 0)
                    found = true;
 
                descriptor->release();
            }
            descriptors->release();
        }
        if (!found)
        {
            onLoginFailed("The specified sub session identifier is not found");
        }
        else
        {
            mSession->setTradingSession(mSubSessionID.c_str(), mPin.c_str());
        }
    }
    mStatusCode = status;
    uni::SetEvent(mEvent);
}
 
/** Get the session status. */
IO2GSessionStatus::O2GSessionStatus SessionStatusListener::getStatusCode() const
{
    return mStatusCode;
}
 
/** Check whether error happened. */
bool SessionStatusListener::wasError() const
{
    return mHasError;
}
 
/** Reset error information (use before login). */
void SessionStatusListener::resetError()
{
    mHasError = false;
    mError = "";
}
 
/** Get error. */
const char *SessionStatusListener::getError() const
{
    return mError.c_str();
}
 
HANDLE SessionStatusListener::getEvent() const
{
    return mEvent;
}
 
 responselistern.h
#include "../../../../../../include/ForexConnect.h"
 
 
/** Response listener class. */
class OfferCollection;
class Offer;
 
class ResponseListener : public IO2GResponseListener
{
 private:
    long mRefCount;
    /** Session object. */
    IO2GSession *mSession;
    /** Collection of the offers. */
    OfferCollection *mOffers;
 protected:
    /** Destructor. */
    virtual ~ResponseListener();
 
    /** Print offer to the console. */
    void printOffer(Offer *offer);
 
    /** Format date to print */
    void formatDate(DATE d, char *buf);
 
 public:
    ResponseListener(IO2GSession *session);
 
    /** Increase reference counter. */
    virtual long addRef();
 
    /** Decrease reference counter. */
    virtual long release();
 
    /** Request execution completed data handler. */
    virtual void onRequestCompleted(const char * requestId, IO2GResponse  *response = 0);
 
    /** Request execution failed data handler. */
    virtual void onRequestFailed(const char *requestId , const char *error);
 
    /** Request update data received data handler. */
    virtual void onTablesUpdates(IO2GResponse *data);
};
 
 responselistener.cpp
#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include <time.h>
#include <math.h>
#include "../../../../../../include/ForexConnect.h"
#include "offer.h"
#include "responselistener.h"
#include "sessionstatus.h"
 
ResponseListener::ResponseListener(IO2GSession *session)
{
    mSession = session;
    mSession->addRef();
    mOffers = new OfferCollection();
    mRefCount = 1;
}
 
ResponseListener::~ResponseListener()
{
    delete mOffers;
    mSession->release();
}
 
/** Increase reference counter. */
long ResponseListener::addRef()
{
    return InterlockedIncrement(&mRefCount);
}
 
/** Decrease reference counter. */
long ResponseListener::release()
{
    long rc = InterlockedDecrement(&mRefCount);
    if (rc == 0)
        delete this;
    return rc;
}
 
/** Request execution completed data handler. */
void ResponseListener::onRequestCompleted(const char *requestId, IO2GResponse  *response)
{
    if (response != 0)
    {
        if (response->getType() == GetOffers)
        {
            //process updates
            IO2GResponseReaderFactory *factory = mSession->getResponseReaderFactory();
            if (factory == 0)
                return;
 
            IO2GOffersTableResponseReader *offersReader = factory->createOffersTableReader(response);
            if (offersReader != 0)
            {
                mOffers->clear();
                int size = offersReader->size();
 
                for (int i = 0; i < size; i++)
                {
                    IO2GOfferRow *offer_row = offersReader->getRow(i);
                    const char *id = offer_row->getOfferID();
                    if (offer_row->isBidValid() && offer_row->isAskValid())
                    {
                        Offer *offer = new Offer(offer_row->getOfferID(), offer_row->getInstrument(),
                                             offer_row->getDigits(), offer_row->getPointSize(),
                                             offer_row->getTime(), offer_row->getBid(), offer_row->getAsk());
                        mOffers->addOffer(offer);
                        printOffer(offer);
                    }
                    offer_row->release();
                 }
                offersReader->release();
            }
            factory->release();
        }
    }
}
 
/** Request execution failed data handler. */
void ResponseListener::onRequestFailed(const char *requestId , const char *error)
{
    printf("Request %s failed:\n%s\n", requestId, error);
}
 
/** Request update data received data handler. */
void ResponseListener::onTablesUpdates(IO2GResponse *data)
{
    //process updates
    IO2GResponseReaderFactory *factory = mSession->getResponseReaderFactory();
    if (factory == 0)
        return;
 
    IO2GOffersTableResponseReader *offersReader = factory->createOffersTableReader(data);
    if (offersReader != 0)
    {
        int size = offersReader->size();
 
        for (int i = 0; i < size; i++)
        {
            IO2GOfferRow *offer_row = offersReader->getRow(i);
            const char *id = offer_row->getOfferID();
 
            Offer *offer = mOffers->findOfferForUpdate(id);
 
            if (offer != 0)
            {
                if (offer_row->isTimeValid() && offer_row->isBidValid() && offer_row->isAskValid())
                {
                    offer->setTime(offer_row->getTime());
                    offer->setBid(offer_row->getBid());
                    offer->setAsk(offer_row->getAsk());
                    printOffer(offer);
                }
            }
            offer_row->release();
        }
        offersReader->release();
    }
 
    factory->release();
}
 
/** Print offer to the console. */
void ResponseListener::printOffer(Offer *offer)
{
    char sbid[32], sask[32], stime[64];
    char format[32];
    sprintf(format, "%%.%if", offer->getPrecision());
    sprintf(sbid, format, offer->getBid());
    sprintf(sask, format, offer->getAsk());
    formatDate(offer->getTime(), stime);
    printf("%s %s bid:=%s ask:=%s\n", offer->getInstrument(), stime, sbid, sask);
}
 
/** Format date to print */
void ResponseListener::formatDate(DATE d, char *buf)
{
 
    struct tm t1;
    CO2GDateUtils::VariantTimeToUnixTime(d, &t1);
    sprintf(buf, "%04i/%02i/%02i %02i:%02i:%02i", t1.tm_year + 1900, t1.tm_mon + 1, t1.tm_mday, t1.tm_hour, t1.tm_min, t1.tm_sec);
}
 The second way to get offers in your C++ application is to use response listener.
In that case you should:
  Create a session, a session status listener, subscribe the status listener to the session status
(see this article).
 
  Implement the IO2GResponseListener interface
in  a response listener class:
class ResponseListener : public IO2GResponseListener{...}
 
  Create a response listener object: 
ResponseListener * responseListener = new ResponseListener(...);
Subscribe an object of this class to the session response:
pSession->subscribeResponse(responseListener);
 
  Log in (see this article).
 
  The events are coming asynchronously. They should come in another thread. When an event comes, a signal will be sent to the main thread.
 
  Use the function onSessionStatusChanged
of the session status listener to capture the Connected event.
 
  Get IO2GLoginRules:
IO2GLoginRules * loginRules = mSession->getLoginRules();
 
  Then you can get IO2GResponse:
IO2GResponse * response = loginRules->getTableRefreshResponse(Offers);
The response can be processed to extract necessary information.
 
  You should also capture IO2GResponse in the
onTablesUpdates
function of a response listener class.
 
  To get information from the "Offers" table from IO2GResponse:
1. Create IO2GResponseReaderFactory:
IO2GResponseReaderFactory * factory = mSession->getResponseReaderFactory();
2. Create IO2GOffersTableResponseReader:
IO2GOffersTableResponseReader * offersReader = factory->createOffersTableReader(response);
3. Process row by row:
for (int i = 0; i < offersReader->size(); i++)
{
      IO2GOfferRow * offer = offersReader->getRow(i);
      // Information like
      // offer->getInstrument(),
      // offer->getOfferID(),
      // offer->getBid(),
      // offer->getAsk(),
      // offer->getVolume()
      // can be extracted now.
}