我正在将一些代码从.NET(4.5)迁移到.NET Core(2),并且有一个像这样的多目标项目......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netcoreapp2.0</TargetFrameworks>
代码库使用来自kernel32的Win32 API函数CopyMemory
,但我发现我需要使用不同的入口点名称,具体取决于我所针对的框架。
#if NET45
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
#else
[DllImport("kernel32.dll", EntryPoint = "RtlCopyMemory", SetLastError = false)]
#endif
public static extern void CopyMemory(IntPtr dest, IntPtr src, IntPtr count);
我原本以为这一切都在比.NET
更低的水平所以,问题是......为什么?
答案 0 :(得分:4)
如果您想要可预测的结果,请求CopyMemory
实际上是一个非常糟糕的主意。对于初学者,没有非托管应用程序调用任何名为CopyMemory
的函数,因为它被定义为Windows标头中C memcpy
函数的简单别名。 CopyMemory
中根本没有kernel32.dll
导出,RtlCopyMemory
是否可用取决于您的平台。当您要求CopyMemory
被P / Invoked(如果有)时,应用于导入的函数的逻辑因平台而异。这是一个适用于Windows 10的小桌子:
+--------------+---------------+------------------------------+
| Platform | ExactSpelling | Resulting unmanaged function |
+--------------+---------------+------------------------------+
| .NET, 32-bit | true | - |
| .NET, 64-bit | true | - |
| .NET, 32-bit | false | RtlMoveMemory |
| .NET, 64-bit | false | memmove |
+--------------+---------------+------------------------------+
对于.NET Core,逻辑要简单得多:.NET Core并不关心这种向后兼容性的废话。如果您要求kernel32!CopyMemory
,那么它会尝试让您kernel32!CopyMemory
。由于根本没有这样的出口,它将失败。对于64位和32位运行时都是如此。
在64位Windows RtlCopyMemory
实际上作为导出存在,这就是为什么它适用于.NET Core(以及64位.NET Framework)。但是,值得注意的是,文档并不能保证它完全存在,因此似乎不宜依赖于此 - 除了更基本的问题之外,它会使您的代码在任何“代码”上都不可移植。不是Windows。
从.NET 4.6开始,Buffer.MemoryCopy
提供了一种便携式替代方案,也可以在.NET Core 2.0中使用。如果您必须 P / Invoke到本机函数(希望仅作为权宜之计),您最好关闭P /调用RtlMoveMemory
,因为它存在于32位和64位Windows:
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", ExactSpelling = true)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, IntPtr count);
这对于两个位都可以在.NET Core和.NET Framework上正常工作(当然,只要你在Windows上运行)。
答案 1 :(得分:2)
它与您定位的框架没有任何关系,重要的是过程的重要性。 .NET 4.5项目从Project&gt;开始。属性&gt;构建标签&gt; &#34;喜欢32位&#34;复选框已打开。 .NETCore大量使用64位代码,让你跳过一个环节来获得32位运行时。
CopyMemory()已经过时,可以追溯到早期的16位Windows版本。他们不得不为32位winapi保留它,有很多VBx程序使用它。但是要把他们的脚放到64位。否则在MSDN文章中有详细记载:&#34;此函数被定义为RtlCopyMemory函数。它的实现是内联提供的。有关更多信息,请参阅WinBase.h和WinNT.h&#34;。哪些值得一看,你会看到什么&#34;内联&#34;手段。实际上也没有使用RtlCopyMemory,而是用memcpy()代替它。
所以只需使用RtlCopyMemory代替任何一种风味。请记住,在Linux或MacOS上部署时,它无法正常工作。