jjzjj

.net - .NET 与 .NET Core 2 的不同 P/Invoke 入口点

coder 2024-06-08 原文

我正在将一些代码从 .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 的水平

那么,问题是……为什么?

最佳答案

如果您想要可预测的结果,请求 CopyMemory 实际上是一个非常糟糕的主意。对于初学者来说,没有非托管应用程序调用任何名为 CopyMemory 的函数,因为它被定义为 Windows header 中 C memcpy 函数的简单别名。 kernel32.dll 中根本没有CopyMemory 导出,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 到 native 函数(希望只是作为权宜之计),您最好 P/Invoking 到 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 上运行)。

关于.net - .NET 与 .NET Core 2 的不同 P/Invoke 入口点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47014586/

有关.net - .NET 与 .NET Core 2 的不同 P/Invoke 入口点的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  3. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  5. java - 为什么 ruby​​ modulo 与 java/other lang 不同? - 2

    我基本上来自Java背景并且努力理解Ruby中的模运算。(5%3)(-5%3)(5%-3)(-5%-3)Java中的上述操作产生,2个-22个-2但在Ruby中,相同的表达式会产生21个-1-2.Ruby在逻辑上有多擅长这个?模块操作在Ruby中是如何实现的?如果将同一个操作定义为一个web服务,两个服务如何匹配逻辑。 最佳答案 在Java中,模运算的结果与被除数的符号相同。在Ruby中,它与除数的符号相同。remainder()在Ruby中与被除数的符号相同。您可能还想引用modulooperation.

  6. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

  7. .net - .NET 将如何影响 Python 和 Ruby 应用程序? - 2

    我很好奇.NET将如何影响Python和Ruby应用程序。用IronPython/IronRuby编写的应用程序是否会非常特定于.NET环境,以至于它们实际上将变得特定于平台?如果他们不使用任何.NET功能,那么IronPython/IronRuby相对于非.NET同类产品的优势是什么? 最佳答案 我不能说任何关于IronRuby的东西,但是大多数Python实现(如IronPython、Jython和PyPy)都试图尽可能忠实于CPython实现。不过,IronPython正在迅速成为这方面的佼佼者之一,并且在PlanetPyth

  8. ruby-on-rails - 如何用不同的用户运行nginx主进程 - 2

    A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(

  9. ruby - 如何使用 Ruby HTTP::Net 处理 404 错误? - 2

    我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。

  10. ruby - 从 sinatra 中的 before do block 返回不同的值 - 2

    有没有办法在sinatra的beforedoblock中停止执行并返回不同的值?beforedo#codeishere#Iwouldliketo'return"Message"'#Iwouldlike"/home"tonotgetcalled.end//restofthecodeget'/home'doend 最佳答案 beforedohalt401,{'Content-Type'=>'text/plain'},'Message!'end如果你愿意,你可以只指定状态,这里有状态、标题和正文的例子

随机推荐