14

我正在使用GDAL的Tamas Szekeres构建,包括使用 C# 和 .net 4.0 的桌面 GIS 应用程序中的 C# 绑定

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

\Plugins\GDAL
\Plugins\GDAL\gdal
\Plugins\GDAL\gdal-data
\Plugins\GDAL\proj

我们正在使用 EPSG:4326,并且该软件是使用 32 位目标构建的,因为 GDAL C# API 使用p/invoke到 32 位库(可以尝试 64 位,因为 Tamas 提供了这些,还没有解决它然而)。

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

在此处输入图像描述

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

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

第一次调用以下方法时出现错误

OSGeo.OSR.CoordinateTransformation.TransformPoint(double[] inout);

奇怪的东西:

  • 错误发生在一台计算机上(到目前为止)
  • 我已经在其他几台 32 位和 64 位计算机上运行该软件,没有问题
  • 编译我正在使用的 GDAL 垫片库后第一次运行时不会发生该错误,它只会在每次后续运行时发生
  • 无论发布或调试版本如何,它都会发生
  • 无论是否附加了调试器,它都会发生
  • 无论我打开还是关闭 Gdal.UseExceptions 或 Osr.UseExceptions();
  • 禁用可移动驱动器会导致该错误消失。这不是我认为的真正解决方案,因为我无法要求客户这样做。

我尝试了以下方法:

  • 捕捉错误
  • 更改 GDAL 目录和环境设置
  • 更改计算机和操作系统:这行得通
  • 使用 SysInternals ProcMon 来跟踪正在打开的文件没有运气,它们似乎都是存在的文件
  • 当硬盘驱动器发生故障时,我重新构建了有问题的计算机,但无济于事。
  • 使用CCleaner “清理”注册表
  • GDAL 目录中的文件在执行时保持不变

假设

  • 非托管代码中发生错误
  • 在 GDAL 初始化期间,某些路径指的是计算机上不再连接的驱动器
  • 我也在假设这仅限于计算机配置错误

配置

  • 视窗 7 专业版
  • 英特尔酷睿 i7 920 @ 2,67GHz
  • 12.0 GB 内存
  • 64 位操作系统
  • 驱动器 C:120 GB SSD,带操作系统、开发(Visual Studio 10)等
  • 驱动器 D:1 TB WD 10,000k 有数据,未访问数据。

问题

我要么需要一个方向来捕获错误,要么需要一个工具或技术来让我找出导致它的原因。我不想发布某些系统可能会出现这种行为的软件。

4

5 回答 5

2

我对这个图书馆没有经验,但也许一些新鲜的眼睛可能会给你一个脑波......

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

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

也许扫描此目录以查找“新构建”和“首次运行”之间的更改?

至少您可能会找到一个可以在关闭时清理的文件以避免此警报...

高温高压

于 2012-07-16T22:12:24.547 回答
2

也许你可以试试这个:

  • 运行 diskmgmt.msc
  • 如果我认为磁盘 2 是可移动磁盘的假设为真,请更改磁盘 2 的驱动器号(右键单击)
  • 运行您的应用程序
  • 如果这消除了错误,则应用程序中的某些内容指的是旧的驱动器号
  • 它可能在 p/invoked 库中
  • 也许看到:http ://gcc.gnu.org/bugzilla/show_bug.cgi?id= 46501 它谈到 gcc 以某种方式将驱动器号编译成二进制文件
于 2012-07-17T12:39:20.593 回答
1

+1 好问题,但不可能抓住”

它是这些糟糕的解决方案之一,将在 5 年内出现在DailyWTF上。但现在它存储在这里http://www.pinvoke.net/default.aspx/user32.senddlgitemmessage

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);

    }

}
于 2012-07-21T03:53:30.917 回答
0

事实证明,没有办法肯定地回答这个问题。我最终通过找出系统上注册的一些硬件不存在来“解决”问题。为什么几年后只有 GDAL 设法引发了这个错误,对我来说仍然是个谜。

我将无法捕获此异常归结为与 p/invoke 相关的特性以及在系统上以非常低的级别引发的硬件错误。

于 2013-03-02T04:40:49.047 回答
0

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

http://www.gdal.org/ogr/cpl__error_8h.html

http://trac.osgeo.org/gdal/ticket/2895

于 2012-07-23T11:41:49.937 回答