Итак, у меня есть собственная сторонняя кодовая база C ++, с которой я работаю (файлы .lib и .hpp), которую я использовал для создания оболочки в C ++ / CLI для последующего использования в C #.
Я столкнулся с конкретной проблемой при переходе из режима отладки в режим выпуска, в которой я получаю исключение нарушения прав доступа при возврате кода обратного вызова.
Код из исходных hpp файлов для формата функции обратного вызова:
typedef int (*CallbackFunction) (void *inst, const void *data);
Код из оболочки C ++ / CLI для формата функции обратного вызова:
(Я объясню, почему я объявил два сразу)
public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
- Быстро, причина, по которой я объявил второй «UnManagedCallbackFunction», заключается в том, что я попытался создать «промежуточный» обратный вызов в оболочке, поэтому цепочка изменилась с Native C ++> C # на версию Native C ++> C ++ / CLI Wrapper> C # ... Полное раскрытие, проблема все еще существует, она только что была перенесена в C ++ / CLI Wrapper теперь в той же строке (возврат).
И, наконец, код сбоя из C #:
public static int hReceiveLogEvent(IntPtr pInstance, IntPtr pData)
{
Console.WriteLine("in hReceiveLogEvent...");
Console.WriteLine("pInstance: {0}", pInstance);
Console.WriteLine("pData: {0}", pData);
// provide object context for static member function
helloworld hw = (helloworld)GCHandle.FromIntPtr(pInstance).Target;
if (hw == null || pData == null)
{
Console.WriteLine("hReceiveLogEvent: received null instance pointer or null data\n");
return 0;
}
// typecast data to DataLogger object ptr
IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;
//Do Logging Stuff
Console.WriteLine("exiting hReceiveLogEvent...");
Console.WriteLine("pInstance: {0}", pInstance);
Console.WriteLine("pData: {0}", pData);
Console.WriteLine("Setting pData to zero...");
pData = IntPtr.Zero;
pInstance = IntPtr.Zero;
Console.WriteLine("pData: {0}", pData);
Console.WriteLine("pInstance: {0}", pInstance);
return 1;
}
Все записи в консоль завершены, и затем мы видим страшный сбой при возврате:
Необработанное исключение в 0x04d1004c в
helloworld.exe: 0xC0000005: Доступ
нарушение чтения местоположения 0x04d1004c.
Если я войду в отладчик отсюда, все, что я увижу, это то, что последняя запись в стеке вызовов:> "04d1004c ()", что приводит к десятичному значению: 80805964
Что интересно, только если вы посмотрите на консоль, которая показывает:
entering registerDataLogger
pointer to callback handle: 790848
fp for callback: 2631370
pointer to inst: 790844
in hReceiveLogEvent...
pInstance: 790844
pData: 80805964
exiting hReceiveLogEvent...
pInstance: 790844
pData: 80805964
Setting pData to zero...
pData: 0
pInstance: 0
Теперь я знаю, что между отладкой и выпуском некоторые вещи в мире Microsoft совершенно разные. Меня, конечно, беспокоит заполнение байтов и инициализация переменных, поэтому, если я что-то здесь не предоставлю, просто дайте мне знать, и я добавлю (уже давно) сообщение. Я также думаю, что управляемый код, возможно, НЕ освобождает всех владельцев, а затем нативная часть C ++ (для которой у меня нет кода) может пытаться удалить или уничтожить объект pData, что приводит к сбою приложения.
Более полное раскрытие, все работает нормально (на первый взгляд) в режиме отладки!
Настоящая проблема с царапинами на голове, которая будет признательна за любую помощь!