C++ 如何使用本机更改托管对象的私有成员?
C++ how to change private members of managed object using a native one?
我正在做一个学生项目。这是一个网络卡牌游戏。该解决方案包含 3 个项目。客户端的 GUI 使用 Windows 表单,因此它管理了 classes。本机 C++ 中的静态客户端库。 GUI 的项目引用了它,因此使用 'Mixed Rules'。服务器也是原生 C++。我使用 RPC 中间件进行通信。它仅适用于本机 C++。这就是为什么我需要静态库来隐藏客户端通信的所有细节。
由于服务器可以随时更改其状态并且应该在客户端的 GUI 中显示,因此我使用回调方法来更改 Windows 表单的组件。在这里我发现了一个问题,因为我需要借助本机对象更改 managed class 的私有成员。
可能有不同的方法可以做到这一点。我的想法是将指向托管 class 实例的指针发送到本机 class 实例并将其保存在那里。因此,稍后我可以从该托管 class 的本机对象 public 成员函数调用来更改组件。
这是我的 'Mixed Rules' GUI 项目:
//Native class for changing window 'Lobby'
class LobbyI : public ClientLib::Lobby {
public:
LobbyI();
~LobbyI();
//Should change window due to current Server's state
void reDraw(const CommonLogic::ServerState&);
};
// Managed class implements GUI for window 'Lobby'
// generated by Visual Studio designer
public ref class LobbyGUI : public System::Windows::Forms::Form {
//My members
ClientLib::Mediator* mediatorPtr; // Is it correct?
LobbyI* lobbyPtr; // ?
public:
LobbyGUI(void) {
InitializeComponent();
mediatorPtr = new ClientLib::Mediator(); // Is it correct?
lobbyPtr = new LobbyI(); // ?
mediatorPtr->setCallback(lobbyPtr);
}
protected:
~LobbyGUI() {
if (components) { delete components; }
delete lobbyPtr; // Is it correct?
lobbyPtr = nullptr; // ?
delete mediatorPtr; // ?
mediatorPtr = nullptr; // ?
}
private: System::Windows::Forms::Button^ buttonLogIn;
//...
这是来自原生静态库ClientLib:
class Lobby {
public:
virtual ~Lobby();
virtual void reDraw(const CommonLogic::ServerState&) = 0;
};
class Mediator {
CommonLogic::ServerState serverState;
Lobby* lobbyPtr;
public:
Mediator();
~Mediator();
void setCallback(Lobby* ptr) { lobbyPtr = ptr; }
void reDrawLobby() { lobbyPtr->reDraw(serverState); }
};
此代码构建正常。我现在唯一需要的是原生派生classLobbyI的成员函数reDraw()能够改变window 由托管 class LobbyGUI 实施。从而获取并保留和使用指向它的指针。然后我认为这一切都会奏效。怎么做?
也许它通常不是最好的实现。我很乐意阅读其他建议。
我也怀疑我在托管 class 中使用指向本机 classes 的指针的方式。这是对的吗?直到我在析构函数中的 delete ptr;
之后插入 ptr=nullptr;
后,它才正常工作。
更新: 现在我发现代码中存在冗余。摘要class大堂没用。我只需要在托管 class 中实现 reDraw() 函数,这显然可以访问 window 的组件。然后将安全指针传递给本机 class 函数,该函数需要指向函数的指针作为参数。
终于解决了!!使用 this article。在下面的代码中,本机对象存储提供的指向托管对象函数的指针。所以这个回调函数可以随时调用。 delegate 用作类型安全函数指针的一种形式。 GCHandle 的实例用于防止委托被垃圾收集器重新定位。
这是一个简单的 CLR 控制台应用程序,它使用从本机对象调用的回调函数递增并打印一些整数。因此我们可以 "change private members of managed object using a native one".
using namespace System;
using namespace System::Runtime::InteropServices;
typedef void(__stdcall *ANSWERCB)(); // define type of callback function
#pragma unmanaged
class NativeClass {
ANSWERCB cbFuncPtr = 0; // pointer to callback function
public:
void setCallback(ANSWERCB fptr) {
cbFuncPtr = fptr;
incAndPrint();
}
void incAndPrint() { cbFuncPtr(); } // invokes callback which increments and prints
};
#pragma managed
ref class ManagedClass {
public: delegate void Del();
private:
Int32 i;
NativeClass* nativePtr;
Del^ delHandle;
GCHandle gch;
public:
ManagedClass(Int32 ii) : i(ii) {
nativePtr = new NativeClass;
delHandle = gcnew Del(this, &ManagedClass::changeAndPrintInt);
gch = GCHandle::Alloc(delHandle);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(delHandle);
ANSWERCB callbackPtr = static_cast<ANSWERCB>(ip.ToPointer());
nativePtr->setCallback(callbackPtr);
}
~ManagedClass() {
delete nativePtr;
nativePtr = __nullptr;
gch.Free();
}
private:
void changeAndPrintInt() // callback function
{
Console::WriteLine(++i);
}
};
int main(array<System::String ^> ^args)
{
ManagedClass mc(1);
return 0;
}
我正在做一个学生项目。这是一个网络卡牌游戏。该解决方案包含 3 个项目。客户端的 GUI 使用 Windows 表单,因此它管理了 classes。本机 C++ 中的静态客户端库。 GUI 的项目引用了它,因此使用 'Mixed Rules'。服务器也是原生 C++。我使用 RPC 中间件进行通信。它仅适用于本机 C++。这就是为什么我需要静态库来隐藏客户端通信的所有细节。
由于服务器可以随时更改其状态并且应该在客户端的 GUI 中显示,因此我使用回调方法来更改 Windows 表单的组件。在这里我发现了一个问题,因为我需要借助本机对象更改 managed class 的私有成员。
可能有不同的方法可以做到这一点。我的想法是将指向托管 class 实例的指针发送到本机 class 实例并将其保存在那里。因此,稍后我可以从该托管 class 的本机对象 public 成员函数调用来更改组件。
这是我的 'Mixed Rules' GUI 项目:
//Native class for changing window 'Lobby'
class LobbyI : public ClientLib::Lobby {
public:
LobbyI();
~LobbyI();
//Should change window due to current Server's state
void reDraw(const CommonLogic::ServerState&);
};
// Managed class implements GUI for window 'Lobby'
// generated by Visual Studio designer
public ref class LobbyGUI : public System::Windows::Forms::Form {
//My members
ClientLib::Mediator* mediatorPtr; // Is it correct?
LobbyI* lobbyPtr; // ?
public:
LobbyGUI(void) {
InitializeComponent();
mediatorPtr = new ClientLib::Mediator(); // Is it correct?
lobbyPtr = new LobbyI(); // ?
mediatorPtr->setCallback(lobbyPtr);
}
protected:
~LobbyGUI() {
if (components) { delete components; }
delete lobbyPtr; // Is it correct?
lobbyPtr = nullptr; // ?
delete mediatorPtr; // ?
mediatorPtr = nullptr; // ?
}
private: System::Windows::Forms::Button^ buttonLogIn;
//...
这是来自原生静态库ClientLib:
class Lobby {
public:
virtual ~Lobby();
virtual void reDraw(const CommonLogic::ServerState&) = 0;
};
class Mediator {
CommonLogic::ServerState serverState;
Lobby* lobbyPtr;
public:
Mediator();
~Mediator();
void setCallback(Lobby* ptr) { lobbyPtr = ptr; }
void reDrawLobby() { lobbyPtr->reDraw(serverState); }
};
此代码构建正常。我现在唯一需要的是原生派生classLobbyI的成员函数reDraw()能够改变window 由托管 class LobbyGUI 实施。从而获取并保留和使用指向它的指针。然后我认为这一切都会奏效。怎么做?
也许它通常不是最好的实现。我很乐意阅读其他建议。
我也怀疑我在托管 class 中使用指向本机 classes 的指针的方式。这是对的吗?直到我在析构函数中的 delete ptr;
之后插入 ptr=nullptr;
后,它才正常工作。
更新: 现在我发现代码中存在冗余。摘要class大堂没用。我只需要在托管 class 中实现 reDraw() 函数,这显然可以访问 window 的组件。然后将安全指针传递给本机 class 函数,该函数需要指向函数的指针作为参数。
终于解决了!!使用 this article。在下面的代码中,本机对象存储提供的指向托管对象函数的指针。所以这个回调函数可以随时调用。 delegate 用作类型安全函数指针的一种形式。 GCHandle 的实例用于防止委托被垃圾收集器重新定位。
这是一个简单的 CLR 控制台应用程序,它使用从本机对象调用的回调函数递增并打印一些整数。因此我们可以 "change private members of managed object using a native one".
using namespace System;
using namespace System::Runtime::InteropServices;
typedef void(__stdcall *ANSWERCB)(); // define type of callback function
#pragma unmanaged
class NativeClass {
ANSWERCB cbFuncPtr = 0; // pointer to callback function
public:
void setCallback(ANSWERCB fptr) {
cbFuncPtr = fptr;
incAndPrint();
}
void incAndPrint() { cbFuncPtr(); } // invokes callback which increments and prints
};
#pragma managed
ref class ManagedClass {
public: delegate void Del();
private:
Int32 i;
NativeClass* nativePtr;
Del^ delHandle;
GCHandle gch;
public:
ManagedClass(Int32 ii) : i(ii) {
nativePtr = new NativeClass;
delHandle = gcnew Del(this, &ManagedClass::changeAndPrintInt);
gch = GCHandle::Alloc(delHandle);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(delHandle);
ANSWERCB callbackPtr = static_cast<ANSWERCB>(ip.ToPointer());
nativePtr->setCallback(callbackPtr);
}
~ManagedClass() {
delete nativePtr;
nativePtr = __nullptr;
gch.Free();
}
private:
void changeAndPrintInt() // callback function
{
Console::WriteLine(++i);
}
};
int main(array<System::String ^> ^args)
{
ManagedClass mc(1);
return 0;
}