I have a QT application which is written in c and c++. I tried to call a CPP function from C file. When I tried to call my callback function with a qpushbutton from UI, It works but when I tried to call my callback function in the main, It does not work correctly. What is the problem according to the below codes? Thx.
mainwindow.cpp
void MainWindow::on_pushButton_clicked()
{
QUrl url;
url.setScheme("ftp");
url.setHost("192.168.1.2");
url.setUserName("ftpadmin");
url.setPassword("password");
url.setPath("");
FtpUploadManager *mFtpManager = new FtpUploadManager(url);
mFtpManager->addFile("/home/user/Desktop/a.txt");
}
fileanalyzer.cpp
static inline void notify_ftp_manager(void *user,char* FileName)
{
FileAnalyzer* _this = (FileAnalyzer*)(user);
QString abc = QString(FileName);
_this->m_FtpManager->addFile(abc);
}
FileAnalyzer::FileAnalyzer(QString path, QString prefix)
{
QUrl url;
url.setScheme("ftp");
url.setHost("192.168.1.2");
url.setUserName("ftpadmin");
url.setPassword("password");
url.setPath("");
m_FtpManager = new FtpUploadManager(url, this);
set_ftp_callback_function(notify_ftp_manager, this);
}
fileanalyzer.h
class FileAnalyzer: public QObject
{
Q_OBJECT
public:
FtpUploadManager *m_FtpManager ;
}
callbackfunction.c
CALLBACKFUNCTION ftp_callback;
void *ftp_callback_user;
void callbackfunction()
{
if(ftp_callback != NULL && ftp_callback_user != NULL)
{
ftp_callback(ftp_callback_user,"a.txt");
}
}
void set_ftp_callback_function(CALLBACKFUNCTION callbackfnc, void* ftp_callback_caller_user)
{
ftp_callback = callbackfnc;
ftp_callback_user = ftp_callback_caller_user;
}
int main()
{
callbackfunction();
}
callbackfunction.h
typedef void (*CALLBACKFUNCTION)(void *user,char* fileName);
void set_ftp_callback_function(CALLBACKFUNCTION callbackfnc, void* ftp_callback_caller_user);
I think the code didn't work because of the static method which I wrote for the callback function. When I changed the static function to class function, It worked! But I still don't know why static method did not work.
Related
I have a multiplatform kotlin project generating a shared library for mingwx64. Once I have generated the DLL, I have incorporated it into a C++ project and now i need to call a function that takes the implementation of an interface as a parameter, but I have no idea how to get it.
I attach example code to explain it:
//Kotlin Multiplatform code
interface InitializationEvents {
fun onComplete()
fun onError(error: String)
}
class MyClass {
fun initialize(succeed: Boolean, listener: InitializationEvents) {
if(succeed)
listener.onComplete()
else
listener.onError("Error description")
}
}
It generates a header file like this:
//libnative.h
typedef {
...
/* User functions. */
struct {
struct {
struct {
libnative_KType* (*_type)(void);
void (*onComplete)(libnative_kref_InitializationEvents thiz);
void (*onError)(libnative_kref_InitializationEvents thiz, const char* error);
} InitializationEvents;
struct {
libnative_KType* (*_type)(void);
libnative_kref_MyClass (*MyClass)();
void (*initialize)(libnative_kref_MyClass thiz, libnative_KBoolean succeed, libnative_kref_InitializationEvents listener);
} MyClass;
} root;
} kotlin;
} libnative_ExportedSymbols;
extern libnative_ExportedSymbols* libnative_symbols(void);
And now I'm using this Cpp code:
// Demo.cpp
int main()
{
libnative_ExportedSymbols* lib = libnative_symbols();
libnative_kref_MyClass myClass = lib->kotlin.root.MyClass.MyClass();
//I guess I have to do something here... 😅
libnative_kref_InitializationEvents listener = { .pinned = NULL };
lib->kotlin.root.MyClass.initialize(myClass, true, listener);
}
void myOnComplete() { }
void myOnError(const char* error) { }
It would need to be able to receive the call to the myOnComplete and myOnError functions as desired by the library.
Thank you very much.
I'm working on a simple wrapper for a IPC lib we are using.
I want to convert the events from this lib to calls on Qt slots.
Right now i have something like this:
void Caller::registerCallback(int id, QObject* reciever, const char* member)
{
_callbackMap[id] = std::make_pair(reciever, QString(member));
}
bool Caller::call(const SomeData data)
{
auto reciever = _callbackMap.value(data.id);
return QMetaObject::invokeMethod(reciever.first, reciever.second.toLocal8Bit(), Qt::QueuedConnection,
QGenericReturnArgument(),
Q_ARG(SomeData, data));
}
void Receiver::someCallback(SomeData data)
{
qDebug() << data.str;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Caller caller;
Receiver reciever;
caller.registerCallback(1, &reciever, "someCallback");
caller.call(SomeData({ "Hi", 1 }));
return a.exec();
}
struct SomeData {
QString str;
int id;
}; Q_DECLARE_METATYPE(SomeData);
This works quite well. But I don't like to register the callbacks as strings. I would prefer a compile time checking with a syntax like this:
caller.registerCallback(1, &reciever, &Reciever::someCallback);
I am aware of this implementation.
The slots I want to register always have exactly one argument and no return value.
I already found this request what could solve my problem but unfortunately this was never implemented.
Also this question doesn't help me as I'm not able to patch the moc we are using.
So is this really not possible with all the meta magic Qt is using?
EDIT:
I found a solution that works also when the Caller dose not know about the Receiver (what is actually what I need):
//Caller.h
class Caller : public QObject
{
Q_OBJECT
public:
Caller(QObject *parent = nullptr);
~Caller();
//void registerCallback(int id, QObject* reciever, const char *member);
template < class R, typename Func >
void inline registerCallback(int id, R reciever, Func callback)
{
using std::placeholders::_1;
registerCallbackImpl(id, reciever, std::bind(callback, reciever, _1));
};
bool call(const SomeData);
private:
QMap<int, std::pair<QObject *, std::function<void(SomeData)>> > _callbackMap;
void registerCallbackImpl(int id, QObject* reciever, std::function<void(SomeData)> callback);
};
//Caller.cpp
void Caller::registerCallbackImpl(int id, QObject* reciever, std::function<void(SomeData)> callback)
{
_callbackMap[id] = std::make_pair(reciever, callback);
}
bool Caller::call(const SomeData data)
{
auto reciever = _callbackMap.value(data.id).first;
auto fn = _callbackMap.value(data.id).second;
QMetaObject::invokeMethod(reciever, [reciever, fn, data]() {
std::invoke(fn, data);
fn(data);
}, Qt::QueuedConnection);
return true;
}
//main.cpp
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Caller caller;
Receiver reciever;
using std::placeholders::_1;
caller.registerCallback(2, &reciever, &Receiver::someCallback);
caller.call(SomeData({ "Hi2", 2 }));
return a.exec();
}
This soulution relies upon std::invoke and lambda.
Variant 1: use std::invoke directly instead of QMetaObject::invoke
Variant 2: use std::invoke inside a lambda, which is passed to QMetaObject::invoke
Variant 3: use MACRO instead of std::invoke in variant 2.
If you use QMetaObject::invoke you've got an option to choose connection type - Direct or Queued. In variant 1 the call is invoked immediately like in direct connection.
receiver.h
#ifndef RECEIVER_H
#define RECEIVER_H
#include <QObject>
#include <QDebug>
struct SomeData {
QString str;
int id;
};
//Q_DECLARE_METATYPE(SomeData);
class Receiver : public QObject
{
Q_OBJECT
public:
explicit Receiver(QObject *parent = nullptr) : QObject(parent) {}
void doSmth(SomeData data) {
qDebug() << data.str;
}
signals:
};
#endif // RECEIVER_H
caller.h
#ifndef CALLER_H
#define CALLER_H
#include <QObject>
#include <QMap>
#include <utility>
#include <map>
#include "receiver.h"
#define CALL_MEMBER_FN(object,ptrToMember) ((object)->*(ptrToMember))
typedef void (Receiver::*callback)(SomeData);
class Caller : public QObject
{
Q_OBJECT
public:
explicit Caller(QObject *parent = nullptr) : QObject(parent) { }
void registerCallback(int id, Receiver* receiver, callback c)
{
auto pair = std::make_pair(receiver, c);
_callbackMap.emplace(id, pair);
}
bool call(const SomeData data)
{
auto &receiver = _callbackMap.at(data.id);
return QMetaObject::invokeMethod(receiver.first, [data, receiver] () {
// method 1
std::invoke(receiver.second, receiver.first, data);
// method 2 (better not to use a MACRO)
CALL_MEMBER_FN(receiver.first, receiver.second)(data);
}, Qt::QueuedConnection);
}
bool call_invoke(const SomeData data)
{
auto &receiver = _callbackMap.at(data.id);
std::invoke(receiver.second, receiver.first, data);
return true;
}
signals:
private:
std::map<int,std::pair<Receiver*,callback>> _callbackMap;
};
#endif // CALLER_H
main.cpp
#include <QCoreApplication>
#include "receiver.h"
#include "caller.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Caller caller;
Receiver reciever;
caller.registerCallback(1, &reciever, &Receiver::doSmth);
caller.registerCallback(2, &reciever, &Receiver::doSmth);
caller.call(SomeData({ "Hi", 1 }));
caller.call_invoke(SomeData({ "Hi2", 2 }));
return a.exec();
}
An alternative approach might be to use a suitable std::function to capture the callback and then make use of QTimer::singleShot with a zero timeout to invoke the callback in the correct context.
struct SomeData {
QString str;
int id;
};
class Caller {
public:
using task = std::function<void(SomeData)>;
void registerCallback (int id, QObject *receiver, task t)
{
_callbackMap[id] = std::make_pair(receiver, t);
}
bool call (SomeData data)
{
auto receiver = _callbackMap.value(data.id);
QTimer::singleShot(0, receiver.first, [=](){ receiver.second(data); });
return true;
}
private:
QMap<int, std::pair<QObject *, task>> _callbackMap;
};
class Receiver: public QObject {
public:
void someCallback (SomeData data)
{
qDebug() << data.str;
}
};
Then use as...
Caller caller;
Receiver receiver;
caller.registerCallback(1, &receiver, [&](SomeData d){ receiver.someCallback(d); });
caller.call(SomeData({ "Hi", 1 }));
I really don't know what's the problem. I know that i'm using the correct instance because I set this class as a context, and even better, the handler is invoked. I also pass the arguments to the c++ signal by value.
what is the problem and how to solve it?
main.cpp
websocket_session sess;
rootContext->setContextProperty("websocketSession", &sess);
const QUrl url(QStringLiteral("qrc:/main.qml"));
main.qml
Connections {
target: websocketSession;
onLoginResponseProcessed: {
console.log(logged_in, role)
}
}
websocket_session.hpp
class websocket_session : public QObject
{
Q_OBJECT
QWebSocket websocket_;
char *buffer_;
QString url_;
bool autoConnect_;
bool rememberMe_;
QString username_;
QString password_;
public:
explicit websocket_session(QObject *parent = nullptr);
~websocket_session();
Q_INVOKABLE void send(const control_messages::Request &req);
Q_INVOKABLE void init(const QString &url, const QString &username, const QString &password);
void process_message(const std::string &data);
//Messages
Q_INVOKABLE void login(const QString &username, const QString &password);
private slots:
void onConnected();
void onDisconnected();
void onTextMessageReceived(const QString &message);
void onError();
signals:
void loginResponseProcessed(bool logged_in, RoleWrapper::Role role);
void error(const QString &error);
};
RoleWrapper.h
#ifndef ROLEWRAPPER_H
#define ROLEWRAPPER_H
#include <QObject>
namespace RoleWrapper
{
Q_NAMESPACE
enum Role {
USER,
ADMIN
};
Q_ENUM_NS(Role)
}
#endif // ROLEWRAPPER_H
I saw this thread that says it's a bug: Qml - c++ signal parameters "undefined" in qml
main.qml prints:
qml: undefined undefined
If the problem is indeed a bug then how can I overcome this problem?
UPDATE
this is the code that emits the signal:
websocket_session.cpp
case LOGIN: {
LoginResponse loginResponse;
payload.UnpackTo(&loginResponse);
auto logged_in = loginResponse.loggedin();
auto role = static_cast<RoleWrapper::Role>(loginResponse.role());
std::cout << "logged_in: " << logged_in << ", role: " << loginResponse.role() << role << Role_Name(loginResponse.role()) << std::endl;
emit loginResponseProcessed(logged_in, role);
break;
}
You have to register the type:
qRegisterMetaType<RoleWrapper::Role>();
please I need your help, I googled a lot and any answer for this problem....
I have a solution that includes various Unmanaged C++ projects, but now I need to use a Visual C++ Form (that is Managed) into the main unmanaged project, and comunicate with it.
It's possible to do it? via wrapper, dll.... how?
I googled a lot but all the cases I found talk about how use Unmanaged into Managed, or are incomplete examples. I found this example and seems that it works, but doesn't compile.
http://www.codeproject.com/Articles/9903/Calling-Managed-Code-from-Unmanaged-Code-and-vice
I'm using Visual Studio 2012.
Thanks a lot.
Finally I found a solution...
1 - When I want to have the FORM control into non managed code (for create, show, hide, set controls value...) I exported static methods as __declspec(dllexport)
2 - When I want to send info from FORM to non managed code I do it using callbacks.
I'm going to explain it....
Firstly... I create a CLR project as DLL, create a windows Form (MyForm.h) with some controls:
1 exit button
1 button that SEND info TO NON MANAGED code
and 1 checkbox that RECEIVE new status FROM NON MANAGED code
(I ommit the gode generated by visual studio)
namespace TestUnmanaged {
... code ommitted ...
private: System::Void QuitBtn_Click(System::Object^ sender, System::EventArgs^ e) {
this->Close();
}
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
//Call to non managed function!!!!
CallToCallBack();
}
};
}
Then, I create a static (non managed) class that has a pointer to the form, and manage it's creation, etc..
//Type of my specific callback function
typedef std::function<bool (int& _msg)> T_CALLBACK_FUNC;
public class unmanagedClass
{
public:
unmanagedClass();
~unmanagedClass();
void CreateForm( void );
HWND getFormHandle(void) const;
void setCallbackFunction(T_CALLBACK_FUNC _callbackFuntion);
void callToCallbackFunction(int _value);
//public for fast tests
gcroot<TestUnmanaged::MyForm^> p;
private:
HWND m_hWnd;
T_CALLBACK_FUNC m_funcionCallback;
};
unmanagedClass s_unmanaged;
Here's the .cpp implementation...
//////////////////////////////////////////////////////////////////////////
// Static Functions for DLL_EXPORT
//////////////////////////////////////////////////////////////////////////
void CloseForm( void )
{
Application::Exit();
}
void CallToCallBack( void )
{
int valor = 5;
s_unmanaged.callToCallbackFunction(valor);
}
//////////////////////////////////////////////////////////////////////////
// Methods for Unmanaged Class
//////////////////////////////////////////////////////////////////////////
HWND unmanagedClass::getFormHandle( void ) const
{
return m_hWnd;
}
unmanagedClass::unmanagedClass()
{
p = gcnew(TestUnmanaged::MyForm);
}
unmanagedClass::~unmanagedClass()
{
delete (p);
}
void unmanagedClass::CreateForm( void )
{
Application::Run(p);
}
void unmanagedClass::setCallbackFunction( T_CALLBACK_FUNC _callbackFuntion )
{
m_funcionCallback = _callbackFuntion;
}
void unmanagedClass::callToCallbackFunction( int _value )
{
m_funcionCallback(_value);
}
Now, I create all the static functions that will be exported as dllexport:
__declspec(dllexport) void CreateFormDLL(void)
{
s_unmanaged.CreateForm();
}
__declspec(dllexport) void CloseFormDLL(void)
{
s_unmanaged.p->Close();
}
__declspec(dllexport) void ShowFormDLL(void)
{
s_unmanaged.p->Show();
}
__declspec(dllexport) void HideFormDLL(void)
{
s_unmanaged.p->Hide();
}
__declspec (dllexport) void setCallbackFunctionDLL( T_CALLBACK_FUNC& _doFunction)
{
s_unmanaged.setCallbackFunction(_doFunction);
}
__declspec (dllexport) void setCheckBoxDLL( bool _newValue )
{
s_unmanaged.p->getCam01ChkBox()->Checked = _newValue;
}
__declspec (dllexport) HWND getFormHandleDLL( void )
{
return (HWND)s_unmanaged.p->Handle.ToPointer();
}
Now.... I create the Win32 console App project and link the Managed project. This will be the main process, and the class "ManagedWrapper". Here is the source....
class ManagedWrapper
{
public:
ManagedWrapper(void);
~ManagedWrapper(void);
void init(void);
void createForm(void);
void showForm(void);
void closeForm(void);
void setCam01ChkBox(const bool _newValue);
private:
void createFormThread(void);
static bool callBackReceiver(int a);
};
#include "ManagedWrapper.h"
#include <thread>
__declspec(dllimport) void CreateFormDLL(void);
__declspec(dllimport) void CloseFormDLL(void);
__declspec(dllimport) void ShowFormDLL(void);
__declspec(dllimport) void HideFormDLL(void);
typedef std::function<bool (int& _msg)> T_CALLBACK_FUNC;
__declspec (dllimport) void setCallbackFunctionDLL( T_CALLBACK_FUNC& _doFunction);
__declspec (dllimport) void setCheckBoxDLL( bool _newValue );
ManagedWrapper::ManagedWrapper(void)
{
}
ManagedWrapper::~ManagedWrapper(void)
{
}
void ManagedWrapper::createForm( void )
{
std::thread showThread (&ManagedWrapper::createFormThread, this);
showThread.detach();
}
void ManagedWrapper::createFormThread( void )
{
CreateFormDLL();
}
void ManagedWrapper::closeForm( void )
{
CloseFormDLL();
}
void ManagedWrapper::showForm( void )
{
ShowFormDLL();
}
void ManagedWrapper::init( void )
{
setCallbackFunctionDLL(T_CALLBACK_FUNC(&ManagedWrapper::callBackReceiver));
}
bool ManagedWrapper::callBackReceiver( int a )
{
printf("Hello world. Parameter value = %d\n",a);
return true;
}
void ManagedWrapper::setCam01ChkBox( const bool _newValue )
{
setCheckBoxDLL( _newValue );
}
And finally.... the simplest use from the main(), create the Form, set the checkbox values, if the user click on the button the callback function writes on console... and finally close.
int _tmain(int argc, _TCHAR* argv[])
{
ManagedWrapper umWrap;
umWrap.init();
umWrap.createForm();
system("PAUSE");
umWrap.setCam01ChkBox(true);
system("PAUSE");
umWrap.setCam01ChkBox(false);
system("PAUSE");
umWrap.closeForm();
return 0;
}
Sorry for the long answer, but I believe that may be usefull for somebody.
I am very new to C++.
I have a class, and I want to create a thread inside a class's function. And that thread(function) will call and access the class function and variable as well.
At the beginning I tried to use Pthread, but only work outside a class, if I want to access the class function/variable I got an out of scope error.
I take a look at Boost/thread but it is not desirable because of I don't want to add any other library to my files(for other reason).
I did some research and cannot find any useful answers.
Please give some examples to guide me. Thank you so much!
Attempt using pthread(but I dont know how to deal with the situation I stated above):
#include <pthread.h>
void* print(void* data)
{
std::cout << *((std::string*)data) << "\n";
return NULL; // We could return data here if we wanted to
}
int main()
{
std::string message = "Hello, pthreads!";
pthread_t threadHandle;
pthread_create(&threadHandle, NULL, &print, &message);
// Wait for the thread to finish, then exit
pthread_join(threadHandle, NULL);
return 0;
}
You can pass a static member function to a pthread, and an instance of an object as its argument. The idiom goes something like this:
class Parallel
{
private:
pthread_t thread;
static void * staticEntryPoint(void * c);
void entryPoint();
public:
void start();
};
void Parallel::start()
{
pthread_create(&thread, NULL, Parallel::staticEntryPoint, this);
}
void * Parallel::staticEntryPoint(void * c)
{
((Parallel *) c)->entryPoint();
return NULL;
}
void Parallel::entryPoint()
{
// thread body
}
This is a pthread example. You can probably adapt it to use a std::thread without much difficulty.
#include <thread>
#include <string>
#include <iostream>
class Class
{
public:
Class(const std::string& s) : m_data(s) { }
~Class() { m_thread.join(); }
void runThread() { m_thread = std::thread(&Class::print, this); }
private:
std::string m_data;
std::thread m_thread;
void print() const { std::cout << m_data << '\n'; }
};
int main()
{
Class c("Hello, world!");
c.runThread();
}