Ошибка "Нет диска" с использованием GDAL из С#/. NET

Я использую Tamas Szekeres строит GDAL включая привязки С# в настольном GIS-приложении с использованием С# и .net 4.0

Я включаю весь дистрибутив GDAL в подкаталог моего исполняемого файла со следующей структурой папок:

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

Мы используем EPSG: 4326, а программное обеспечение построено с использованием 32-битной цели, поскольку API GDAL С# использует p/invoke для 32-битные библиотеки (можно попробовать 64 бит с тех пор, как Tamas предоставляет их, еще не добрались до него).

Когда я запускаю свое приложение, я получаю следующую ошибку:

enter image description here

Эта ошибка обычно возникает, когда программное обеспечение пытается получить доступ к устройству, которое больше не подключено, например съемный диск. Невозможно "поймать" это исключение, потому что оно выдает системный диалог.

После отклонения диалога с помощью любой из кнопок программное обеспечение продолжает выполняться в соответствии с запросом.

Ошибка возникает при первом вызове следующего метода

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

Странный материал:

  • Ошибка возникает на одном, и только один компьютер (пока)
  • Я запустил это программное обеспечение на нескольких других компьютерах без проблем 32 и 64 бит.
  • Ошибка не возникает при первом запуске после компиляции библиотеки подгонки GDAL, которую я использую, она возникает только при каждом последующем прогоне
  • это происходит независимо от выпуска или отладки сборки
  • Это происходит независимо от того, подключен ли отладчик или нет
  • Это происходит независимо от того, включаю ли я или нет Gdal.UseExceptions или Osr.UseExceptions();
  • отключение съемных дисков приводит к исчезновению ошибки. Это не то, что я считаю реальным решением, поскольку я не смогу попросить клиента сделать это.

Я пробовал следующее:

  • обнаружение ошибки
  • изменение каталогов GDAL и настроек среды
  • смена компьютеров и операционных систем: это сработало
  • используется SysInternals ProcMon для отслеживания того, какие файлы открываются без везения, все они выглядят как файлы, которые существуют
  • Я перекомпоновал компьютер, когда жесткий диск потерпел неудачу, но безрезультатно.
  • "очистка" реестра с помощью CCleaner
  • файлы в каталоге GDAL без изменений

Предположения

  • Ошибка в неуправляемом коде
  • Во время инициализации GDAL некоторый путь относится к диску на компьютере, который больше не привязан.
  • Я также работаю над предположением, что это ограничивается ошибкой конфигурации компьютера

Конфигурация

  • Windows 7 Pro
  • Intel Core i7 920 @2,67 ГГц
  • Оперативная память 12.0 ГБ
  • 64-разрядная ОС
  • Дисковод C: 120 ГБ SSD с ОС, разработка (Visual Studio 10) и т.д.
  • Драйвер D: 1 ТБ WD 10,000k с данными, которые не доступны для данных.

Вопрос

Мне нужно либо направление, чтобы уловить ошибку, либо инструмент или метод, которые позволят мне выяснить, что вызывает его. Я не хочу выпускать программное обеспечение с возможностью того, что некоторые системы будут иметь такое поведение.

Ответы

Ответ 1

У меня нет опыта работы с этой библиотекой, но, возможно, некоторые свежие глаза могут дать вам мозговую волну...

Во-первых, WELL WRITTEN QUESTION! Очевидно, эта проблема действительно вас превзошла...

Ваша заметка об ошибке, не возникающей после того, как перескакивает крик: Создает ли эта библиотека какой-то файл состояния в своем двоичном каталоге после его запуска? Если это так, возможно, что он сохраняет неверную информацию о пути в этот файл конфигурации, в ошибочной попытке ускорить следующий запуск.

Возможно, сканирование этого каталога для изменений между "свежей сборкой" и "первым запуском"?

По крайней мере, вы можете найти файл, который вы можете очистить при выключении, чтобы избежать этого предупреждения...

НТН

Ответ 2

Возможно, вы можете попробовать следующее:

  • Запустите diskmgmt.msc
  • Измените раскладку диска на диск 2 (щелкните правой кнопкой мыши), если мое предположение, что диск 2 является съемным диском, является истинным
  • Запустите приложение
  • Если это устранит ошибку, что-то в приложении относится к старому расписанию
  • Это может быть в p/invoked libs
  • Возможно, см.: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46501 В нем говорится о том, что gcc каким-то образом компилирует диск в двоичный

Ответ 3

+1 Большой вопрос, но Это not можно "поймать"

Это одно из этих ужасных решений, которое появится через DailyWTF через 5 лет. Но пока он хранится здесь 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 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);

    }

}

Ответ 5

Оказывается, не было никакого способа однозначно ответить на этот вопрос. Я решил "решить" проблему, выяснив, что в системе было какое-то оборудование, зарегистрированное в системе, которой не было. Мне все еще остается загадкой, почему через несколько лет только GDAL удалось спровоцировать эту ошибку.

Я помещу неспособность поймать это исключение до особенностей, связанных с p/invoke, и аппаратной ошибки, брошенной на очень низком уровне в системе.