![](/img/trans.png)
[英]Can I call MAPI32.DLL > MAPISendMail from a 64-bit C# Winforms application?
[英]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.