Как я могу использовать P / Invoke для вызова 64-битной C ++ DLL из 64-битного приложения C #?

Я работаю над кодом, который включает использование P / Invoke для вызова неуправляемых функций из нескольких библиотек C ++. Я хотел бы иметь возможность создавать приложения как 32-разрядные, так и 64-разрядные.

В настоящее время он работает только как x86.

У меня есть 32- и 64-битные копии каждой из указанных C ++ DLL, и я использую следующий код для изменения 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);

Как я уже говорил, все работает нормально при запуске приложения под x86 на моей локальной машине (Windows 7 x64). Однако, когда я компилирую его как приложение x64, я получаю «AccessViolationException» при вызове gdk_pixbuf_save ().

Есть идеи? Я относительно новичок в взаимодействии кода, но я думаю, что это может иметь какое-то отношение к тому, как переменные IntPtr отправляются в / из неуправляемого кода? Но почему он отличается от x86 до x64?

1

Решение

Большое спасибо всем, кто прокомментировал — вы отправили меня по правильному пути и помогли мне решить основную проблему.

Первоначально я хотел иметь сборку x64 так, на всякий случай это было необходимо … и все закончилось тем, что было именно этим.

Как выясняется, эти комментарии верны. На x64 билды недокументированные ___arglist Ключевое слово не работает как задумано.

Я не могу комментировать то, что, в частности, идет не так. В связанном мною комментарии упоминается возможность неправильной настройки соглашения о вызовах. Я не уверен, как это работает … не только x64 один в любом случае?

Что бы то ни было, вернемся к делу:

Я изменил свой DllImport за gdk_pixbuf_save выглядеть так:

[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 пуст (есть другие, необязательные, параметры, которые могут быть указаны), документация говорит мне, что он должен быть нулевым. Для этого я передаю IntPtr.Zero (или же UIntPtr.Zero, в моем случае).

Теперь мой код компилируется, запускается, и я (что более важно) имею доступ к 64-битной памяти.

Еще раз спасибо тем, кто прокомментировал мой пост — без ваших указателей на ___arglist параметр, я бы был совершенно невежествен

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]