2

私の問題は、混合言語プログラミングの細かい点を理解し、外部ライブラリの 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 を返します。

パラメーター: device 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 は構造に関する情報を含む構造への POINTER を返し、関数が最初に構造を作成することを暗示しているため、これは間違っていると感じます。

私は混合言語プログラミング、C++ の完全な初心者、および貧弱な VB プログラマーにまったく慣れていません。この問題を解決するための正しい方法を教えてくれる人はいますか? 私の感じでは、DLL で作成されたメモリ内の構造体を参照するように VB を取得する方法を理解する必要があるため、関数の戻り値として「物へのポインター」を理解するように vb を取得する必要があります。

提供された支援に感謝します。ただ rtfm とは言わないでください。私は今、FM で目を覚ましています。どこを見ればいいのかわかりません。

どうもありがとう、デビッド

4

2 に答える 2

3

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 は明らかにメモリ内に新しいオブジェクトを作成するため、それを解放/破棄する必要もあります。構造体を使用した後は、必ず適切な関数を呼び出してください。

于 2009-01-24T22:42:01.130 に答える
0

はい、あなたの構造は間違っています。実際、ポインターを取得してから、それが「指す」メモリを読み取る必要があります。

私は以前に C++ で外部 DLL の呼び出しを行ったことがありますが、通常は膨大な量のドキュメントを読み進める必要があります。ここにいる誰もあなたのためにそれをするつもりはないと思いますが、私はあなたを適切な方向に向けようとします.

まず、ポインタはアドレスであり、メモリ内のある場所を「指す」値です。ポインターの「逆参照」は、ポインターが指すメモリを読み取ることです (間違ったメモリを読み書きすると、メモリが混乱してプログラムを強制終了する可能性があります)。

さらに、低レベルでは、DLL の呼び出しには、情報のビットをスタックにコピーし、関数にそれらを取得させることが含まれます。「呼び出し規則」は、これがどのように行われるかを正確に説明しています。「c」、パスカル、およびその他のそのような規則があります。

DLL の関数を呼び出し、ポインタを取得し、ポイントされた情報をローカル構造にコピーしてから続行します。難しいのは、DLL 関数を宣言する方法を正確に理解することです。ライブラリのドキュメントにサンプル コードが含まれている場合は、そこから開始する必要があります。

短いGoogleは、VBでポインターを処理するための一貫した方法さえまったく示していません。1 つのアイデアは、DLL を呼び出してオブジェクトを値で返す短い C++ プログラムを作成することです。これが役立つかどうかはわかりませんが、外部ライブラリを扱うときにそのような問題が発生します。

幸運を

于 2009-01-24T22:58:59.630 に答える