Программирование на разных языках, VB и C ++, Понимание API и указателей - PullRequest
2 голосов
/ 25 января 2009

Моя проблема в понимании тонкости программирования смешанного языка и доступ к API во внешних библиотеках. Мои навыки в C ++ отсутствуют и в VB, посредственно.

У меня есть c ++ dll (библиотека portaudio), и я пытаюсь получить к нему доступ из VB (Visual Studio 2005). Я получаю ошибки MarshallDirectiveException при вызове функции, я считаю, потому что Я неправильно взаимодействую с DLL.


функция и структуры C ++ определены следующим образом:

информация заголовка:

typedef int PaHostApiIndex;
...
typedef double PaTime;
...
typedef struct PaDeviceInfo
 {
     int structVersion;  /* this is struct version 2 */
     const char *name;
     PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/
     int maxInputChannels;
     int maxOutputChannels;
     PaTime defaultLowInputLatency;
     PaTime defaultLowOutputLatency;
     PaTime defaultHighInputLatency;
     PaTime defaultHighOutputLatency;
     double defaultSampleRate;
 } PaDeviceInfo;
 ...
 const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device );

использование программы из документов:

const PaDeviceInfo* Pa_GetDeviceInfo    (   PaDeviceIndex   device   )  

Получить указатель на структуру PaDeviceInfo, содержащую информацию об указанном устройство.

Возвращает: Указатель на неизменяемую структуру PaDeviceInfo. Если параметр устройства находится вне диапазона функция возвращает NULL.

Параметры: устройство Допустимый индекс устройства в диапазоне от 0 до (Pa_GetDeviceCount () - 1)


В программе VB у меня есть:

Private Declare Function Pa_GetDeviceInfo Lib "portaudio_x86.dll" (ByVal dindex As Integer) As PaDeviceInfo
...
Private Structure PaDeviceInfo
        Dim structVersion As Integer
        <MarshalAs(Runtime.InteropServices.UnmanagedType.LPStr)> Dim name As String
        Dim hostapi As Integer
        Dim maxInputChannels As Integer
        Dim maxOutputChannels As Integer
        Dim defaultLowInputLatency As Double
        Dim defaultLowOutputLatency As Double
        Dim defaultHighInputLatency As Double
        Dim defaultHighOutputLatency As Double
        Dim defaultSampleRate As Double
End Structure
...
        Dim di As New PaDeviceInfo
        di = Pa_GetDeviceInfo(outputParameters.device)

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

Я совершенно новичок в программировании на смешанных языках, абсолютный новичок на c ++ и плохой программист на VB. Может ли кто-нибудь направить меня правильным способом для решения этой проблемы? Я чувствую, что мне нужно понять, как заставить VB ссылаться на структуру в памяти, созданную в dll, поэтому мне нужно получить vb, чтобы понимать 'указатель на вещь' как возвращаемую функцию.

Большое спасибо за любую оказанную помощь. Пожалуйста, не просто говорите RTFM, я в моих глазах в FM в минуту, я просто не знаю, где искать.

Большое спасибо, David

Ответы [ 2 ]

3 голосов
/ 25 января 2009

Ваше объявление функции API неверно. Функция возвращает указатель, который не отражен в вашем коде. Подпись переводится на VB следующим образом:

Private Declare Function Pa_GetDeviceInfo Lib "portaudio_x86.dll" ( _
    ByVal dindex As Integer _
) As IntPtr

Конечно, напрямую использовать IntPtr нелегко. На самом деле, довольно много маршаллинга задействовано :

Dim obj As PaDeviceInfo = _
    DirectCast(Marshal.PtrToStructure(ptr, GetType(PaDeviceInfo)), PaDeviceInfo)

(более или менее важное) примечание: поскольку ваша DLL, очевидно, создает новый объект в памяти, ей также необходимо освободить / уничтожить его. Обязательно вызовите соответствующую функцию после использования структуры.

0 голосов
/ 25 января 2009

Да, ваша структура неверна. Вы действительно должны получить указатель и затем прочитать память, на которую он «указывает».

Я уже делал внешние вызовы DLL в C ++, и это, как правило, требует огромного разбора документации. Я не думаю, что кто-то здесь сделает это для вас, но я постараюсь указать вам правильное направление.

Во-первых, указатель - это адрес, значение, которое «указывает» на какое-то место в памяти. «разыменование» указателя считывает память, на которую указывают указатели (и если вы читаете или пишете не ту память, память может расстроиться и убить вашу программу).

Кроме того, на низком уровне вызов DLL включает копирование битов информации в стек и последующее получение этой функцией функции. «Соглашения о вызовах» описывают, как именно это делается - существуют «с», паскаль и другие подобные соглашения.

Вы захотите вызвать функцию DLL, получить указатель, скопировать указанную информацию в вашу локальную структуру и затем продолжить. Трудно будет понять, как именно объявить функцию DLL. Если в документации вашей библиотеки есть какой-то пример кода, возможно, с этого и стоит начать.

Короткий Google даже не показывает какого-либо последовательного способа работы с указателями в VB вообще. Одной из идей было бы создать короткую программу на C ++, которая вызывала бы DLL и возвращала объект по значению. Я не знаю, поможет ли это, но такие ошибки возникают при работе с внешними библиотеками.

Удачи

...