2010-05-31 14 views
41

Otrzymuję ten dziwny błąd w niektórych rzeczach, z których korzystałem od dłuższego czasu. To może być coś nowego w Visual Studio 2010, ale nie jestem pewien.
Próbuję wywołać niezmienioną funkcję napisaną w C++ z C#.
Z tego co czytałem w internecie, a sam komunikat o błędzie nie ma to coś wspólnego z faktem, że podpis w moim pliku C# nie jest taki sam jak ten z C++, ale naprawdę nie mogę go zobaczyć.
Przede to wszystko jest moje unamanged funkcja poniżej:Wywołanie funkcji PInvoke "[...]" spowodowało asymetrię stosu

TEngine GCreateEngine(int width,int height,int depth,int deviceType); 

A oto moja funkcja w C#:

[DllImport("Engine.dll", EntryPoint = "GCreateEngine", CallingConvention = CallingConvention.StdCall)] 
     public static extern IntPtr CreateEngine(int width,int height,int depth,int device); 

Kiedy debugowania w C++ widzę wszystkie argumenty po prostu w porządku, tak więc mogę tylko myślę, że ma to coś wspólnego z transformacją z TEngine (która jest wskaźnikiem do klasy o nazwie CEngine) na IntPtr. Użyłem tego wcześniej w VS2008 bez problemu.

+0

Witam wszystkich, mam do czynienia z samym problemem, ale z Visual Studio 2013. Dodałem bezpośrednio odniesienie C++ dll do mojego projektu C#, który działał dobrze w 2010 roku, ale nie w 2013 roku. Wspomniałem również CallingConvention.Cdecl – Finisher001

Odpowiedz

20

Może problem leży w konwencji telefonicznej. Jesteś pewien, że funkcja niezarządzana została skompilowana jako stdcall, a nie coś innego (chyba zgadłbym fastcall)?

+0

Niestety, ale Naprawdę tego nie rozumiem. Skompilowałem dokładnie tak, jak powiedziałem na moje pytanie. Nie dodałem żadnego __std ani niczego w tym stylu. Zanim bez niego zadziałało bardzo dobrze. EDYCJA: ale teraz najwyraźniej dodanie __std w prototypie funkcji i deklaracja naprawia to. Dzięki – Sanctus2099

+0

Miałem ten dokładny problem - założyłem, że declspec (dllexport) zrobił je stdcall z jakiegoś powodu, ale tak nie było. Zmiana mojej konwencji wywoływania biblioteki DLL w celu jawnego określenia konwencji wywoływania (a następnie określenia w C# też) naprawiła mój problem. – ArtHare

2

W moim przypadku (VB 2010 i DLL skompilowany z Intelem Fortran 2011 XE) problem występuje, gdy moja aplikacja jest przeznaczona dla .NET Framework 4. Jeśli zmienię docelową strukturę na wersję 3.5, wszystko działa poprawnie zgodnie z oczekiwaniami. Więc przypuszczam powód jest coś wprowadzony w .NET Framework 4, ale nie mam pojęcia, który w tej chwili jeden

Aktualizacja: Problem został rozwiązany przez rekompilacji Fortran DLL i wyraźnie określając stdcall jako wywołanie konwencję nazw eksportowych w bibliotece DLL.

77

Posiadałem _cdecl C++ dll, który wywołałem bez żadnych problemów z Visual Studio 2008, a następnie identyczny kod w Visual Studio 2010 nie działałby. Mam to samo PInvoke ... również niesymetryczne błędy w stosie.

Rozwiązanie dla mnie było, aby określić konwencja wywołania w (...) atrybutu dllimport: Od:

[DllImport(CudaLibDir)] 

Do:

[DllImport(CudaLibDir, CallingConvention = CallingConvention.Cdecl)] 

myślę, że zmienił domyślnego powołanie konwencja dla DLLImport pomiędzy .NET 3.5 i .NET 4.0?

+0

Miałem ten sam problem i ta sugestia natychmiast go naprawiła. Dzięki Scott! (Microsoft - "Dodanie niepotrzebnej złożoności do twojej pracy od 1987 roku!") – user20493

+0

Naprawiłem również mój problem! Sława. :) – eandersson

+0

@ user20493: zobacz edytowaną odpowiedź Keitha. – mafu

46

Może się również zdarzyć, że w systemie .NET Framework w wersji 3.5 opcja pInvokeStackImbalance MDA jest domyślnie wyłączona. Poniżej 4.0 (lub może VS2010) jest to enabled by default.

Tak. Technicznie, kod był zawsze błędny, a poprzednie wersje architektury poprawiły go w milczeniu.

Cytując .NET Framework 4 Migration Issues document. „Aby poprawić wydajność w współdziałania z kodem niezarządzanym, nieprawidłowe wywołanie konwencje w A invoke platformie teraz spowodować, że aplikacja nie w poprzednich wersjach, warstwa Organizowanie rozwiązać te błędy górę stos ...Jeśli masz pliki binarne, których nie można zaktualizować, możesz dodać element do pliku konfiguracyjnego aplikacji, aby umożliwić wywoływanie błędów o wartości , które należy rozwiązać, tak jak we wcześniejszych wersjach. Jednak może to mieć wpływ na wydajność aplikacji.”

Łatwy sposób, aby naprawić to, aby określić konwencję telefonicznej i upewnij się, że jest taka sama jak w DLL a. __declspec(dllexport) powinny uzyskując cdecl Format.

[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl)] 
+0

dzięki. zadziałało –

4

użyć następującego kodu, jeśli mówią Twój DLL ma nazwę MyDLL.dll i chcesz korzystać z funkcji MyFunction w terminie DLL

[DllImport("MyDLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)] 
public static extern void MyFunction(); 

to działało dla mnie.

+2

Co tutaj robiłeś inaczej? Dlaczego rozwiązało problem? –