Я создаю универсальное приложение Windows 10 (телефон + планшеты) + библиотеки. В решении у меня есть проект C++ dll, который создает неуправляемый my.dll
, который вызывается из C#. DLL, имеет экспорт, как это:Параметры не передаются в неуправляемую DLL на x86 при построении с .NET. Native
// === C++ ===
typedef struct { int f1; uint32_t f2; } R;
// A and B are also structures.
MY_EXPORT R the_function(A *a, const B *b, const uint8_t *c);
// === C# ===
[DllImport("my.dll", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
extern static R the_function(A a, B b, byte[] c);
[StructLayout(LayoutKind.Sequential)]
internal struct R
{
public int f1; // Actually a enum but it shouldn’t matter.
public uint f2_id;
}
internal struct A
{
IntPtr nativePtr;
}
internal struct B
{
IntPtr nativePtr;
}
Тест приложение работает на платформах ARM и X64. Он работает на X86, если «Компиляция с .NET Native tool chain» не отмечена.
Неуправляемая DLL-авария на X86, если установлена опция «Скомпилировать с помощью .NET Native tool chain», говоря о нарушении доступа. Я могу воспроизвести как в сборках Debug, так и в Release.
При использовании отладчика, я вижу, что есть ошибка в том, как передаются аргументы. На # стороне C, в некоторых сгенерированного компилятором C# код есть строка, как это:
unsafe___value = global::McgInterop.my_PInvokes.the_function(a, b, unsafe_c);
В отладчике, я подтверждаю, что аргументы в порядке.
На стороне C++ значения неверны. Значение b - это то, что было передано в a, значение c - это то, что было передано в b.
Я попытался создать минималистский пример, но не смог, он работает нормально. my.dll экспортирует 100 + экспортированный метод __cdecl, это большой кросс-платформенный C++ SDK, над которым я работаю, чтобы довести до платформы Windows 10, похоже, что остальные методы работают нормально.
Любые идеи, что здесь происходит? Или, по крайней мере, как я могу выделить проблему? Заранее спасибо.
Обновление: ОК, это минимальный репродукт.
Неуправляемый код:
typedef struct
{
int f1;
DWORD f2;
} R;
R __cdecl nativeBug(int a, int b)
{
CStringA str;
str.Format("Unmanaged DLL: a = %i, b = %i\n", a, b);
::OutputDebugStringA(str);
R res
{
11, 12
};
return res;
}
C# магазин приложений:
[StructLayout(LayoutKind.Sequential)]
struct R
{
public int f1;
public uint f2;
}
[DllImport("NativeBugDll.dll", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
extern static R nativeBug(int a, int b);
private void Page_Loaded(object sender, RoutedEventArgs e)
{
App.Current.UnhandledException += app_UnhandledException;
R r = nativeBug(1, 2);
Debug.WriteLine("Result: f1={0}, f2={1}", r.f1, r.f2);
}
private void app_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Debug.WriteLine("Unhandled exception: " + e.Message);
}
Debug выход без .NET Native нормально:
Unmanaged DLL: a = 1, b = 2
Result: f1=11, f2=12
И вот отлаживать выход с .NET Native сборки :
Unmanaged DLL: a = 91484652, b = 1
Unhandled exception: Object reference not set to an instance of an object.
STATUS_STACK_BUFFER_OVERRUN encountered
Затем визуальная студия полностью висит.
X64 build прекрасно работает даже с .NET Native.
Показать код C++ (по крайней мере, функция подписи) –
IIRC, x86 является единственным из трех платформ вы упомянули, где разные правила для stdcall и cdecl. –
См. Обновление, добавленный заголовок. – Soonts