#.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. ДА. Извините за это. Это мой первый вопрос, и я не понимал, как мне нужно было его закрыть.