Вызов функции PInvoke [имя функции] привел к дисбалансу стека

#c# #c #pinvoke #unmanaged

#c# #c #pinvoke #неуправляемый

Вопрос:

Я пытаюсь использовать PInvoke для вызова неуправляемой библиотеки DLL C и получаю ошибки (см. Ниже). При использовании depends.exe я вижу искаженное имя в списке экспортированных функций, отсюда и странное EntryPoint название. Хотя это исключение появляется, если я продолжу Step Over во время отладки, функция возвращает значение и ptr равно 1 и выводится «Успех».

Я пробовал некоторые предложения, найденные в других сообщениях, но ничего не сработало. Я подумал, uint32_t это говорит само за себя. Я попытался изменить сигнатуру C # PInvoke для использования, long и ulong однако исключение по-прежнему выдается, а значение ptr является очень большим числом. Я также пробовал устанавливать CharSet и ExactSpelling свойства для DllImport атрибута, но, похоже, это тоже не сработало.

Мой вопрос в том, что я делаю, что вызывает исключение, и если я не могу / не должен игнорировать исключение — как это можно сделать?

Неуправляемый C

MyClass.h

 class __declspec(dllexport) MyClass
{
public:
   uint32_t runCommand(uint32_t start);
};
  

MyClass.cpp

 uint32_t MyClass::runCommand(uint32_t start);
{
    uint32_t status = 1;
    return status;
}
  

Управляемый C#

Подпись P/ Invoke

 [DllImport("myClass.dll", 
           EntryPoint = "?runCommand@MyClass@myClass@@QAEII@Z", 
           CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 runCommand(UInt32 baseAddress);
  

Использование

 public static void Do()
{
    UInt32 a = 0xA000;
    UInt32 ptr = runCommand(a);
    Console.Write("Success!");
}
  

Ошибка:

Помощник по управляемой отладке ‘PInvokeStackImbalance’ обнаружил проблему в ‘C:Users…TestApp.vshost.exe ‘.

Дополнительная информация: Вызов функции PInvoke ‘TestApp!TestApp.CSMyClass::runCommand’ привел к дисбалансу стека. Вероятно, это связано с тем, что управляемая подпись PInvoke не соответствует неуправляемой целевой подписи. Убедитесь, что соглашение о вызове и параметры подписи PInvoke соответствуют целевой неуправляемой подписи.

Используется Visual Studio 2015, а приложение C # — .NET Framework 4.6.

Ответ №1:

Существует несоответствие в соглашениях о вызовах, которое вызывает дисбаланс стека.

Поскольку runCommand является функцией-членом MyClass , для нее используется соглашение о вызове not __cdecl , но __thiscall (обратите внимание, что существует неявный указатель « this «, передаваемый в качестве аргумента нестатическими функциями-членами классов C ).

Возможно, вам захочется либо экспортировать чистую функцию интерфейса C (не функцию-член класса C ) из вашей DLL для P / Invoke’ing, либо вы можете использовать C / CLI для создания крошечного связующего слоя между собственным и управляемым кодом, обернув свой собственный класс C в управляемый класс .NET, написанный на C / CLI, и использовать оболочку управляемого класса из C #.

Комментарии:

1. Спасибо. Повторяю читателям, если вы сталкиваетесь с этим, и ваш сценарий позволяет вам просто превратить функцию-член в статическую функцию-член, вы тоже можете это сделать. В MyClass.h файле я изменил определение на static uint32_t runCommand(uint32_t start); , и это устранило проблему.

2. Пожалуйста. Я не проверял это подробно (поскольку мне не нравится экспортировать классы C из интерфейсов DLL), но это, вероятно, потому, что статическая функция-член не имеет дополнительного this параметра указателя.

3. Именно поэтому. @Kevin, конечно, лучше вынести эту функцию за пределы класса?

4. @DavidHeffernan Я пытался сделать это в своем реальном коде, но это невозможно сделать так, как это настроено. Я получаю SEHExceptions, поэтому я предполагаю, что мне придется использовать подход C / CLI.

5. Я не понимаю, почему это должно быть так. Это должно быть осуществимо через p / invoke, если хотите.