He estado experimentando con delegados de C++/CLI (ya que estoy tratando de crear una biblioteca de referencia .NET), y he tenido el siguiente problema.Delegado de C++/CLI como puntero de función (System.AccessViolationException)
Defino un delegado en C++/CLI, y luego creo una instancia del delegado en C#, y luego invoco la instancia del delegado a través de un C++ no administrado mediante un puntero de función. Todo esto funciona como se esperaba.
Código para ilustrar esta (primera mi C#)
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);
}
}
}
Archivo siguiente mi manejado 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);
}
};
}
Y mi no administrado C++ archivo (Unmanaged.cpp)
#include "Unmanaged.hpp"
namespace Unmanaged
{
typedef void (*WriteMessageType)();
WriteMessageType WriteMessageFunc;
void WriteMessage(void* Function)
{
WriteMessageType WriteMessageFunc = (WriteMessageType)(Function);
WriteMessageFunc();
}
}
Este código funciona como se esperaba, y la salida es "1024", como el puntero de función llama al método() método de egate
Mi problema surge cuando trato de aplicar el mismo método con un delegado con argumentos, es decir: delegate void MessageDelegate (int number);
Mi código es ahora de la siguiente manera (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);
}
}
}
Mi archivo gestionado 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);
}
};
}
Y mi no administrado archivo de 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);
}
}
cuando ejecuto el programa me sale el siguiente error:
Se produjo una excepción no controlada del tipo 'System.AccessViolationException' en la biblioteca no administrada Test.dll
Información adicional: Intentó leer o escribir en la memoria protegida. Esto a menudo es una indicación de que otra memoria está corrupta.
Dicho sea de paso, la ventana de la consola muestra 1024, pero luego aparece un int aleatorio (~ 1000000), y luego aparece el error.
Puedo comenzar a imaginar algunas de las razones por las que recibo este error, pero no estoy seguro y estoy teniendo dificultades para descubrirlo. Si alguien pudiera decirme por qué recibo este error y qué podría hacer para solucionarlo, lo agradecería mucho.
+1 para una pregunta bien descrita –