14

私は、C# および .net 4.0 を使用するデスクトップ GIS アプリケーションで、C# バインディングを含むGDALのTamas Szekeresビルドを使用しています。

次のフォルダー構造を持つ実行可能ファイルのサブディレクトリに、GDAL ディストリビューション全体を含めています。

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

EPSG:4326 を使用しており、GDAL C# API が 32 ビット ライブラリに対してp/invokeを使用しているため、ソフトウェアは 32 ビット ターゲットを使用してビルドされています (Tamas がこれらを提供しているため、64 ビットを試すことができますが、まだ試していません)。まだ)。

アプリケーションを実行すると、次のエラーが表示されます

ここに画像の説明を入力

このエラーは通常、リムーバブル ドライブなど、接続されていないデバイスにソフトウェアがアクセスしようとしたときに発生します。システム ダイアログがポップアップするため、この例外を「キャッチ」することはできません。

いずれかのボタンを使用してダイアログを閉じた後、ソフトウェアは設計どおりに実行を続けます。

次のメソッドを初めて呼び出すと、エラーが発生します

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

奇妙なもの:

  • エラーは1台のコンピューターでのみ発生します(これまでのところ)
  • このソフトウェアを、32ビットと64ビットの両方の他のいくつかのコンピューターで問題なく実行しました
  • 私が使用しているGDAL shimライブラリをコンパイルした後の最初の実行ではエラーは発生しません。その後の各実行でのみ発生します
  • リリースやデバッグビルドに関係なく発生します
  • デバッガーが接続されているかどうかに関係なく発生します
  • Gdal.UseExceptions または Osr.UseExceptions(); をオンまたはオフにするかどうかに関係なく発生します。
  • リムーバブル ドライブを無効にすると、バグが消えます。これは、お客様に依頼することができないため、実際の解決策とは考えていません。

私は次のことを試しました:

  • エラーをキャッチする
  • GDAL ディレクトリと環境設定の変更
  • コンピューターとオペレーティング システムの変更: これは機能しました
  • SysInternals ProcMon を使用して、開かれているファイルを追跡しましたが、それらはすべて存在するファイルのようです
  • ハードドライブが故障したときに問題のコンピューターを再構築しましたが、役に立ちませんでした。
  • CCleanerを使用してレジストリを「クリーニング」する
  • GDAL ディレクトリ内のファイルは実行時に変更されません

仮定

  • アンマネージ コードでエラーが発生しています
  • GDAL の初期化中に、一部のパスが接続されていないコンピューター上のドライブを参照しています
  • これはコンピューターの構成エラーに限定されているという仮定にも取り組んでいます

構成

  • ウィンドウズ 7 プロ
  • インテル コア i7 920 @ 2,67GHz
  • 12.0GBのRAM
  • 64 ビット OS
  • ドライブ C: OS、開発 (Visual Studio 10) などを搭載した 120 GB SSD
  • ドライブ D: 1 TB WD 10,000k、データあり、データへのアクセスなし。

質問

エラーをトラップするための指示、またはエラーの原因を突き止めるためのツールまたはテクニックが必要です。一部のシステムでこの動作が発生する可能性があるソフトウェアをリリースしたくありません。

4

5 に答える 5

2

多分あなたはこれを試すことができます:

  • diskmgmt.msc を実行します。
  • ディスク 2 がリムーバブル ディスクであるという私の仮定が正しい場合は、ディスク 2 のドライブ文字を変更します (右クリック)。
  • アプリケーションを実行する
  • これでエラーが解消された場合、アプリケーション内の何かが古いドライブレターを参照しています。
  • p/invoked ライブラリにある可能性があります
  • たぶん参照してください: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46501 gcc が何らかの形でドライブレターをバイナリにコンパイルすることについて話しています。
于 2012-07-17T12:39:20.593 に答える
2

私はこのライブラリの経験がありませんが、おそらく新鮮な目で脳波が得られるかもしれません...

まず、よく書かれた質問です!明らかに、この問題は本当に困惑しています...

再構築が叫んだ後にエラーが発生しないことについてのメモ: このライブラリは、実行後にバイナリディレクトリに何らかの状態ファイルを生成しますか? その場合、次の起動を加速するための誤った試みで、誤ったパス情報をその「構成」ファイルに保存している可能性があります。

このディレクトリをスキャンして、「フレッシュ ビルド」と「最初の実行」の間の変更を確認してください。

少なくとも、このアラートを回避するためにシャットダウン時にクリーンアップできるファイルが見つかるかもしれません...

HTH

于 2012-07-16T22:12:24.547 に答える
1

+1 素晴らしい質問ですが、「キャッチ」することはできません

5年後にDailyWTFに登場するこれらのひどいソリューションの1つ. しかし、今のところ、ここに保存されています 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 に追加できます。これは役立つかもしれません:

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

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

于 2012-07-23T11:41:49.937 に答える
0

この質問に明確に答える方法はありませんでした。システムに存在しないハードウェアが登録されていることを突き止めて、問題を「解決」しました。数年後、なぜGDALだけがこのバグを引き起こすことができたのか、私にはまだ謎です.

この例外をキャッチできないのは、p/invoke に関連する特異性と、システム上で非常に低いレベルでスローされるハードウェア エラーに帰着します。

于 2013-03-02T04:40:49.047 に答える