Is it possible to get a return value from a QRemoteObject Dynamic Replica slot?

701 Views Asked by At

I am unable to call a slot returning a value on a QRemoteObjectDynamicReplica.

It seems that InvokeMethod on Replica doesn't support return value. I have only succeeded in calling void returning slots and even in this case, in DirectConnection mode, the invokeMethod finished before host slot invocation, so it seems that no host answer is in waiting.

I have a code like this which works perfectly on Host side, but not on Replica Side.

  bool success = QMetaObject::invokeMethod(_replica,"getName", Qt::DirectConnection,
      Q_RETURN_ARG(QString, retVal),
      Q_ARG(QString, "id")
   );

If i understand well the topic of REPC (i haven't try it yet), it seems that the calling of returning value slots is possible: Usage is to declare SLOT followed by the desired signature wrapped in parentheses. The return value can be included in the declaration. If the return value is skipped, void will be used in the generated files.

Do REPC do some kind of magic to allow this feature, or did i miss something ?

Thanks for help.

2

There are 2 best solutions below

2
Daes On BEST ANSWER

For those who are looking for an answer on this, there is a way :) : the

QRemoteObjectPendingCall

undocumented argument.

bool success = QMetaObject::invokeMethod(_replica,"getName",Qt::DirectConnection,
    Q_RETURN_ARG(QRemoteObjectPendingCall, call),
    Q_ARG(QString, "id")
 );
auto e = call.error();// , QRemoteObjectPendingCall::InvalidMessage);

call.waitForFinished();

//QVERIFY(call.isFinished());

qDebug() << QMetaType::typeName(call.returnValue().type());

QString retVal = call.returnValue().toString();

This is exactly the same kind a future object available for REPC Replica (except not templated) No Documentation but there is some example in : Qt Remote Objects integration tests

Sadly, there is currently (5.13.0) no way to get the pending reply in QML (QTBUG-77178) but Qt People are looking for it.

0
László Papp On

The accepted answer invokes the method with the wrong signature due to QRemoteObjectPendingCall. It should be QRemoteObjectPendingReply<T>. You would get something like this:

QMetaMethod::invokeMethod: return type mismatch for method FooReplica::getName(QString): cannot convert from QRemoteObjectPendingReply<QString> to QRemoteObjectPendingCall during invocation

This can actually be proven by printing the return value of the invocation.

qDebug() << success; -> false

This will print false rather than true since one is trying to invoke a method with the wrong signature as indicated by the internals of Qt.

This makes the author think that waitForFinished succeeded because it returned quickly without the 30 secs default timeout.

But it only returned quickly because there was nothing to wait for. If one prints out the return value of the waitForFinished call, one will see that it is actually false due to this rather true.

qDebug() << call.waitForFinished(); -> false

This will then generate a QVariant(Invalid), which for a QString will be simply an "empty string" (default value) rather than what was intended to be returned.

It took me quite a while to figure out, but I believe that we are all hitting this bug both in Qt 5 and Qt 6 on Windows, Linux and Mac, both with qmake and cmake, in my experiments.

https://lists.qt-project.org/pipermail/development/2023-October/044608.html

and

https://bugreports.qt.io/browse/QTBUG-94542

There is currently no fix for it at the time of writing this, but there is an async workaround without waiting:

QRemoteObjectPendingCallWatcher* watcher =
  new QRemoteObjectPendingCallWatcher(_replica->getName("id"));
connect(watcher, &QRemoteObjectPendingCallWatcher::finished,
  [](QRemoteObjectPendingCallWatcher* watch)
{ 
  qDebug << watcher->returnValue().toString();
});