Вызов библиотеки DLL Visual Basic в C ++ - PullRequest
1 голос
/ 09 сентября 2010

Я приобрел библиотеку DLL, созданную в Visual Basic, у стороннего поставщика ( Sensor DLL.dll ).Эта DLL содержит функции для общения с датчиком, и мне нужно вызывать эти функции из программы на Visual C ++, которую я пишу.Поставщик не предоставит файл заголовка, и я не знаю Visual Basic.Если бы у меня был заголовочный файл, это был бы 15-минутный проект ... вместо этого я все еще борюсь с ним неделю спустя.Пожалуйста, помогите!

Мне сказали, что одна функция ( Get_Data ) в DLL имеет вид:

Public Function Get_Data(ByVal Handle As String) As String

Я пробовал несколько методов для вызова этой функции Get_Dataбезуспешно:

Способ 1) атрибут DllImport

#using <mscorlib.dll>
using namespace System::Runtime::InteropServices; 

namespace Sensor
{

[DllImport ("Sensor DLL.dll", EntryPoint = "Get_Data", CharSet = System:: Runtime :: InteropServices :: CharSet :: Unicode)] BSTR Get_Data (дескриптор BSTR);}

//then I call the function
Sensor::Get_Data(Handle);

Этот метод, похоже, наиболее близок к тому, что я получил для решения.Он компилируется, но выдает следующую ошибку при запуске:

Произошло необработанное исключение типа 'System.EntryPointNotFoundException'

Дополнительная информация: Невозможно найти точку входа с именем 'Get_Data'in DLL' Sensor DLL.dll '.

Я пробовал различные комбинации / перестановки типов данных, кроме BSTR, включая BSTR *, wchar_t, int и т. д. Возможно, я пропустил одну, но каждый тип данныхвозвращает ту же ошибку.

Метод 2) Атрибут класса хранения dllimport

__declspec(dllimport) BSTR Get_Data(BSTR Handle);

//then I call the function
Get_Data(Handle);

Этот метод вводит меня в заблуждение, поскольку я не задаю нужную DLLимпортировать из.Я скопировал DLL в папку проекта и добавил ее в проект вручную, так что, надеюсь, это означает, что ее можно найти.При компиляции компоновщик возвращает следующие ошибки:

ошибка LNK2028: неразрешенный токен (0A00034F) "wchar_t * __cdecl Get_Data (wchar_t *)" (? Get_Data @@ $$ FYAPA_WPA_W @ Z), на который есть ссылки вфункция "int __cdecl main (void)" (? main @@ $$ HYAHXZ)

ошибка LNK2019: неразрешенный внешний символ "wchar_t * __cdecl Get_Data (wchar_t *)" (? Get_Data @@ $$ FYAPA_WPA_W @ Z) упоминается в функции "int __cdecl main (void)" (? main @@ $$ HYAHXZ)

Я подозревал, что это может означать, что я должен использовать wchar_t или wchar_t * вместо BSTR, но изменить налюбой тип данных приводит к той же ошибке.

Метод 3) GetProcAddress

typedef BSTR (*Get_Data_Ptr)(BSTR Handle);  
HINSTANCE LoadMe;
LoadMe = LoadLibraryA("Sensor DLL.dll");

if (!LoadMe)
    std::cout << "\nDLL failed to load!\n";

Get_Data_Ptr LibMainGet_Data;  
LibMainGet_Data = (Get_Data_Ptr)GetProcAddress(LoadMe,"Get_Data");

//then I call the function
LibMainGet_Data(Handle);

Компилируется, но при запуске выдает следующую ошибку:

Произошло необработанное исключение типа 'System.AccessViolationException'

Дополнительная информация: Попытка чтения или записи в защищенную память.Это часто указывает на то, что другая память повреждена.

Когда я нащупываю различные части этого кода в режиме отладки, кажется, что, как и в первом методе, он также не смог найти точку входа 'Get_Data' в DLL.

Кто-нибудь вызывал функции из VB DLL с использованием C ++, если вы сами не создали DLL, у вас нет файлов .idl и т. Д.?У кого-нибудь есть такой рабочий пример, которым вы могли бы поделиться?
Спасибо!

Ответы [ 5 ]

1 голос
/ 03 декабря 2010

В OLE / COM viewer, чтобы просмотреть библиотеку типов COM в dll / exe / ..., вы должны открыть ее, используя «Файл-> Просмотр TypeLib» вместо «Файл-> Привязать к файлу» «

1 голос
/ 09 сентября 2010

Я полагаю, что недостающая часть - это соглашение о вызовах. C ++ имеет свое собственное соглашение о вызовах функций, отличное от VB6 (я полагаю, VB6, поскольку вы не указали VB.NET явно). VB6 использует соглашение STDCALL, тогда как C ++, в зависимости от поставщика, использует другое соглашение о вызовах, называемое __cdecl, поэтому вы видите __cdecl в строке ошибки компилятора для метода # 2. Предполагается, что ваша внешняя функция использует это соглашение о вызовах по умолчанию. Соглашение о вызовах - это набор правил, описывающих, как функции вызывают друг друга; в частности, о том, как используются регистры, в какие параметры заказа доставляются, как определяется значение / ссылка и т. д.

Я бы предложил придерживаться метода № 3, так как метод № 1 предназначен для Managed C ++, который не является стандартным C ++, а метод № 2 мне незнаком и выглядит немного неоднозначно. Что вы хотите попробовать, так это объявить указатель функции typedef для использования STDCALL.

typedef BSTR (__stdcall *Get_Data_Ptr)(BSTR Handle);
1 голос
/ 09 сентября 2010

VB6 DLL обычно является COM-сервером.На самом деле у вас есть эквивалент файла .h, в него встроена библиотека типов.Начните с Project + Properties, Common Properties, Framework и References.Кнопка «Добавить новую ссылку», вкладка «Обзор», выбор библиотеки DLL.

Далее, «Просмотр» + «Обозреватель объектов».Вы должны увидеть сгенерированную библиотеку Interop в списке.Откройте узел, чтобы увидеть, что там.Вы пишете обычный управляемый код, такой как gcnew, для создания COM-объекта и вызова методов интерфейса.Вам нужна минимальная документация по доступным методам, чтобы догадаться, как их следует вызывать.

0 голосов
/ 09 сентября 2010

Программа Visual Basic обычно требует времени выполнения для выполнения.

Если у вас есть COM-объект (реализованный в VB), используйте COM API для связи с ним из C ++.Вы должны будете сначала зарегистрировать COM.Вот поток, объясняющий, как это сделать: http://forums.devx.com/archive/index.php/t-87059.html

Если вы используете язык .NET, используйте метод Hans Passant со ссылкой, которая создаст для вас dll взаимодействия.Это намного проще.

  • Способ 1. Не делайте этого, если у вас есть COM-объект, который вы хотите использовать из среды .NET, обратитесь к нему.
  • Метод2: вы получаете ошибки, потому что вам не хватает файла .lib для правильной ссылки на DLL (статически динамически связывать)
  • Метод 3: будет чисто динамическим решением, но вы должны знать точные имена методовв DLL.Они могут варьироваться в зависимости от параметров и используемого соглашения о вызове.Это очень похоже (фактически идентично, я бы сказал) проблеме, с которой вы сталкиваетесь при решении по методу 1.Название метода для вас не "Get_Data", а что-то еще.С помощью такого инструмента, как просмотрщик зависимостей , вы можете просмотреть экспортированные имена.

Даже метод 3 с правильными именами может дать сбой, потому что если это COM-объектвам понадобится среда под названием Appartment, чтобы использовать COM-объекты.Вы «входите» в эту квартиру, звоня CoInitialize.Это создает магические вещи в TLS (Thread Local Storage) для выполнения магии COM.Я надеюсь, это объясняет, почему ваши попытки будут бессмысленными, если ваша DLL является COM-компонентом, что вполне вероятно в соответствии с ATL, например, с именами, которые мы можем видеть.

РЕДАКТИРОВАТЬ: я забыл сказать, чтовы также можете легко увидеть, что находится внутри dll, если это COM с OLE / COM Viewer (обычно, если у вас есть компилятор, у вас будет такой инструмент).

0 голосов
/ 09 сентября 2010

Похоже, что DLL на самом деле не экспортирует функцию с именем Get_Data.Откройте командную строку и используйте dumpbin , чтобы получить список экспортов DLL, например:

dumpbin /exports "Sensor DLL.dll"

(dumpbin.exe находится в VC \ bin в вашей установке Visual StudioПапка, которая, как правило, что-то вроде C:\Program Files\Microsoft Visual Studio 10.0).

Затем замените Get_Data на фактическую точку входа и посмотрите, повезет ли вам больше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...