Ошибка переноса атрибута DllImport PInvokeStackImbalance

#.net #pinvoke #dllimport

#.net #pinvoke #dllimport

Вопрос:

Я пытаюсь вызвать неуправляемую dll из vb (VS2013 Express), используя атрибут DllImport следующим образом:

 <DllImport("armdll32.dll", setlasterror:=True, charset:=CharSet.Ansi)>
Public Shared Function ArmConnect(ByVal port As Integer, ByVal baud As Long, ByRef   serialNumber As String) As Integer

End Function
  

Я вызываю функцию следующим образом:

 Dim serialNumber As String = ""

Debug.WriteLine(MicroScribeWrapper.ArmConnect(0, 0, serialNumber))
  

но я получаю следующую ошибку:

Помощник по управляемой отладке ‘PInvokeStackImbalance’ обнаружил проблему в ‘C:XXXX ‘ Дополнительная информация: вызов функции PInvoke ‘MicroscribeSDKTest!MicroscribeSDKTest.MicroScribeWrapper::ArmConnect’ привел к дисбалансу стека. Вероятно, это связано с тем, что управляемая подпись PInvoke не соответствует неуправляемой целевой подписи. Убедитесь, что соглашение о вызове и параметры подписи PInvoke соответствуют целевой неуправляемой подписи.

Документация из файла справки dll описывает функцию следующим образом:

ArmConnect обнаруживает и устанавливает соединение с микроскрипью. ArmDll32/ArmDll64 подключатся к первому обнаруженному устройству микрозаписи. Порядок обнаружения следующий: постоянно сканируйте все порты USB; при вызове с port=0 и baud = 0 сканируйте все доступные последовательные порты (COM) и попытайтесь подключиться со скоростью 115200 бод; в противном случае сканируйте нужный последовательный порт с требуемой скоростью передачи в бодах. Номер порта и параметры скорости передачи в бодах игнорируются, если на USB-порту обнаруживается микрозапись. При использовании USB-соединений иногда желательно подключить к главному компьютеру более одного устройства микрозаписи. В приложениях как таковых каждое уникальное подключенное устройство может быть идентифицировано по строке его серийного номера, передаваемой необязательным параметром SerialNumber. При использовании этой конфигурации для каждого модуля микрозаписи должны быть запущены отдельные экземпляры ArmDLL.

         int ArmConnect ( int port, long baud, char *serialNumber = 0 );
  

Я почти уверен, что проблема связана с тем, как я вызываю метод ArmConnect, но все, что я пробовал на сегодняшний день, потерпело неудачу.

Будем признательны за любую помощь.

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

1. ByRef serialNumber As String заменить на ByVal baud As Long заменить на Integer

2. также убедитесь в том, что CallingConvention: msdn.microsoft.com/en-us/library /…

Ответ №1:

Я вижу здесь несколько проблем.

  • В C в Windows long является 32-разрядным. Таким образом, baud параметр в вашем p / invoke должен быть Integer .
  • Строковый параметр serialNumber предположительно является строкой C. Это указатель на строку, заканчивающуюся нулем. Это было бы ByVal serialNumber As String в p / invoke.
  • Наконец, соглашение о вызовах. Как написано, может показаться, что неуправляемый код использует соглашение о вызове cdecl. Ваш p / invoke использует stdcall. Я полагаю, что соглашение о вызове неуправляемого кода на самом деле является stdcall, и в документации, которую вы включили, это опущено. Чтение файла заголовка библиотеки могло бы устранить это.
  • Я думаю, маловероятно, что функция возвращает ошибки при вызове SetLastError .

Итак, вкратце, p / invoke должен быть

 <DllImport("armdll32.dll", CallingConvention=CallingConvention.Cdecl, _
    CharSet:=CharSet.Ansi)>
Public Shared Function ArmConnect( _
    ByVal port As Integer, _
    ByVal baud As Integer, _
    ByVal serialNumber As String _
) As Integer
End Function
  

или

 <DllImport("armdll32.dll", CallingConvention=CallingConvention.Stdcall, _
    CharSet:=CharSet.Ansi)>
Public Shared Function ArmConnect( _
    ByVal port As Integer, _
    ByVal baud As Integer, _
    ByVal serialNumber As String _
) As Integer
End Function
  

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

1. Спасибо, Дэвид. Я просмотрел файл заголовка, как вы предложили, и оказалось, что есть ArmConnectSN, а также ArmConnect . В первом используется аргумент SerialNumber, во втором — нет. Это, в сочетании с другими вашими предложениями, похоже, все работает. Еще раз спасибо!

2. ДА. Извините за это. Это мой первый вопрос, и я не понимал, как мне нужно было его закрыть.