Arent parameters passed to unmanaged x86 dll when building with .NET Native

I am creating a universal Windows 10 application (phone + tablets) + libraries. In the solution, I have a C ++ dll project that creates unmanaged my.dllcalls from C #. The DLL is exported as follows:

// === 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;
}

The testing application runs on ARM and X64 platforms. It works on X86 if "Compile with .NET Native tool chain" is not checked.

Unmanaged DLL crash on X86, if "Compile with .NET Native tool chain" is checked, indicating an access violation. I can reproduce both in Debug and Release builds.

, theres ​​, . # , #, :

unsafe___value = global::McgInterop.my_PInvokes.the_function( a, b, unsafe_c );

, .

++ . b - , a, c - , b.

, , . my.dll 100 + __cdecl, - ++ 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;
}

#:

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

.NET Native :

Unmanaged DLL: a = 1, b = 2
Result: f1=11, f2=12

.NET Native build:

Unmanaged DLL: a = 91484652, b = 1
Unhandled exception: Object reference not set to an instance of an object.
STATUS_STACK_BUFFER_OVERRUN encountered

.

X64 .NET Native.

+4
2

! , .NET Native. - Microsoft . , dotnetnative@microsoft.com.

, .

EDIT: , , . , .

, 2 VS.

#:

[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)]
+4
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);

. , , . , # :

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

Source: https://habr.com/ru/post/1619249/


All Articles