ntdll.dll UWP debug/release 错误

UWP debug/release error with ntdll.dll

我正在编写一个 UWP 程序来检测 LED 的颜色,这个程序 运行s 在 Raspberry Pi 3 和 Windows 10 IoT 上连接显示器。

程序所做的是在 LED 关闭的情况下拍摄参考图像,然后在 LED 开启时拍摄图像。

两个图像都被转换为相同的像素格式,然后被裁剪为较小的尺寸,其中仅显示 LED(参考和点亮的 LED)。

然后将这些图片部分转换为灰度,然后创建两者的差异图片,以便仅显示从参考变为点亮 LED 的像素。

为此,我使用了 NuGet 包 portable.AForge.imaging。代码如下所示。

            LEDBildNeu = LEDBild.Clone(PixelFormat.Format24bppRgb);
            ReferenzbildNeu = Referenzbild.Clone(PixelFormat.Format24bppRgb);

            Crop cropping = new Crop(new System.Drawing.Rectangle(Convert.ToInt32(x), Convert.ToInt32(y), 100, 100));

            CroppedLED = cropping.Apply(LEDBildNeu);
            CroppedReferenz = cropping.Apply(ReferenzbildNeu);

            Grayscale grayscale = new Grayscale(0.2125, 0.7154, 0.0721);
            GrayscaleReferenz = grayscale.Apply(CroppedReferenz);
            GrayscaleLED = grayscale.Apply(CroppedLED);
            
            Difference difference = new Difference(GrayscaleReferenz);
            Differenzbild = difference.Apply(GrayscaleLED);

只要我处于调试模式,这段代码就可以正常工作,所有功能都可以正常工作。 但是,当我更改为发布模式时,在构建时出现此错误:

1>C:\Users\morsch.nuget\packages\microsoft.net.native.compiler.7.2\tools\Microsoft.NetNative.targets(697,5): warning : MCG : warning MCG0007: Unresolved P/Invoke method 'ntdll.dll!memcpy' for method 'System.Byte* AForge.SystemTools.memcpy(System.Byte*, System.Byte*, System.Int32)'. Calling this method would throw exception at runtime. Please make sure the P/Invoke either points to a Windows API allowed in UWP applications, or a native DLL that is part of the package. If for some reason your P/Invoke does not satisify those requirements, please use [DllImport(ExactSpelling=true) to indicate that you understand the implications of using non-UWP APIs.

1>C:\Users\morsch.nuget\packages\microsoft.net.native.compiler.7.2\tools\Microsoft.NetNative.targets(697,5): warning : MCG : warning MCG0007: Unresolved P/Invoke method 'ntdll.dll!memset' for method 'System.Byte* AForge.SystemTools.memset(System.Byte*, System.Int32, System.Int32)'. Calling this method would throw exception at runtime. Please make sure the P/Invoke either points to a Windows API allowed in UWP applications, or a native DLL that is part of the package. If for some reason your P/Invoke does not satisify those requirements, please use [DllImport(ExactSpelling=true) to indicate that you understand the implications of using non-UWP APIs.

当我运行发布模式下的代码并到达创建差异图片的部分时,我得到异常

System.TypeLoadException: 'Unresolved P/Invoke method 'memcpy!ntdll.dll' from this method. Please look for this method in build warnings for more details.'

UWP 不支持

According to this 'memset' 和 'memcpy'。我现在的问题是:

为什么即使不支持这两个入口点,程序 运行 在调试模式下也没有任何问题,但一旦我转向发布模式,我就会遇到异常?

是否有解决该问题的方法?

我已经尝试使用

        [DllImport("ntdll.dll", EntryPoint = "memset")]

        [DllImport("ntdll.dll", EntryPoint = "memcpy")]

但要么是我做错了,要么就是这样不行。

我知道我可以编写一个解决方法,手动检查像素并创建新图像,但我想尽可能解决该问题。

我找到了一个有效的解决方案:

我没有使用 NuGet 下载 portable.AForge 包,而是从 GitHub 下载了 portable.AForge

找到名为 SystemTools.cs 的 .cs 文件(位于 AForge/Sources/Core/)。 用任何.cs编辑程序打开它,现在搜索所有代码,如

#if !MONO
...
#else

并将其删除。

这将从 ntdll.dll 中清除 memcpu() 或 memset() 的使用。 保存 SystemTools.cs,创建库并手动将 AForge-Package 添加到应用程序。

修改后没有任何问题。

找到正确的指令组合可能是一个非常令人沮丧且耗时的过程。以下是我通过电子邮件从 Microsoft 收到的其他信息,希望对您有所帮助:


有用的链接:

https://devblogs.microsoft.com/dotnet/net-native-deep-dive-dynamic-features-in-static-code/

https://docs.microsoft.com/en-us/dotnet/framework/net-native/runtime-directives-rd-xml-configuration-file-reference

https://docs.microsoft.com/en-us/dotnet/framework/net-native/runtime-directive-policy-settings

我们为让您的应用程序做好提前编译准备所做的分析非常广泛。我们需要为各种泛型类型、反射可调用包装器、序列化信息、编组存根等生成代码。在某些情况下(如您所想),由于 运行 组合学,我们最终生成的代码超出了绝对必要的范围。完全有可能对我们的启发式算法进行一些调整可以使您的应用程序在不损失任何功能的情况下进行编译。

实际上,有两种方法可以操纵编译器的行为。一种是通过将元素放入您的 csproj 来使用我们的一些编译器标志。另一个正在编辑您的应用程序 Properties\Default.rd.xml 文件。

编译器标志

有多种可用的标志,但这里有一些可能会有所帮助:

<ShortcutGenericAnalysis>true</ShortcutGenericAnalysis> - 可以帮助停止 运行 对泛型类型的分析并减少总体生成要求。

<UseDotNetNativeSharedAssemblyFrameworkPackage>false</UseDotNetNativeSharedAssemblyFrameworkPackage> - 消除了编译器必须应对的链接边界之一。我实际上怀疑关闭它会使事情变得更糟而不是更好但是整个程序优化器很难推理但是重建很便宜可以尝试。

运行时指令

上面有很多读物,但 tl;dr 是该文件由编译器读取,并且可以包含很多关于我们希望它做什么或忽略什么的提示等。还包括该文件的整体语法在上面的阅读中,但我认为我们对默认包含的一个特殊指令不是很清楚:

<Assembly Name="*Application*" Dynamic="Required All" />

该指令表示:“请 save/generate 提供足够的信息,以便可以通过反射检查和创建所有用户类型。”其中“用户类型”表示程序集中未使用 .NET 密钥令牌签名的任何类型。所以,基本上所有不是明确 .NET Framework 的东西。这会导致大量的膨胀,但也会让大多数人永远不必考虑这些事情。如果我们没有足够的信息,您将得到 运行 时间异常,例如 MissingMetadataException 或 TypeLoadException 或 NullReferenceException。每个实例都需要一些代码检查和摆弄指令才能得到修补。这可能是一个烦人的脆弱过程。总而言之,分析引擎非常复杂,您将“免费”获得很多东西,无需特殊指令或任何麻烦。完全有可能您的应用程序 运行 只需稍加调整即可变得很棒。

好的,现在的目标是删除该指令但仍然有一个可用的应用程序。有两种方法需要权衡,所以我将描述这两种方法,然后让您决定哪种方法适合您。这两个工作流程大致如下:

  1. 从零开始。

    一个。删除特殊的 Application 指令

    b。构建应用程序

    c。如果构建失败,请给我们发送电子邮件,否则...

    d。测试应用程序,看看是否遇到任何 运行时间错误

    e。如果这样做,您需要查看错误位置并查看添加一些指令是否有帮助,然后返回 (b)。

    f。如果你没有发现错误,你就完成了!万岁!

  2. 一切从头开始

    一个。删除特殊的 Application 指令

    b。获取项目的全套 dll 列表,例如通过检查此处:obj[architecture]\Release\ilc\in

    c。对于每个 dll,添加一个 Dynamic 指令。它们看起来像:<Assembly Name="ASSEMBLYNAMEWITHOUTEXTENTION" Dynamic="Required All"/>

    d。注释掉这些库的一些子集

    e。构建应用程序

    f。如果在 RHBIND 中构建再次失败,请转到 (d)

    克。测试应用程序,看看是否遇到任何 运行时间错误

    小时。如果这样做,您需要查看错误位置并查看添加一些指令是否有帮助,然后返回 (e)

    我。如果你没有发现错误,你就完成了!万岁!