繁体   English   中英

如何使用P / Invoke从64位C#应用程序中调用64位C ++ DLL?

[英]How can I use P/Invoke to call a 64-bit C++ DLL from a 64-bit C# Application?

我正在处理一些涉及使用P / Invoke从一些C ++ DLL调用非托管函数的代码。 我希望能够将应用程序构建为32位或64位。

当前,它仅可用作x86。

我有每个引用的C ++ DLL的32位和64位副本,并且正在使用以下代码来更改DllDirectory,具体取决于该应用程序是x86还是x64构建的(/ lib / x64拥有64位dll,/ lib / x86保留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);

如前所述,在本地计算机(Windows 7 x64)上以x86形式运行应用程序时,一切工作正常。 但是,当我将其编译为x64应用程序时,在调用gdk_pixbuf_save()时会收到“ AccessViolationException”。

有任何想法吗? 我是互操作代码的新手,但我认为这可能与IntPtr变量与非托管代码之间的关系如何? 但是,为什么x86与x64不同?

非常感谢所有发表评论的人-您使我走上了正确的道路,并帮助我解决了潜在的问题。

最初,我想拥有一个x64构建版本,以防万一 。。。

事实证明, 这些评论是正确的。 在x64版本上,未记录的___arglist关键字无法正常运行。

我无法评论具体是哪里出了问题。 我链接的评论提到了调用约定设置不正确的可能性。 我不确定这是如何工作的... x64不是只有一个调用约定吗?

无论如何,回到重点:

我将gdk_pixbuf_save DllImport更改如下:

[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);

此处的关键是我将最后一个参数arglist作为IntPtr而不是___arglist

实际上,我将它作为UIntPtr传入,因为我将所有原始IntPtr对象都切换到了UIntPtr

话虽如此,当我调用该函数时,它看起来像这样:

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

由于我的___arglist为空(可以指定其他可选参数),因此文档告诉我应该以null终止。 为此,我传入IntPtr.Zero (在我的例子中为UIntPtr.Zero )。

现在,我的代码可以编译,运行,并且(更重要的是)我可以访问64位的内存。

再次感谢那些对我的帖子发表评论的人-如果您没有指向___arglist参数的指针,我将一无所知。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM