2009-01-24 93 views
2

我的問題是瞭解混合語言編程 和訪問外部庫中API的更精細的點。我的C++技能不存在 和VB,平庸。混合語言編程,VB和C++,瞭解API和指針

我有一個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++ utter noob和一個糟糕的VB程序員。 任何人都可以引導我以正確的方式來解決這個問題嗎? 我的感覺是,我需要理解如何讓VB引用在dll中創建的memry中的結構,所以我需要讓vb將「指向東西的指針」理解爲函數返回。

非常感謝您提供的任何幫助。請不要只是說rtfm,我在我的眼睛在FM的 分鐘,我只是不知道在哪裏看。

非常感謝, 大衛

+0

誰投了票,謝謝,但我希望有人有一個答案!說真的,我在'困難的東西'這個領域問的問題,因此不太可能得到答案,或者人們正在閱讀這個問題,並且會「噓噓,什麼是小白,回到麻煩的東西上」? – 2009-01-24 22:29:11

+0

看起來你正試圖在VB.NET中處理互操作,所以我唯一的建議就是在C++/CLI中編寫一些託管包裝代碼。從長遠來看,這可能會讓你的生活變得更輕鬆。另一方面,對於任何處理VB6或VBA互操作的人來說,我不能推薦本書的相關章節(現在可以在線獲得)「Hardcore Visual Basic」:http://vb.mvps.org/鐵桿/ – 2010-05-20 17:42:33

回答

3

你的API函數的聲明是錯誤的。該函數返回一個不會反映在代碼中的指針。簽名轉化爲VB如下:

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

當然,使用IntPtr直接是不容易的。事實上,頗有些編組是involved

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

(或多或少是重要的)側面說明:因爲你的DLL顯然是在內存中創建一個新的對象,它也需要釋放/摧毀它。確保在使用該結構後調用相應的功能。

0

是的,你的結構是錯誤的。你必須得到一個指針,然後讀取它「指向」的內存。

我以前在C++中完成了外部DLL調用,它通常涉及大量的文檔瀏覽。我不認爲這裏有人會爲你做這件事,但我會試着指出你的方向。

首先,一個指針是一個地址,一個「指向」內存中某個位置的值。 「取消引用」指針是讀取指針指向的內存(如果您讀取或寫入錯誤的內存,內存可能會變得不安並殺死您的程序)。

此外,在低級別,調用DLL包括將信息的位複製到堆棧,然後讓函數檢索它們。 「調用慣例」完全描述瞭如何完成 - 有「c」,pascal和其他這樣的慣例。

您將需要調用DLL的函數,獲取指針,將指向的信息複製到本地結構中,然後繼續。困難的事情將是搞清楚如何聲明DLL函數。如果你的庫文檔有一些示例代碼,那可能是從哪裏開始的。

一個簡短的Google甚至都沒有顯示任何一致的方式來處理VB中的指針。一個想法是創建一個簡短的C++程序,它將調用DLL並通過值返回一個對象。我不知道這是否會有所幫助,但是在處理外部庫時會出現這樣的問題。

好運