4

Я создаю универсальное приложение 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.

+0

Показать код C++ (по крайней мере, функция подписи) –

+0

IIRC, x86 является единственным из трех платформ вы упомянули, где разные правила для stdcall и cdecl. –

+0

См. Обновление, добавленный заголовок. – Soonts

ответ

0
MY_EXPORT R the_function(A *a, const B *b, const uint8_t *c); 

Первые два аргумента содержат адреса структур.

extern static R the_function(A a, B b, byte[] c); 

Здесь вы передаете структуры по значению. Учитывая код в вопросе, это единственное отличие, которое я вижу. Чтобы передать адреса структур, измените C# на:

extern static R the_function(ref A a, ref B b, byte[] c); 
+0

Эти структуры представляют объекты с подсчетом ссылок с API-интерфейсом C. Я хочу, чтобы код C# обрабатывал эти указатели как непрозрачные. Вот почему в коде C# я храню свои необработанные указатели в других структурах. Я мог бы использовать только тип IntPtr, но с этими структурами C# компилятор обеспечивает безопасность типа, например. Я не могу передать экземпляр B в вызов a_release (A a), потому что он не будет компилироваться. Обратите внимание, что мой код компилируется и работает на ARM (все конфигурации), X64 (все конфигурации) и X86 (когда .NET Native отключен), поэтому я думаю, что правильно сделал эту часть. – Soonts

+0

Ну, я не мог догадаться об этих деталях. Почему вы так много скрываете? Вы хотите помочь? –

+0

Извините, похоже, я скрываю. Это просто сложный SDK, над которым я работаю. Мой вопрос уже на две страницы, если я расскажу все эти технические детали, это будет намного дольше. – Soonts

4

Yikes! Похоже, может быть ошибка в .NET Native.Я попросил кого-то здесь в Microsoft взглянуть. Если вы хотите связаться с нами, не стесняйтесь писать нам по адресу [email protected]

Я обновлю это, поскольку мы знаем больше.

EDIT: Таким образом, существует определенная ошибка, если встроенная функция возвращает такие структуры. Оптимизатор оказался в состоянии, когда он выталкивает один дополнительный аргумент в стек после двух параметров, и это вызывает ошибку.

Я открыл ошибку, и мы получим исправление для обновления 2 VS.

C#:

[StructLayout(LayoutKind.Sequential)] 
struct R 
{ 
    public int f1; 
    public int f2; 
    } 

[DllImport("DllImport_NativeDll.dll")] 
extern static R nativeBug(int a, int b); 

public static void Run() 
{ 
     R r = nativeBug(1, 2); 
} 

Native:

typedef struct 
{ 
    int f1; 
    int f2; 
} R; 

extern "C" __declspec(dllexport) R nativeBug(int a, int b) 
{ 
    R res 
    { 
     11, 12 
    }; 
    return res; 
} 

Код сгенерирован:

00f1766b 8b55fc   mov  edx,dword ptr [ebp-4] 
00f1766e 52    push edx 
00f1766f 8b45f8   mov  eax,dword ptr [ebp-8] 
00f17672 50    push eax 
00f17673 8d4ddc   lea  ecx,[ebp-24h] 
00f17676 51    push ecx <-- Bonus and unfortunate push 
00f176ab ff1524b4d200 call dword ptr [PInvokeAndCom!_imp__nativeBug (00d2b424)] 
+0

Спасибо, я только что отправил электронное письмо на мое минимальное решение для воспроизведения. – Soonts

Смежные вопросы