Ошибка "Нет диска" с использованием 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);
}
}
Ответ 4
Вы можете добавить настраиваемые обработчики ошибок в gdal. Это может помочь:
http://www.gdal.org/ogr/cpl__error_8h.html
http://trac.osgeo.org/gdal/ticket/2895
Ответ 5
Оказывается, не было никакого способа однозначно ответить на этот вопрос.
Я решил "решить" проблему, выяснив, что в системе было какое-то оборудование, зарегистрированное в системе, которой не было. Мне все еще остается загадкой, почему через несколько лет только GDAL удалось спровоцировать эту ошибку.
Я помещу неспособность поймать это исключение до особенностей, связанных с p/invoke, и аппаратной ошибки, брошенной на очень низком уровне в системе.