2013-11-20 88 views
1

我正在研究一些涉及使用P/Invoke從幾個C++ DLL調用非託管函數的代碼。我希望能夠將應用程序構建爲32位或64位。如何使用P/Invoke從64位C#應用程序調用64位C++ DLL?

目前,它只能用作x86。

我有每個引用的C++ DLL的32位和64位副本,並且使用以下代碼來更改DllDirectory,具體取決於應用程序是構建爲x86還是x64(/ lib/x64保存64位dll ,/ lib中/ 86保持32位的):

[DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
static extern bool SetDllDirectory(string lpPathName); 

string libPath = Path.Combine(Environment.CurrentDirectory, "lib", (Environment.Is64BitProcess == true ? "x64" : "x86")); 
SetDllDirectory(libPath); 

我的非託管C++函數被定義爲的其餘部分如下:

[DllImport("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
static extern void g_type_init(); 
[DllImport("libgobject-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
static extern void g_object_unref(IntPtr pixbuf); 
[DllImport("librsvg-2-2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
static extern IntPtr rsvg_pixbuf_from_file_at_size(string file_name, int width, int height, out IntPtr error); 
[DllImport("libgdk_pixbuf-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
static extern bool gdk_pixbuf_save(IntPtr pixbuf, string filename, string type, out IntPtr error, __arglist); 

實際使用這些函數的代碼類似於此:

g_type_init(); 
IntPtr ptrError; 
IntPtr ptrPixbuf = rsvg_pixbuf_from_file_at_size(filePath, width, height, out ptrError); 
if (ptrError == IntPtr.Zero) 
{ 
    bool isSaved = gdk_pixbuf_save(ptrPixbuf, outputPath, outputFormat, out ptrError, __arglist(null)); //this line fails when compiled as x64! 
    if (isSaved && File.Exists(outputPath)) 
    { 
     return outputPath; 
    } 
} 
g_object_unref(ptrPixbuf); 

正如我所提到的,當我的本地機器上運行應用程序爲x86時,一切正常(Windows 7 x64)。但是,當我將它編譯爲x64應用程序時,我在調用gdk_pixbuf_save()時收到「AccessViolationException」。

任何想法?我對互操作代碼比較陌生,但我認爲它可能與IntPtr變量如何發送到非託管代碼有關。但爲什麼它不同於x86到x64?

+0

你將不得不調試它,所以你至少有一個想法哪個參數是錯誤的。在本機C++代碼上設置一個斷點並從此處取得斷點。 –

+1

__arglist沒有記錄,所以也許它只是不工作...... –

+1

你有沒有嘗試明確定義額外的參數,而不是使用__arglist? – master131

回答

0

非常感謝所有評論過的人 - 您寄給我的是正確的道路,並幫助我解決了潛在的問題。

最初,我想有一個x64版本,以防萬一這是必要的......它結束了就是這樣。原來,these comments是正確的。在x64版本中,無證的___arglist關鍵字不能按預期運行。

我不能評論什麼,具體而言,出問題了。我鏈接的評論提到調用約定沒有被正確設置的可能性。我不知道這是如何工作的...不x64只有一個調用約定,無論如何?

不管,回點:

我改變了我的gdk_pixbuf_saveDllImport看起來像這樣:

[DllImport("libgdk_pixbuf-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)] 
static extern bool gdk_pixbuf_save(UIntPtr pixbuf, string filename, string type, out UIntPtr error, UIntPtr arglist); 

這裏的關鍵是,我傳遞的最後一個參數,arglistIntPtr而不是___arglist

實際上,我將它傳遞爲UIntPtr,因爲我將所有原始IntPtr對象切換爲UIntPtr

話雖這麼說,當我打電話的功能,它看起來像這樣:

bool isSaved = gdk_pixbuf_save(ptrPixbuf, outputFilePath, outputFileFormat, out ptrError, UIntPtr.Zero); 

由於我___arglist是空的(也有可能被指定其他可選參數),該documentation告訴我,它應該以null結尾。爲了達到這個目的,我通過了IntPtr.Zero(或UIntPtr.Zero,就我而言)。

現在,我的代碼編譯,運行,我(更重要的是)有權訪問64位內存。

再次感謝那些對我的帖子發表評論的人 - 沒有你指向___arglist參數的指針,我完全無能爲力。

+1

幹得好!另外:不要使用SetDllDirectory,您可以在調用任何其他pinvokes之前調用DLL的完整路徑來調用LoadLibrary。只是另一種方式來做到這一點。 –

相關問題