GCF LOGO VCL LOGO
Using IPC in your applications

The IPC module in GCF makes it possible for you to host objects in your application for communication with other applications AND to invoke methods on objects in other applications. In the following paragraphs we explain how certain key communication scenarios work.

Enabling IPC communication with your application

To allow incoming IPC communication, you should create an instance of GCF::IpcServer and have it listen for incoming requests.

if( server.listen() )
// Listening for incoming requests

GCF::IpcServer is a subclass of QTcpServer. The GCF::IpcServer::listen() method basically creates a server socket and listens for incoming socket connection requests. Every connection request received at this socket will be ackowledged and responded.

An application can have any-number of instances of GCF::IpcServer created. Each server should listen on a different port. You can implement your own mechanisms to publish the availablility of servers and communicate that information to client-GCF applications. You can also make use of GCF::IpcServerDiscovery to discover servers in the Local Area Network.

"Exposing" objects for IPC communication

Any object in your application can be made available for IPC communication

  • adding the object to the object tree (GCF::ApplicationServices::objectTree()), if the object has not already been added to it.
  • setting the allowmetaaccess key to true against the information key=value map of the object.

The following code snippet shows you how

class MyClass : public QObject
{
Q_OBJECT
public:
// ...
Q_INVOKABLE GCF::Result method1(const QVariant &p1, const QVariant &p2, ...)
// ...
};
MyClass *obj = new MyClass(gApp);
QVariantMap objInfo;
objInfo["allowmetaaccess"] = true;
new GCF::ObjectTreeNode(gAppService->objectTree()->rootNode(), "MyService", obj, objInfo);
// Now methods on obj can be invoked from other applications.

To mark objects for remote access in the content file, you can

<content>
....
....
<object name="..." allowMetaAccess="true" />
....
....
</content>

Service method rules

Public invokable (signal, slot and Q_INVOKABLE) methods in a "exposed" object can be remotely invoked by other applications. Such methods are called "service methods". Service methods have to adhere to the following rules

  • Method name must be unabiguous. No two service methods must have the same name, even though C++ allows for method overloading.
  • Method parameters can be of type: int, bool, double, QString, QStringList, QVariant, QVariantList, QVariantMap or QByteArray. All other types must be represented in terms of these types. NOTE: Custom types can be registered using qRegisterMetaType and their streaming operators can be registered using qRegisterMetaTypeStreamOperators. Such types can be accepted as QVariant. Example:
    struct MyType { ... };
    // Register the type
    qRegisterMetaType<MyType>("MyType");
    // Register streaming operators for the type
    QDataStream &operator<<(QDataStream &out, const MyType &myObj) { ... }
    QDataStream &operator>>(QDataStream &in, MyType &myObj) { ... }
    qRegisterMetaTypeStreamOperators<MyType>("MyType");
    class MyClass : public QObject
    {
    Q_OBJECT
    public:
    // ...
    Q_INVOKABLE GCF::Result serviceMethod(const QVariant& arg) {
    MyType type = arg.value<MyType>();
    return this->method(type);
    }
    GCF::Result method(const MyType &type) { ... }
    // ...
    };
  • Return types can be void, int, bool, double, QString, QStringList, QVariant, QVariantList, QVariantMap, QByteArray or GCF::Result.
  • Methods should return fast. They should never consume more than 60 seconds of clock time. If they do take longer than that, then callers should be made aware of that and they should adjust their call timeout using GCF::IpcCall::setTimeoutDuration().

Invoking service methods

To invoke a service method, you can make use of the GCF::IpcCall class. One instance of this class can be used to make only one service call. Example:

QHostAddress addr = ...;
quint16 port = ...;
GCF::IpcCall *call = new GCF::IpcCall(addr, port, "Application.MyService",
"method1", QVariantList() << ... << ...);
connect(call, SIGNAL(done(bool)), ..., SLOT(callDone(bool)));
void abcd::callDone(bool val) {
GCF::IpcCall *call = qobject_cast<GCF::IpcCall *>(this->sender());
if(val) {
QVariant result = call->result();
} else {
QString errMsg = call->errorMessage();
// Display errMsg
}
}

The GCF::IpcCall class always works in asynchronous mode. To use the class in blocking mode you can make use of the GCF::IpcCall::waitForDone() method on the call object. This method waits for the call to complete before it returns. The function returns true if the call was successful, false otherwise. NOTE: the waitForDone() method waits for a 10 seconds (or a value set using GCF::IpcCall::setTimeoutDuration()). Example:

QHostAddress addr = ...;
quint16 port = ...;
GCF::IpcCall *call = new GCF::IpcCall(addr, port, "Application.MyService",
"method1", QVariantList() << ... << ...);
if( call->waitForDone() ) {
QVariant result = call->result();
} else {
QString errMsg = call->errorMessage();
// Display errMsg
}

Signal/Slot connections across applications

You can make use of GCF::IpcRemoteObject to maintain a persistent connection with a remote object. Signal/Slot connections can be made between GCF::IpcRemoteObject and any other object in the application to

  • connect signal from a local object to a member (signal or slot) in a remote object
  • connect signal from the remote object to a member (signal or slot) in a local object

In addition to remote-signal/slot connections, GCF::IpcRemoteObject can be used to fetch properties of the remote object and also invoke methods on the remote object.

The following code snippet shows you how to create an instance of GCF::IpcRemoteObject and prepare to use it.

GCF::IpcRemoteObject *remoteObj = new GCF::IpcRemoteObject(addr, port, "Application.MyService");
// Wait for the object to get activated
GCF::SignalSpy spy(remoteObj, SIGNAL(activated()));
spy.wait();
if( remoteObj->isActivated() ) {
// Connection to the remote object is now activated
}

You can make use of the GCF::ipcConnect() methods to make signal/slot connections between a local object and remote object. Example:

GCF::IpcRemoteObject *remoteApp = new GCF::IpcRemoteObject(addr, port, "Application");
// Wait for the object to get activated
GCF::SignalSpy spy(remoteApp, SIGNAL(activated()));
spy.wait();
// When a local button is clicked, we want the remoteApp to quit.
QPushButton *quitButton = ...;
GCF::ipcConnect(quitButton, SIGNAL(clicked()), remoteApp, SLOT(quit()));

Discovering remote servers

You can use GCF::IpcServerDiscovery class to discover address and port numbers of GCF::IpcServer objects in GCF applications running on the local-area-network. The following example shows how GCF::IpcServerDiscovery can be used in your applications

quint port = 55001;
discovery.start(port);
// GCF::IpcServerDiscovery emits a foundServer() signal whenever it detects the
// presense of a new server.
See Also
GCF::IpcServer
GCF::IpcCall
GCF::IpcRemoteObject
GCF::IpcServerDiscovery
GCF::ipcConnect
TicTacToe - Example application for GCF's IPC module.
Communique - Example application for GCF's IPC module.