У меня есть буфер, который я выделяю в C# и переходя к собственному коду. Я затем сохранить указатель на этот буфер:Использование управляемого буфера в нативном коде после вызова возвращает
Заголовок Определения
// called when a meter is attached
typedef void(__cdecl * lpfnMeterAttachCallback)();
extern lpfnMeterAttachCallback frMeterAttachCallback;
// called when a meter is detached
typedef void(__cdecl * lpfnMeterDetachCallback)();
extern lpfnMeterAttachCallback frMeterDetachCallback;
// called when a meter is detached
typedef void(__cdecl * lpfnMeterReadCompleteCallback)();
extern lpfnMeterReadCompleteCallback frMeterReadCompleteCallback;
extern char* frbuffer;
Main
lpfnMeterAttachCallback frMeterAttachCallback;
lpfnMeterDetachCallback frMeterDetachCallback;
lpfnMeterReadCompleteCallback frMeterReadCompleteCallback;
char* frbuffer;
extern "C" __declspec(dllexport) void __cdecl InitDriver(
lpfnMeterAttachCallback meterAttachCallback,
lpfnMeterDetachCallback meterDetachCallback,
lpfnMeterReadCompleteCallback meterReadCompleteCallback, char* buffer)
{
frMeterAttachCallback = meterAttachCallback;
frMeterDetachCallback = meterDetachCallback;
frMeterReadCompleteCallback = meterReadCompleteCallback;
frbuffer = buffer;
...
}
, а затем в фоновом режиме вызова, заполнить его, как так:
JSONValue testSS = ss->GetJSON();
std::string help = *testSS;
strcpy(frbuffer, help.c_str());
if (frMeterReadCompleteCallback) frMeterReadCompleteCallback();
Howeve r моя строка возвращается пустой или как поврежденные данные. В идеале я хотел, чтобы строка передавалась моему делегату, а затем использовала ее, но столкнулась с проблемами InterOp, пытаясь это сделать.
C#
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void InitDriver(MeterAttachCallback meterAttachCallback,
MeterDetachCallback meterDetachCallback,
MeterReadCompleteCallback meterReadCompleteCallback, StringBuilder sb);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MeterAttachCallback();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MeterDetachCallback();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void MeterReadCompleteCallback();
static public void OnMeterAttach()
{
Console.WriteLine("OnMeterAttach");
}
static public void OnMeterDetach()
{
Console.WriteLine("OnMeterDetach");
}
static StringBuilder sb = new StringBuilder(10 * 1024 * 1024); //10MB
static public void OnMeterReadComplete()
{
Console.WriteLine("OnMeterReadComplete; JSON:", sb.ToString());
}
static void Main(string[] args)
{
InitApolloCppDriver(OnMeterAttach, OnMeterDetach, OnMeterReadComplete, sb);
Console.ReadLine();
}
я пишу/чтение буфера неправильно, или я должен быть реализации этого по-другому?
Маршаллер в .NET будет хранить память, используемую 'sb' pinned (так что неуправляемый код может получить к ней доступ) в течение всего времени вызова InitEriver, так что это не сработает. Есть способы сделать это вручную, но это сложно. Передача строки в обратных вызовах выглядит лучше (и проще). Он будет работать, если вы получите правильную сортировку. – Chris
Вы не можете надеяться получить ссылку на эту память и ожидать, что она будет означать что-либо после функции, которая была передана ссылкой. Думаю об этом. Как управляемый код освобождает память, если он не знает, что неуправляемый код будет содержать ссылку на него. Вам нужно переосмыслить это. Начните с удаления буфера.Это бесполезно. –
Метод InitDriver постоянно запускается после вызова, действуя как сервер. Обратный вызов возникает, когда выполняется «сервер», используя буфер, переданный функции сначала, заполняя его, а затем вызывает обратный вызов в ожидании следующего запроса. –