#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, если хотите.