Здравствуйте, сообщество Stackoverflow!
Я пытаюсь взаимодействовать в программе на C # с очень старой DLL, написанной на C ++, и сталкиваюсь с очень большой проблемой:
Моя C ++ DLL предоставляет метод getPlugin со следующей подписью:
extern "C" Plugin* getPlugin();
с определением Plugin:
virtual void onLoad(Service* service) = 0;
virtual const char *getDescription()const = 0;
Определение класса Service:
virtual void getLongValueConf(const char *section, const char*key,long *output_value ) = 0;
реализация метода getDescription
:
const char* MyClass::getDescription() const
{
static char buffer[512];
sprintf(buffer, "FOO");
return loc_tc_buffer;
}
реализацияметод onLoad
, вызывающий метод getLongValueConf
:
void MyClass::onLoad(Service* service)
{
_service = service;
_service->getLongValueConf("FOO", "BAR",(long*) &_value);
}
Итак, я реализую в своей программе на C #:
СтатическийОболочка, содержащая точку входа:
public static class Wrapper
{
[DllImport("MyCppDll.dll", EntryPoint= "getPlugin", CallingConvention= CallingConvention.StdCall, CharSet= CharSet.Ansi, BestFitMapping= false, ThrowOnUnmappableChar= true)]
public static extern IntPtr getPlugin();
}
Реализация класса Plugin, который содержит структуру, соответствующую vtable:
public class Plugin
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void onLoadCb(IntPtr service);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate IntPtr getDescriptionCb();
[StructLayout(LayoutKind.Sequential)]
public struct PluginVtbl
{
public IntPtr onLoad;
public IntPtr getDescription;
}
}
Реализация класса Service
public class Service
{
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void getLongValueConf(char[] section, char[] key, ref int output_value);
[StructLayout(LayoutKind.Sequential)]
public struct ServiceVtbl
{
public IntPtr getLongValueConf;
}
}
Внутренний класс для вызова методов onLoad и getDescription:
public static class Loader
{
private static IntPtr serverPointer;
private static IntPtr vtable;
private static PluginVtbl handle;
private static IntPtr servicePointer;
public static void Load(ServiceVtbl service)
{
serverPointer = SSI_getServerPlugin();
vtable = Marshal.ReadIntPtr(serverPointer, 0);
handle = (PluginVtbl)Marshal.PtrToStructure(vtable, typeof(PluginVtbl));
onLoadCb func = (onLoadCb)Marshal.GetDelegateForFunctionPointer(handle.onLoad, typeof(onLoadCb));
servicePointer = new IntPtr();
int size = Marshal.SizeOf(typeof(ServiceVtbl));
servicePointer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(service, servicePointer, false);
func(servicePointer);
}
public static string GetDescription()
{
serverPointer = SSI_getServerPlugin();
vtable = Marshal.ReadIntPtr(serverPointer, 0);
handle = (PluginVtbl)Marshal.PtrToStructure(vtable, typeof(PluginVtbl));
getDescriptionCb func = (getDescriptionCb)Marshal.GetDelegateForFunctionPointer(handle.getDescription, typeof(getDescriptionCb));
IntPtr pointerTemp = func();
return Marshal.PtrToStringAnsi(pointerTemp);
}
}
И затем, моя программная реализация:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Server.GetDescription());
ServiceVtbl table = new ServiceVtbl();
getLongValueConf delgetLongValueConf = new getLongValueConf(getLongValueConf);
table.getLongValueConf = Marshal.GetFunctionPointerForDelegate(delgetLongValueConf);
Server.Load(table);
}
static void getLongValueConf(char[] section, char[] key, ref int output_value)
{
Console.WriteLine("{0} {1}", section, key);
}
}
Когда я вызываю Console.WriteLine(Server.GetDescription());
, мой вывод 'FOO'.Но у меня есть AccesViolationException, когда я вызываю Server.onLoad
метод.Поэтому я решил проверить адреса разных указателей и заметил, что servicePointer
в моем коде C # не имеет тот же адрес, что и указатель service
в коде C ++.
Есть ли у кого-нибудьрешение?
РЕДАКТИРОВАТЬ: трассировка стека
void Main (строковые аргументы [])
.Server.Load (таблица)
..func (servicePointer)
... void MyClass :: onLoad (Сервис * сервис) Сторона CPP
...._ service-> getLongValueConf ("FOO", "BAR", (long *) & _value) Нарушение доступа
Спасибо!
Оливье.