[英]How to call a c++ function with byte* and int* parameters from C# through a CLI/C++ wrapper
[英]How to write wrapper classes for mapping Qt Signals to C# events (through C++/CLI)
通過C ++ / CLI包裝器調用C ++ / Qt類就像在公園散步一樣。
但我堅持將C ++ / Qt信號映射到C#事件。
我試圖結合一些可用的how-tos / answers但沒有得到任何工作結果:
這里的問題是,這些方法/答案是相當陳舊的。 我目前正在使用Qt5.5(很快5.6)和.NET 4.6。 我試圖使一切都適應當前的技術水平但可能失敗了。
可能是因為樹木太多而無法看到森林,所以我想問一個能夠用當前框架版本完成任務的工作示例,這樣我就可以發現差異並從錯誤中吸取教訓。
[edit]您可以查看此github倉庫,以獲取此來源。 QtSignal到C#事件的部分已注釋掉,以使此代碼處於工作狀態。
Github回購: https : //github.com/qwc/QtSignalToCSharpEvent
對於那些仍然想要閱讀所有內容而不玩游戲的人...繼續閱讀...這里是我當前的非工作代碼:
所以我有一個純Qt5課程
#ifndef PUREQT_H
#define PUREQT_H
#include <QObject>
#include <QString>
#include "PureQt_global.h"
class PUREQTSHARED_EXPORT PureQt : public QObject {
Q_OBJECT
public:
PureQt(QString name);
~PureQt(){}
QString getSomeVar();
void someFunc(const QString & string);
public slots:
signals:
void someFuncWasCalled(const QString &string);
private:
QString someVar;
};
#endif // PUREQT_H
通過以下相當簡單的實現:
#include "PureQt.h"
PureQt::PureQt(QString name) {
this->someVar = "ctor("+name+")";
}
QString PureQt::getSomeVar() {
return this->someVar;
}
void PureQt::someFunc(const QString &string) {
this->someVar += "someFunc("+string+")";
emit someFuncWasCalled(this->someVar);
}
然后我用C ++ / CLI實現了一個托管包裝器,以便能夠從C#調用非托管代碼。 請注意,我已經嘗試添加代碼以獲取事件管理信號。
#pragma once
#include "conversion.h"
#include "../pureqt/PureQt.h"
#include "SignalProxy.h"
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
namespace ManagedCppQtSpace {
// different variants... from tinkering around.
delegate void someFuncWasCalled(String^);
delegate void someFuncWasCalledU(QString str);
[StructLayoutAttribute(LayoutKind::Sequential)]
public ref struct DelegateWrapper {
[MarshalAsAttribute(UnmanagedType::FunctionPtr)]
someFuncWasCalledU^ delegate;
};
public ref class ManagedCppQt
{
public:
ManagedCppQt(String^ name){
pureQtObject = new PureQt(StringToQString(name));
proxy = new SignalProxy(pureQtObject);
wrapper = gcnew DelegateWrapper();
wrapper->delegate = gcnew someFuncWasCalledU(this, ManagedCppQt::signalCallback);
signalCallbackProxy callbackproxy;
Marshal::StructureToPtr(wrapper, callbackproxy, false); // currently im stuck here with a compile error, but the problem may lie somewhere else...
proxy->setCallback(callbackproxy);
};
~ManagedCppQt(){
delete pureQtObject;
};
event someFuncWasCalled ^ someFuncCalled;
void someFunc(String^ string){
pureQtObject->someFunc(StringToQString(string));
};
String^ getSomeString() {
return QStringToString(pureQtObject->getSomeVar());
}
void signalCallback(QString str) {
someFuncCalled(QStringToString(str));
}
DelegateWrapper ^ wrapper;
private:
PureQt * pureQtObject;
SignalProxy * proxy;
};
}
因此,為了將來自Qt的信號和槽處理與能夠在托管代碼中引發事件的回調鏈接,當沒有更改基本代碼的選項時,某些將需要代理類(因為它也用於其他非托管C ++項目)。
#ifndef SIGNALPROXY_H
#define SIGNALPROXY_H
#include <QObject>
#include "../pureqt/PureQt.h"
typedef void (*signalCallbackProxy) (QString str);
class SignalProxy : public QObject
{
Q_OBJECT
public:
explicit SignalProxy(PureQt* pqt);
~SignalProxy();
void setCallback(signalCallbackProxy callback);
signals:
public slots:
void someFuncSlot(QString str);
private:
PureQt* pureQt;
signalCallbackProxy scallback;
};
#endif // SIGNALPROXY_H
實施:
#include "SignalProxy.h"
SignalProxy::SignalProxy(PureQt* pqt){
pureQt = pqt;
this->connect(pureQt, SIGNAL(PureQt::someFuncWasCalled(QString)), this, SLOT(someFuncSlot(QString)));
}
SignalProxy::~SignalProxy()
{}
void SignalProxy::setCallback(signalCallbackProxy callback){
this->scallback = callback;
}
void SignalProxy::someFuncSlot(QString str){
if(this->scallback != NULL)
this->scallback(str);
}
所以。 現在,如何正確地鏈接這兩個世界,Qt信號 - >托管.NET事件?
我也嘗試了一些簡單的方法,這會導致編譯錯誤,例如:
QObject::connect(pureQtObject, &PureQt::someFuncWasCalled, &MangagedCppQtSpace::ManagedCppQt::signalCallback);
而不是代理類,或使用lambda函數:
QObject::connect(pureQtObject, &PureQt::someFuncWasCalled, [] (QString str) {
signalCallback(str);// or ManagedCppQt::signalCallback, but for this the method has to be static, and it isn't possible to raise events from static methods...
}
這里的問題是將Qt與C ++ CLI混合使用。 要獲得功能信號和插槽,您需要處理頭文件以生成自己的元數據。 問題是該工具將無法理解C ++ CLI功能。
要首先解決此問題,您必須回退到C ++接口,並執行安全的C ++ CLI操作。
所以你需要像這樣的額外類,它不知道.net並創建標准C ++的橋梁:
class PureQtReceiverDelegate { // this should go to separate header file
virtual void NotifySomeFunc(const char *utf8) = 0;
};
class PureQtReceiver : public QObject {
Q_OBJECT
public:
PureQtReceiver(PureQtReceiverDelegate *delegate, PureQt *parent)
: QObject(parent)
, mDelegate(delegate)
{
bool ok = connect(parent, SIGNAL(PureQt::someFuncWasCalled(QString)),
this, SLOT(someFuncReceiver(QString)));
Q_ASSERT(ok);
}
public slots:
void someFuncReceiver(const QString & string)
{
delegate->NotifySomeFunc(string.toUtf8().data());
}
private:
PureQtReceiverDelegate *delegate;
};
現在,您的C ++ CLI類應實現此PureQtReceiverDelegate
,並將字符串轉換為.net版本並發布通知。
請注意,您可以/應該在C ++ CLI頭文件中轉發聲明Qt特定的類。
如果你使用Qt 5並且有可用的C ++ 11,那么有更方便的解決方案:你可以在連接到QObject時使用lambda表達式。 所以你的ManagedCppQt
看起來像這樣:
標題:
#include "../pureqt/PureQt.h"
using namespace ManagedCppQtSpace;
ManagedCppQt:ManagedCppQt(String^ name) {
pureQtObject = new PureQt(QStringFromString(name));
QObject::connect(pureQtObject, &PureQt::someFuncWasCalled,
[this](const QString &string){
if (this->someFuncCalled) {
String^ s = StringFromQString(string);
this->someFuncCalled(s);
}
});
}
ManagedCppQt::~ManagedCppQt(){
delete pureQtObject;
}
在cpp:
#include "../pureqt/PureQt.h" using namespace ManagedCppQtSpace; ManagedCppQt:ManagedCppQt(String^ name) { pureQtObject = new PureQt(QStringFromString(name)); QObject::connect(pureQtObject, &PureQt::someFuncWasCalled, [this](const QString &string){ if (this->someFuncCalled) { String^ s = StringFromQString(string); this->someFuncCalled(s); } }); } ManagedCppQt::~ManagedCppQt(){ delete pureQtObject; }
這更容易,更快速,更容易維護。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.