&引用;“无磁盘”;从C#/.NET使用GDAL时出错

&引用;“无磁盘”;从C#/.NET使用GDAL时出错,c#,.net,windows,gis,gdal,C#,.net,Windows,Gis,Gdal,我正在使用的构建包括使用C#和.NET4.0的桌面GIS应用程序中的C#绑定 我使用以下文件夹结构将整个GDAL发行版包含在可执行文件的子目录中: \Plugins\GDAL \Plugins\GDAL\gdal \Plugins\GDAL\gdal-data \Plugins\GDAL\proj 我们使用的是EPSG:4326,该软件是使用32位目标构建的,因为GDAL C#API用于32位库(可以尝试使用64位,因为Tamas提供了这些,还没有开始使用它) 当我运行我的应用程序时,我得到以

我正在使用的构建包括使用C#和.NET4.0的桌面GIS应用程序中的C#绑定

我使用以下文件夹结构将整个GDAL发行版包含在可执行文件的子目录中:

\Plugins\GDAL
\Plugins\GDAL\gdal
\Plugins\GDAL\gdal-data
\Plugins\GDAL\proj
我们使用的是EPSG:4326,该软件是使用32位目标构建的,因为GDAL C#API用于32位库(可以尝试使用64位,因为Tamas提供了这些,还没有开始使用它)

当我运行我的应用程序时,我得到以下错误

当不再连接软件(如可移动驱动器)时,通常会发生此错误。无法“捕获”此异常,因为它会弹出一个系统对话框

使用任何按钮取消对话框后,软件将继续按设计执行

错误发生在我第一次调用以下方法时

OSGeo.OSR.CoordinateTransformation.TransformPoint(double[] inout);
奇怪的是:
  • 错误发生在一台计算机上,并且只有一台计算机(到目前为止)
  • 我已经在其他几台32位和64位计算机上运行过这个软件,没有任何问题
  • 编译我正在使用的GDAL shim库后,在第一次运行时不会出现此错误,它只会在每次后续运行时出现
  • 无论发布版本或调试版本如何,都会发生这种情况
  • 无论是否附加了调试器,都会发生这种情况
  • 无论我是打开还是关闭Gdal.UseExceptions还是Osr.UseExceptions(),它都会发生 >强>禁用可移动驱动器导致错误消失。< /强>这不是我认为真正的解决方案,因为我不能要求客户这样做。
我尝试了以下方法:

  • 捕捉错误
  • 更改GDAL目录和环境设置
  • 改变计算机和操作系统:这是有效的
  • 使用SysInternals ProcMon跟踪正在打开的文件,它们看起来都是存在的文件
  • 当硬盘出现故障时,我重新构建了这台有问题的计算机,但毫无效果
  • 使用“清理”注册表
  • GDAL目录中的文件在执行时保持不变
假设
  • 非托管代码中发生错误
  • 在GDAL初始化期间,某些路径指的是计算机上不再连接的驱动器
  • 我还假设这仅限于计算机配置错误
配置
  • Windows 7 Pro
  • 英特尔酷睿i7 920@2,67GHz
  • 12.0 GB内存
  • 64位操作系统
  • 驱动器C:120 GB SSD,带操作系统、开发(Visual Studio 10)等
  • 驱动器D:1 TB WD 10000K,带数据,未访问数据
问题
我要么需要一个方向来捕捉错误,要么需要一个工具或技术来让我找出导致错误的原因。我不想在发布软件时,考虑到某些系统可能会有这种行为。

我没有使用此库的经验,但也许一些新鲜的眼睛会给你一个灵感

首先,写得好的问题!显然这个问题真的让你难倒了

您关于在重建后未发生错误的注释突然出现:此库在运行后是否在其二进制目录中生成某种状态文件? 如果是这样的话,它可能正在将不正确的路径信息保存到该“配置”文件中,从而错误地试图加速其下一次启动

也许可以扫描此目录以查找“新生成”和“首次运行”之间的更改

至少你可能会找到一个文件,你可以在关机时清理,以避免此警报


HTH

也许你可以试试这个:

  • 运行diskmgmt.msc
  • 如果我假设磁盘2是可移动磁盘,请更改磁盘2的驱动器号(右键单击)
  • 运行应用程序
  • 如果这消除了错误,则应用程序中的某些内容引用了旧的驱动器号
  • 它可能在p/libs中
  • 也许可以看到:它讨论了gcc以某种方式将驱动器号编译成二进制

    • +1一个很好的问题,但是不可能“抓住”

      这是一个可怕的解决方案,将在5年内出现。但现在它被储存在这里


      您可以将自定义错误处理程序添加到gdal。这可能有助于:


      事实证明,没有办法明确回答这个问题。 我最终“解决”了这个问题,因为我发现系统上有一些注册的硬件不存在。几年后,为什么只有格达尔设法挑起了这个bug,这对我来说仍然是个谜


      我将无法捕获此异常归因于p/invoke涉及的特性以及在系统上抛出的非常低级别的硬件错误。

      如果您愿意,您可以向上投票,以补偿我的赏金。我将检查目录中是否有启动时写入的某种文件。考虑到这一点,可能会有一些写入注册表的内容更难拦截。有人能推荐一个拦截注册表写入的工具吗?我猜SysInternals有一个。SysInternals绝对会处理监视器更新1:根据下面的第一个答案,我查看了GDAL目录中的文件数,并且文件数是稳定的。更新2:我采纳了自己的建议,使用设备管理器禁用了系统上的所有可移动设备。这“解决”了问题!这不是一个真正的解决办法,所以我将把这个问题留待讨论。如何跟踪哪个软件正在访问哪个可移动设备?可能是方法调用导致了异常,因此Visual Studio尝试加载库的原始源文件,这些源文件可能是从PC上指向空驱动器的驱动器编译而来的?不过,您应该可以使用ProcMon看到这一点。嘿!在过去的8个小时里你需要帮助吗?让
      using Microsoft.VisualBasic;  //this reference is for the Constants.vbNo;  
      
      public partial class Form1 : Form
      {
      [DllImport("user32.dll")]
      static extern IntPtr SendDlgItemMessage(IntPtr hDlg, int nIDDlgItem, uint Msg, UIntPtr wParam, IntPtr lParam);
      
      [DllImport("user32.dll", SetLastError = true)]
      public static extern IntPtr SetActiveWindow(IntPtr hWnd);
      
      // For Windows Mobile, replace user32.dll with coredll.dll
      [DllImport("user32.dll", SetLastError = true)]
      static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
      
      // Find window by Caption only. Note you must pass IntPtr.Zero as the first parameter.
      [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
      static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
      
      [DllImport("user32.dll", SetLastError = true)]
      static extern uint GetDlgItemText(IntPtr hDlg, int nIDDlgItem,[Out] StringBuilder lpString, int nMaxCount);
      
      public void ClickSaveBoxNoButton()
      {
          //In this example, we've opened a Notepad instance, entered some text, and clicked the 'X' to close Notepad.
          //Of course we received the 'Do you want to save...' message, and we left it sitting there. Now on to the code...
          //
          //Note: this example also uses API calls to FindWindow, GetDlgItemText, and SetActiveWindow.
          //    You'll have to find those separately.
      
          //Find the dialog box (no need to find a "parent" first)
          //classname is #32770 (dialog box), dialog box title is Notepad
          IntPtr theDialogBoxHandle; // = null;
          string theDialogBoxClassName = "#32770";
          string theDialogBoxTitle = "Notepad";
          int theDialogItemId = Convert.ToInt32("0xFFFF", 16);
          StringBuilder theDialogTextHolder = new StringBuilder(1000);
          //hardcoding capacity - represents maximum text length
          string theDialogText = string.Empty;
          string textToLookFor = "Do you want to save changes to Untitled?";
          bool isChangeMessage = false;
          IntPtr theNoButtonHandle; // = null;
          int theNoButtonItemId = (int)Constants.vbNo;
          //actual Item ID = 7
          uint theClickMessage = Convert.ToUInt32("0x00F5", 16);
          //= BM_CLICK value
          uint wParam = 0;
          uint lParam = 0;
      
          //Get a dialog box described by the specified info
          theDialogBoxHandle = FindWindow(theDialogBoxClassName, theDialogBoxTitle);
          //a matching dialog box was found, so continue
          if (theDialogBoxHandle != IntPtr.Zero)
          {
      
              //then get the text
              GetDlgItemText(theDialogBoxHandle, theDialogItemId, theDialogTextHolder, theDialogTextHolder.Capacity);
              theDialogText = theDialogTextHolder.ToString();
      
          }
      
          //Make sure it's the right dialog box, based on the text we got.
          isChangeMessage = Regex.IsMatch(theDialogText, textToLookFor);
      
      
          if ((isChangeMessage))
          {
              //Set the dialog box as the active window
              SetActiveWindow(theDialogBoxHandle);
      
              //And, click the No button
              SendDlgItemMessage(theDialogBoxHandle, theNoButtonItemId, theClickMessage, (System.UIntPtr)wParam, (System.IntPtr)lParam);
      
          }
      
      }