Mam więc macierzystą bazę kodu C++ innej firmy, z którą pracuję (pliki .lib i .hpp), której użyłem do zbudowania wrappera w C++/CLI do ewentualnego użycia w języku C#.Dostęp do wyjątku naruszenia/awarii z wywołania zwrotnego C++ do funkcji C#
Wystąpił szczególny problem podczas przełączania z trybu debugowania do wydania, ponieważ otrzymuję wyjątek naruszenia dostępu po zwróceniu kodu wywołania zwrotnego.
Kod z oryginalnych plików HPP dla formatu funkcja zwrotna:
typedef int (*CallbackFunction) (void *inst, const void *data);
kod z C++/CLI otoki dla formatu funkcja zwrotna: (Wytłumaczę dlaczego oświadczyłem dwa chwilę)
public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);
--Quickly, powodem oświadczyłem drugi „UnManagedCallbackFunction” jest to, że starałem się stworzyć „pośrednik” wywołania zwrotnego w opakowaniu jednostkowym, więc łańcuch zmieniono z macierzystym C++> C# w wersji Native C++> C++/CLI Wrapper> C# ... Pełny opis Problem nadal występuje, został on właśnie przeniesiony do Owijarki C++/CLI w tej samej linii (powrót).
I wreszcie, kod upaść z 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;
}
Wszystko pisze do konsoli to zrobić i wtedy widzimy bał awarii na zwrot:
nieobsługiwany wyjątek w 0x04d1004c w helloworld.exe: 0xC0000005: Access naruszenie lokalizacji odczytu 0x04d1004c.
Gdybym krok do debuggera stąd, wszystko co widzę to, że ostatni wpis na stos wywołań to:> „04d1004c()”, które ocenia na wartość dziesiętną: 80805964
Która jest tylko ciekawe, jeśli spojrzeć na konsoli, która pokazuje:
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
teraz wiem, że między debugowania i uwalniania niektóre rzeczy są zupełnie inne w świecie Microsoft. Oczywiście obawiam się dopełnienia bajtów i inicjalizacji zmiennych, więc jeśli jest coś, czego tu nie dostarczam, daj mi znać, a dodam do (już długiego) postu. Sądzę też, że zarządzany kod NIE może zwalniać całego prawa własności, a następnie natywne elementy C++ (do których nie mam kodu) mogą próbować usunąć lub zabić obiekt pData, powodując awarię aplikacji.
Pełniejsze ujawnienie, wszystko działa dobrze (pozornie) w trybie debugowania!
Prawdziwy problem z drapaniem głowy, który doceni każdą pomoc!
Dla wsparcia było to w większości przypadków poprawne. Po skontaktowaniu się z zewnętrznym dostawcą, dowiedzieliśmy się, że zostały skompilowane przy użyciu specyfikacji CDecl, a nie standardowego kodu wymaganego dla zgodności z kodami zarządzanymi: http://msdn.microsoft.com/en-us/library/367eeye0%28VS.80%29.aspx . Dodałem pytanie dotyczące StackOverflow, aby zapytać, dlaczego tak musi być? Mamy nadzieję, że ktoś da lepsze wyjaśnienie niż cytowany artykuł MSDN. – TomO
W ustawieniach projektu jest domyślna konwencja wywołująca (C/C++), jeśli nie została określona przez __declspec(). Ta konwencja wywoływania nie była widoczna w kodzie. Co dzieje się z niedopasowanymi konwencjami jest jasne: jeśli odpowiedzialność za czyszczenie stosów nie jest zgodna, miażdży stos (nie resetuje się do stanu sprzed połączenia z powodu podwójnego oczyszczenia lub zbyt małej ilości). To zależy od ilości argumentów przekazywanych na stosie. http://en.wikipedia.org/wiki/Calling_convention – jdehaan