Ho sperimentato con delegati C++/CLI (come sto cercando di creare una libreria di riferimento .NET) e ho riscontrato il seguente problema.C++/CLI delegato come puntatore di funzione (System.AccessViolationException)
Definisco un delegato in C++/CLI, quindi creo un'istanza del delegato in C# e quindi richiamo l'istanza del delegato tramite C++ non gestito tramite un puntatore a funzione. Tutto funziona come previsto.
Codice per illustrare
using System;
namespace TestProgram
{
class Program
{
static void Main(string[] args)
{
Library.Test.MessageDelegate messageDelegate = new Library.Test.MessageDelegate(Message);
Library.Test test = new Library.Test(messageDelegate);
test.WriteMessage();
Console.Read();
}
static void Message()
{
Console.WriteLine(1024);
}
}
}
Successivo file di mio Managed C++ (Managed.cpp)
#include "Unmanaged.hpp"
#include <string>
namespace Library
{
using namespace System;
using namespace System::Runtime::InteropServices;
public ref class Test
{
public:
delegate void MessageDelegate();
internal:
MessageDelegate^ Message;
void* delegatePointer;
public:
Test(MessageDelegate^ messageDelegate)
{
delegatePointer = (void*)Marshal::GetFunctionPointerForDelegate(messageDelegate).ToPointer();
}
void WriteMessage()
{
Unmanaged::WriteMessage(delegatePointer);
}
};
}
E la mia non gestito C++ di file (Unmanaged.cpp) questo (prima il mio C#)
#include "Unmanaged.hpp"
namespace Unmanaged
{
typedef void (*WriteMessageType)();
WriteMessageType WriteMessageFunc;
void WriteMessage(void* Function)
{
WriteMessageType WriteMessageFunc = (WriteMessageType)(Function);
WriteMessageFunc();
}
}
Questo codice funziona come previsto e l'output è "1024", poiché Method() viene chiamato dal puntatore alla funzione del metodo di esempio.
Il mio problema sorge quando provo ad applicare lo stesso metodo con un delegato con argomenti, ovvero: delegate void MessageDelegate (int number);
Il mio codice è ora la seguente (C#):
using System;
namespace AddProgram
{
class Program
{
static void Main(string[] args)
{
Library.Test.MessageDelegate messageDelegate = new Library.Test.MessageDelegate(Message);
Library.Test test = new Library.Test(messageDelegate);
test.WriteMessage(1024);
Console.Read();
}
static void Message(int number)
{
Console.WriteLine(number);
}
}
}
mio gestito di file C++:
#include "Unmanaged.hpp"
#include <string>
namespace Library
{
using namespace System;
using namespace System::Runtime::InteropServices;
public ref class Test
{
public:
delegate void MessageDelegate(int number);
internal:
MessageDelegate^ Message;
void* delegatePointer;
public:
Test(MessageDelegate^ messageDelegate)
{
delegatePointer = (void*)Marshal::GetFunctionPointerForDelegate(messageDelegate).ToPointer();
}
void WriteMessage(int number)
{
Unmanaged::WriteMessage(delegatePointer, number);
}
};
}
E la mia non gestito di file C++:
#include "Unmanaged.hpp"
namespace Unmanaged
{
typedef void (*WriteMessageType)(int number);
WriteMessageType WriteMessageFunc;
void WriteMessage(void* Function, int number)
{
WriteMessageType WriteMessageFunc = (WriteMessageType)(Function);
WriteMessageFunc(number);
}
}
Quando ho eseguire il programma ottengo il seguente errore:
Un'eccezione non gestita di tipo 'System.AccessViolationException' si è verificata nella libreria Unmanaged Test.dll
Ulteriori informazioni: Tentativo di leggere o scrivere memoria protetta. Questo è spesso un'indicazione che un'altra memoria è corrotta.
Per inciso, la finestra della console mostra 1024, ma è seguita da un int casuale (~ 1000000), quindi viene visualizzato l'errore.
Posso iniziare ad immaginare alcuni dei motivi per cui ho riscontrato questo errore, ma non sono sicuro e sto avendo difficoltà a scoprirlo. Se qualcuno potesse dirmi perché sto ricevendo questo errore e cosa potrei fare per risolverlo, lo apprezzerei molto.
+1 per una domanda ben descritta –