I use C++/CLI as middleware between my C++ game server and (future) C# plugins. It's supposed to load all types from the loaded assembly which implement a certain interface called IPlakScript
, construct them and return a native interface for them to the server, and it's doing exactly this, except for some reason casting the object to IPlakScript
fails with an InvalidCastException
. Here's my code:
C++/CLI code:
public interface class IPlakScript
{
public:
void OnScriptInit(Server^ server);
void OnScriptShutdown();
};
static IScript* LoadGamemodeM(String^ name)
{
try {
auto assembly = Assembly::LoadFrom(name);
auto types = assembly->GetTypes();
for each (auto t in types)
{
LogWrite("Found some class " + t->Module->FullyQualifiedName);
LogWrite("IPlakScript mdl " + IPlakScript::typeid->Module->FullyQualifiedName);
for each (auto i in t->GetInterfaces())
LogWrite("IMPLEMENTS: " + i->FullName);
for each (auto m in t->GetMembers())
LogWrite("MEMBER: " + m->Name + " " + m->MemberType.ToString());
if (t->GetInterface("PlakMP.IPlakScript")) // aka implements IPlakScript
{
LogWrite("Found gamemode class " + t->FullName);
Object^ obj = t->GetConstructor(gcnew cli::array<System::Type^, 1> {})->Invoke(gcnew cli::array<System::Object^, 1> {});
for each (auto m in t->GetMethods())
LogWrite("METHOD: " + m->Name);
IPlakScript^ ps = safe_cast<IPlakScript^>(obj); // the exception is thrown here, even though the exact same operation is perfectly fine in C#: why?
return new Script(ps);
//ps->OnScriptInit(gcnew PlakMP::Server(g_pScriptable));
}
}
}
catch (Exception^ e)
{
String^ description = "PSEsharp exception: " + e->ToString();
LogWrite(description);
}
return nullptr;
}
C# code:
using System;
using PlakMP;
namespace CSharpGamemodeTest
{
public class TestGamemode : IPlakScript
{
public TestGamemode()
{
Console.WriteLine("TestGamemode constructed");
if (this is IPlakScript) // evaluates to true, thus it's not a C# problem
Console.WriteLine("I'm PlakScript!");
}
public void OnScriptInit(Server server)
{
_server = server;
_server.LogWrite("Hello from C#!");
}
public void OnScriptShutdown()
{
_server.LogWrite("Goodbye from C#!");
}
private Server _server;
}
}
Log output:
[2020-05-07 09:34:43] Found some class E:\PlakMP\Sources\Release\plakscript\CSharpGamemodeTest.dll
[2020-05-07 09:34:43] IPlakScript mdl E:\PlakMP\Sources\Release\plakscript\PSEsharp.dll
[2020-05-07 09:34:43] IMPLEMENTS: PlakMP.IPlakScript
[2020-05-07 09:34:43] MEMBER: OnScriptInit Method
[2020-05-07 09:34:43] MEMBER: OnScriptShutdown Method
[2020-05-07 09:34:43] MEMBER: GetType Method
[2020-05-07 09:34:43] MEMBER: ToString Method
[2020-05-07 09:34:43] MEMBER: Equals Method
[2020-05-07 09:34:43] MEMBER: GetHashCode Method
[2020-05-07 09:34:43] MEMBER: .ctor Constructor
[2020-05-07 09:34:43] Found gamemode class CSharpGamemodeTest.TestGamemode
TestGamemode constructed
I'm PlakScript!
[2020-05-07 09:34:43] METHOD: OnScriptInit
[2020-05-07 09:34:43] METHOD: OnScriptShutdown
[2020-05-07 09:34:43] METHOD: GetType
[2020-05-07 09:34:43] METHOD: ToString
[2020-05-07 09:34:43] METHOD: Equals
[2020-05-07 09:34:43] METHOD: GetHashCode
[2020-05-07 09:34:43] PSEsharp exception: System.InvalidCastException: Unable to cast object of type 'CSharpGamemodeTest.TestGamemode' to type 'PlakMP.IPlakScript'.
at PSManagedWrapper.LoadGamemodeM(String name) in E:\PlakMP\Sources\PSEsharp\PSEsharp.cpp:line 123
Admittedly, the code is a quite disgusting mess: but hey - it's my first time working with C++/CLI! Any help would be greatly appreciated, thanks in advance.
Aucun commentaire:
Enregistrer un commentaire