Исключение PInvokeStackImbalance при использовании IntPtr в .NET 4?(Работает в .NET 3.5) - PullRequest
4 голосов
/ 28 марта 2012

Может быть, это немного нубский вопрос, но это то, что вызывает у меня рассол в течение последних нескольких часов (или дней) ...

Я вызываю метод из DLL в моем коде в .NET Framework 4.0

  [DllImport("xeneth.dll")]
    public static extern ErrorCode XC_GetFrame(Int32 h, FrameType type, ulong ulFlags, IntPtr buff, uint size);

и затем использовать его здесь:

if (XC_GetFrame(myCam, XC_GetFrameType(myCam), 0, IntPtr.Zero, (uint)fs) != ErrorCode.E_NO_FRAME)

Однако, когда я запускаю это в .NET 4.0, я получаю ошибку P / INVOKE, однако ... выполнение этого в 3.5 не вызывает эту ошибку. После того, как я и другой программист просмотрели код, мы, кажется, отложили его до IntPtr, работающего по-другому на 4.0.

Мое приложение должно работать в .NET 4.0, так как пара функций, необходимых для приложения, доступна только в 4.0 ...

Есть что-нибудь, что, возможно, я пропускаю или просто забыл включить?

Любые мысли очень ценятся!

Tom

Обновление:

Родная декларация:

virtual ErrCode XCamera::GetFrame(FrameType type, unsigned long ulFlags, void *buffer, unsigned int size)

Ошибка: вызов функции PInvoke 'DLLTest! DLLTest.Form1 :: XC_GetFrameType' разбалансировал стек. Это вероятно потому, что управляемая подпись PInvoke не совпадает с неуправляемой целевой подписью. Убедитесь, что соглашение о вызовах и параметры подписи PInvoke соответствуют целевой неуправляемой подписи.

Ответы [ 3 ]

9 голосов
/ 28 марта 2012

Для этого есть две общие причины:

  1. Несоответствие соглашений о вызовах. Ваш код C # использует значение по умолчанию stdcall. Возможно, нативный код использует cdecl. Попробуйте добавить CallingConvention=CallingConvention.Cdecl к атрибуту DllImport.
  2. Несоответствие списков параметров (см. Ниже).

Не обманывайте себя, что ваш код в порядке, потому что .net 3.5 не вызывает эту ошибку. Обнаружение ошибок в .net 4 лучше, поэтому вы видите только ошибки там. Но ваш код не работает во всех версиях .net.


Собственное определение для вашего виртуального метода C ++:

virtual ErrCode XCamera::GetFrame(FrameType type, unsigned long ulFlags, 
    void * buffer, unsigned int size);

Похоже, вы передаете указатель объекта в качестве первого параметра в вашем вызове pinvoke. Я думаю, что это может сработать, хотя я недостаточно знаю, как обрабатываются виртуальные функции при экспорте, чтобы понять, является ли это проблемой. Предположительно, вы экспортировали простую функцию C для создания объектов.

Другая проблема, которую я вижу, состоит в том, что в Windows C / C ++ long составляет 32 бита. C # long составляет 64 бита. Это означает, что правильное объявление для ulFlags такое же, как uint в вашем коде C #.

3 голосов
/ 28 марта 2012

Вдобавок ко всему, вы проверяли битность обоих проектов?Вы получите ошибки, если один 64-битный, а другой 32-битный.Обратите внимание, что в последней версии по умолчанию для проектов C # был изменен с любого процессора на x86.Это не имеет значения в x86 OS, но в x64 OS это имеет существенное значение.

Кроме того, вы, как правило, должны включать как можно больше текста ошибки, цензура для защиты частной информации - это хорошо., но номер ошибки и текст могут быть весьма полезны.Кроме того, при работе с extern полезно включить оба определения любых типов struct, чтобы убедиться, что они эквивалентны.(Еще одна распространенная проблема).

1 голос
/ 28 марта 2012

Может быть, лучший вопрос, почему он работал раньше.Предоставленное вами объявление:

virtual ErrCode XCamera::GetFrame(FrameType type, unsigned long ulFlags, void * buffer, unsigned int size)

имеет типы .NET, соответствующие: FrameType, uint, IntPtr, uint.

В Windows unsigned long - это 32-битный тип,в то время как в C # ulong это 64-битный тип.

...