pinvokestackimbalance - làm cách nào để khắc phục hoặc tắt nó đi?


76

Tôi vừa chuyển sang vs2010 từ vs2008. Chính xác cùng một giải pháp, ngoại trừ bây giờ mỗi lệnh gọi đến một dll C ++ đều mang lại một ngoại lệ 'pinvokestackimbalance'.

Ngoại lệ này không bị loại bỏ vào năm 2008. Tôi có toàn quyền truy cập vào C ++ dll và ứng dụng gọi điện. Dường như không có bất kỳ vấn đề nào với chân cắm, nhưng vấn đề này khiến việc gỡ lỗi các vấn đề khác là không thể; IDE liên tục dừng lại để nói với tôi về những điều này.

Ví dụ, đây là chữ ký C #:

    [DllImport("ImageOperations.dll")]
    static extern void FasterFunction(
        [MarshalAs(UnmanagedType.LPArray)]ushort[] inImage, //IntPtr inImage, 
        [MarshalAs(UnmanagedType.LPArray)]byte[] outImage, //IntPtr outImage, 
        int inTotalSize, int inWindow, int inLevel);

Đây là những gì nó trông như thế nào ở phía C ++:

#ifdef OPERATIONS_EXPORTS
#define OPERATIONS_API __declspec(dllexport)
#else
#define OPERATIONS_API __declspec(dllimport)
#endif
extern "C" {


OPERATIONS_API void __cdecl FasterFunction(unsigned short* inArray, 
                                       unsigned char* outRemappedImage,
                                       int inTotalSize, 
                                       int inWindow, int inLevel);

}

Điều gì khác biệt giữa vs2010 và vs2008 có thể khiến các ngoại lệ này bị loại bỏ? Tôi có nên thêm một bộ tham số khác vào chỉ thị DllImport không?

Câu trả lời:


146

Trước tiên, hãy hiểu rằng mã sai (và luôn luôn như vậy). "PInvokeStackImbalance" không phải là một ngoại lệ, mà là một trợ lý gỡ lỗi được quản lý. Theo mặc định, nó đã bị tắt trong VS2008, nhưng nhiều người không bật nó, vì vậy nó được bật theo mặc định trong VS2010. MDA không chạy ở chế độ Phát hành, vì vậy nó sẽ không kích hoạt nếu bạn xây dựng để phát hành.

Trong trường hợp của bạn, quy ước gọi điện không chính xác. DllImportmặc định thành CallingConvention.WinApi, giống với CallingConvention.StdCallmã máy tính để bàn x86. Nó nên được CallingConvention.Cdecl.

Điều này có thể được thực hiện bằng cách chỉnh sửa dòng [DllImport("ImageOperations.dll")]thành:

[DllImport("ImageOperations.dll", CallingConvention = CallingConvention.Cdecl)]

Để biết thêm thông tin, hãy xem tài liệu tham khảo MSDN này


Cảm ơn! Các trường hợp ngoại lệ chắc chắn đã ngừng bắn. Có thể điều này sẽ giải quyết một số vấn đề ổn định lâu dài mà chúng tôi đang gặp phải.
mmr

4
Hoàn toàn có thể. Loại mất cân bằng ngăn xếp cụ thể này thực sự hơi phổ biến; nó không gây ra bất kỳ lỗi nào ngay lập tức nhưng sẽ từ từ tiêu thụ ngăn xếp của luồng. Cuối cùng, "những điều tồi tệ" sẽ xảy ra. CLR là thường có thể nâng cao một StackOverflowException, nhưng using, catchfinallykhối điều thực sự phức tạp khi ngăn xếp đầy. Vì lý do này, bắt đầu trong .NET 2.0, a StackOverflowExceptionsẽ chỉ kết thúc quá trình.
Stephen Cleary

Thông tin thêm về quy ước gọi tương tác tại đây .
Drew Noakes

Tuyệt vời, điều này đã chỉ cho tôi đúng hướng sau khi cố gắng cập nhật một số dự án lên .Net 4.0. Sau khi thay đổi quy ước gọi trong nguồn C # thành Cdecl, sau đó tôi phải thực hiện thay đổi đối với các tệp * .h và * .c của chúng tôi để sử dụng '__cdecl`.
IAbstract

Cảm ơn bạn! Phản hồi này đã lưu trong ngày. Trong trường hợp của tôi, sự cố phát sinh từ việc tham chiếu đến DLL Visual C ++ 8.0 (Visual Studio 2008) trong dự án Visual Studio 2010.
Schrockwell

45

Để tắt nó đi:

  1. CTRL + ALT + E
  2. Trong "Hỗ trợ gỡ lỗi được quản lý", bỏ chọn PInvokeStackImbalance.

3
Không bao giờ, không bao giờ , không bao giờ bắn người đưa tin. Sự mất cân bằng ngăn xếp sẽ ăn gan của bạn, với đậu fava, sớm hay muộn.
Hans Passant

8

Tốt hơn để giải quyết vấn đề này, nó không khó lắm ở đây tôi đang đề cập đến một số phương pháp, nó có thể giống như một số người bạn của tôi đã đề cập ở trên. Tôi đang làm việc với PCSC một ứng dụng Smartcard mà tôi đã sử dụng khoảng một tuần, rất khó chịu vì đã có rất nhiều thay đổi cuối cùng đã có giải pháp.

Đối với tôi công việc của nó với Phần mở rộng PInvoke mà tôi đã cài đặt cho VS2010, bạn có thể tải xuống tại đây http://www.red-gate.com/products/dotnet-development/pinvoke/

Tải xuống và cài đặt nó, Đóng visual studio và mở lại, bạn có thể tìm thấy tiện ích mở rộng tại Menu Bar. nhập mô tả hình ảnh ở đây

Nếu lỗi là do chữ ký không khớp, bạn chỉ cần nhấp vào PInvoke.net> Chèn chữ ký PInvoke

Cửa sổ mới sẽ xuất hiện như bên dưới nhập mô tả hình ảnh ở đây

Nhập tên của dll và nhấp vào tìm kiếm, bạn có thể thấy tất cả các chức năng của dll đó trong cửa sổ kết quả tìm kiếm, Nhấp vào chức năng bạn sẽ nhận được chữ ký cho Chức năng cụ thể đó.

Sử dụng chữ ký đó và bạn cần sửa đổi các chương trình của mình theo Chữ ký đó, Chủ yếu là Kiểu dữ liệu.

Điều này giải quyết vấn đề của tôi, bạn có thể gặp vấn đề khác như callConvention hoặc các thuộc tính bổ sung cần chỉ định trong khi nhập dll.

Mã hóa hạnh phúc Hãy khỏe mạnh!


Hầu hết các tệp DLL không thể được tìm thấy trong cửa sổ tìm kiếm. Đáng tiếc là nó trông khá gọn gàng.
cuộn

3

Tôi cũng gặp sự cố này khi sử dụng VS2010. Nó là gì: Visual Studio mặc định là mã 64 bit cho 'bất kỳ CPU nào'. Các con trỏ đến các biến (ví dụ: chuỗi) bây giờ trở thành 64 bit khi gọi các Dlls bên ngoài của bạn, trong đó tất cả các Dlls đáng tin cậy và đáng tin cậy của bạn đều sử dụng con trỏ 32 bit.

Đừng cho rằng có bất cứ điều gì sai trái với Dlls của bạn, không có.

Thay đổi cài đặt VS của bạn để tạo mã X86 như thế này (Phiên bản Express của C #)

  1. đi tới Công cụ -> Tùy chọn.
  2. Ở góc dưới cùng bên trái của hộp thoại Tùy chọn, chọn hộp có nội dung "Hiển thị tất cả cài đặt".
  3. Trong chế độ xem dạng cây ở phía bên trái, hãy chọn "Dự án và giải pháp".
  4. Trong các tùy chọn ở bên phải, hãy chọn hộp có nội dung "Hiển thị cấu hình bản dựng nâng cao".
  5. Bấm OK.
  6. Đi tới Xây dựng -> Trình quản lý Cấu hình ...
  7. Trong cột Nền tảng bên cạnh dự án của bạn, hãy nhấp vào hộp tổ hợp và chọn "".
  8. Trong cài đặt "Nền tảng mới", hãy chọn "x86".
  9. Bấm OK.
  10. Nhấp vào Đóng.

Tôi cũng lưu ý rằng mặc dù máy tính tăng gấp đôi công suất sau mỗi 12 tháng, máy tính hiện tại của tôi với 1g RAM, dường như không nhanh hơn chiếc 486 đầu tiên của tôi với 4 Meg. Đừng lo lắng về việc sử dụng mã 64 bit, nó sẽ không nhanh hơn hoặc tốt hơn vì nó được xây dựng trên một tháp cồng kềnh định hướng đối tượng khổng lồ.


1
Cảm ơn vì những lời khuyên, tôi sẽ kiểm tra chúng. Nhưng nếu bạn đang chạy HĐH Windows 64 bit chỉ có 1 gb RAM, bạn sẽ gặp vấn đề về tốc độ. Bạn nên nâng cấp lên ít nhất 4 gb, nếu không bạn sẽ gặp sự cố hoán đổi. Hệ điều hành 64 bit có đủ khả năng để có nhiều thông tin trong bộ nhớ hơn là trên đĩa và sự thay đổi đó có thể tạo ra tốc độ tăng nhanh, tùy thuộc vào hoạt động. Nếu máy của bạn không nhanh hơn 486, có thể đã đến lúc thực hiện một số kiểm tra vi rút :)
mmr Ngày

Điều này đã làm việc, cảm ơn bạn rất nhiều! đã tiết kiệm cho tôi hàng giờ nếu không phải là ngày!
Alex Z,

0

Tôi đã cố gắng gọi dll với CallingConventionThisCallvà nó đã làm việc cho tôi. Đây là mã của tôi làm việc với BLOB MS Sql Server.

[DllImport("sqlncli11.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.ThisCall)]
            private static extern SafeFileHandle OpenSqlFilestream(
                        string FilestreamPath,
                        UInt32 DesiredAccess,
                        UInt32 OpenOptions,
                        byte[] FilestreamTransactionContext,
                        UInt32 FilestreamTransactionContextLength,
                        Int64 AllocationSize);

Thông tin thêm tại: https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention(v=vs.110).aspx

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.