我正在构建一个Windows 10通用应用程序(手机+平板电脑)+库.在解决方案中,我有C++ DLL项目,它构建了my.dll
从C#调用的非托管项目.DLL导出如下:
// === 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平台.如果未选中"使用.NET Native工具链编译",它将在X86上运行.
如果选中"使用.NET Native工具链编译",则说明访问冲突,非托管DLL在X86上崩溃.我可以在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平台,看起来其他方法工作正常.
有什么想法在这里发生了什么?或者至少如何隔离问题?提前致谢.
更新:好的,这是一个最小的repro.
非托管代码:
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#store app:
[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
然后视觉工作室完全挂起.
即使使用.NET Native,X64构建也能正常工作.
哎呀!看起来.NET Native中可能存在错误.我已经请微软的人来看一看.如果您想与我们联系,请随时发送电子邮件至dotnetnative@microsoft.com.
我会更新这个更新.
编辑:所以如果本机函数返回这样的结构,肯定会有一个真正的错误.优化器最终处于这样一种状态,它在两个参数之后将一个额外的参数推送到堆栈,这就是造成错误的原因.
我已经打开了一个错误,我们将修复VS的Update 2.
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); }本机:
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)]