Blue Toque
Blue Toque

Reputation: 1804

"No Disk" error using GDAL from C#/.NET

I am using Tamas Szekeres builds of GDAL including the C# bindings in a desktop GIS application using C# and .net 4.0

I am including the entire GDAL distribution in a sub-directory of my executable with the following folder structure:

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

We are using EPSG:4326, and the software is built using 32-bit target since the GDAL C# API is using p/invoke to the 32-bit libraries (could try 64 bit since Tamas provides these, haven't gotten around to it yet).

When I run my application I get the following error

enter image description here

This error typically happens when software tries to access a device that is no longer attached, such as a removable drive. It is not possible to "catch" this exception because it pops up a system dialog.

After dismissing the dialog using any of the buttons, the software continues to execute as designed.

The error occurs the first time I call the following method

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

The strange stuff:

I have tried the following:

Assumptions

Configuration

The Question

I either need a direction to trap the error, or a tool or technique that will allow me to figure out what is causing it. I don't want to release the software with the possibility that some systems will have this behaviour.

Upvotes: 14

Views: 854

Answers (5)

user694971
user694971

Reputation: 421

You could add custom error handlers to gdal. This may help:

Link

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

Upvotes: 0

Blue Toque
Blue Toque

Reputation: 1804

It turns out there was no way to definitely answer this question. I ended up "solving" the problem by figuring out that there was some hardware registered on the system that wasn't present. It is still a mystery to me why, after several years, only GDAL managed to provoke this bug.

I will put the inability to catch this exception down to the idiosyncrasies involved with p/invoke and the hardware error thrown at a very low level on the system.

Upvotes: 0

Jeremy Thompson
Jeremy Thompson

Reputation: 65692

+1 Great question, but It is not possible to "catch"

Its one of these awful solutions that will turn up on DailyWTF in 5 years. But for now it is stored here 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);

    }

}

Upvotes: 1

Daniel van Os
Daniel van Os

Reputation: 41

Maybe you can try this:

  • Run diskmgmt.msc
  • Change the driveletter for Disk 2 (right click) if my assumption that Disk 2 is a Removable Disk is true
  • Run your application
  • If this removes the error, something in the application is referring to the old driveletter
  • It could be in the p/invoked libs
  • Maybe see: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46501 It talks about gcc somehow compiling a driveletter into a binary

Upvotes: 2

Adam
Adam

Reputation: 4227

I have no experience with this library, but perhaps some fresh eyes might give you a brainwave...

Firstly, WELL WRITTEN QUESTION! Obviously this problem really has you stumped...

Your note about the error not occurring after a rebuild screams out: Does this library generate some kind of state file, in its binary directory, after it runs? If so, it is possible that it is saving incorrect path information into that 'configuration' file, in a misguided attempt to accelerate its next start-up.

Perhaps scan this directory for changes between a 'fresh build' and 'first run'?

At very least you might find a file you can clean up on shut-down to avoid this alert...

HTH

Upvotes: 2

Related Questions