使用ntdll.dll进行UWP调试/发布错误

时间:2017-12-12 14:35:39

标签: c# exception uwp raspberry-pi3 windows-10-iot-core

我正在编写一个用于检测LED颜色的UWP程序,该程序在带有Windows 10物联网的Raspberry Pi 3上运行,附带显示器。

程序执行的操作是在LED关闭的情况下拍摄参考图像,然后从LED打开图像。

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

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

为此,我使用NuGet-Package 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 \ 1.7.2 \ tools \ Microsoft.NetNative.targets(697,5):警告:MCG:警告MCG0007:未解决的P /为方法'System.Byte * AForge.SystemTools.memcpy(System.Byte *,System.Byte *,System.Int32)'调用方法'ntdll.dll!memcpy'。调用此方法将在运行时抛出异常。请确保P / Invoke指向UWP应用程序中允许的Windows API,或者作为程序包一部分的本机DLL。如果由于某种原因您的P / Invoke不满足这些要求,请使用[DllImport(ExactSpelling = true)表示您了解使用非UWP API的含义。

     

1> C:\ Users \ morsch.nuget \ packages \ microsoft.net.native.compiler \ 1.7.2 \ tools \ Microsoft.NetNative.targets(697,5):警告:MCG:警告MCG0007:未解决的P /为方法'System.Byte * AForge.SystemTools.memset(System.Byte *,System.Int32,System.Int32)'调用方法'ntdll.dll!memset'。调用此方法将在运行时抛出异常。请确保P / Invoke指向UWP应用程序中允许的Windows API,或者作为程序包一部分的本机DLL。如果由于某种原因您的P / Invoke不满足这些要求,请使用[DllImport(ExactSpelling = true)表示您了解使用非UWP API的含义。

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

  

System.TypeLoadException:来自此方法的'未解析的P / Invoke方法'memcpy!ntdll.dll'。请在构建警告中查找此方法以获取更多详细信息。'

UWP不支持

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

为什么程序在调试模式下运行没有任何问题,即使不支持这两个入口点,但是当我转向发布模式时,我会得到例外情况?

该问题是否有解决方法?

我已经尝试过使用

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

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

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

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

2 个答案:

答案 0 :(得分:1)

找到正确的指令组合可能是非常令人沮丧且耗时的过程。这是我通过电子邮件从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" />

此指令说:“请保存/生成足够的信息,以便可以通过反射检查和创建所有用户类型。”其中,“用户类型”是指程序集中未使用.NET密钥令牌签名的任何类型。 。因此,基本上所有不是显式.NET Framework的东西。这导致很多人but肿,但也使大多数人不必考虑这些事情。如果我们没有足够的信息,您将获得运行时异常,例如MissingMetadataException或TypeLoadException或NullReferenceException。每个实例都需要进行一些代码检查并摆弄指令以进行修补。这可能是一个令人烦恼的脆弱过程。综上所述,分析引擎非常复杂,您可以无偿地获得很多免费的东西,而无需特殊的指令或任何麻烦。只需稍作调整,您的应用程序就很有可能运行良好。

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

  1. 从无到有。

    a。删除特殊的 Application 指令

    b。构建应用

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

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

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

    f。如果您没有发现任何错误,那就大功告成!哇!

  2. 从一切开始

    a。删除特殊的 Application 指令

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

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

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

    e。构建应用

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

    g测试应用程序,看看是否遇到运行时错误

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

    i。如果您没有发现任何错误,那就大功告成!哇!

答案 1 :(得分:0)

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

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

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

#include <stdio.h>

int reverse(int numOne, int numTwo)
{
  int rev;
  rev = numTwo*10 + numOne;

  return rev;
}

int issquare(int num)
{
  int i, valid;
  valid = 0;
  for(i = 0; i < num; i++)
  {
    if((i*i) == num)
    {
      valid = 1;
    }
  }
  return valid;
}
int main()
{
  int num1, num2, normal, rev, alice, bob;
  scanf("%d %d", &num1, &num2);
  printf("%d %d", num1, num2);
  rev = reverse(num1, num2);
  normal = num1*10 + num2;
  bob = issquare(normal);
  alice = issquare(rev);
  if(bob==1)
  {
    if(alice==1)
    {
      printf("Tie");
    }
  }
  if(bob==1)
  {
    if(alice==0)
    {
      printf("Bob wins.");
    }
  }
  if(alice==1)
  {
    if(bob==0)
    {
      printf("Alice wins.");
    }
  }

  return 0;
}

并将其删除。

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

更改后,它没有任何问题。