none
デザインモード(this.DesignMode)を正しく得ることができない場合があります。 RRS feed

  • 質問

  • Vista、 Visual Studio 2008 です。

    PictureBoxから派生したコントロールabcを作成しています。
    OnPaintで、if (this.DesignMode == false)  のようにして、
    デザインモードの時は、利用DLLの関数を実行しないようにしています。
    このコントロールを同じソリュション内にある上の階層のプロジェクトのフォームに乗せ利用しています。
    別に問題なく動いていたのですが。

    このコントロールが乗ったフォームが選択された状態(タブがある状態)で、
    別の簡単なテスト用の実行単位のプロジェクトを、このソリューションに追加し、
    そのテスト用のフォームを表示したまま、Vidual Studio を終わり、再度実行させると、
    デザインモードが正しく得られていないようで、利用DLLの関数が実行され、
    ”コントロールabcがデザイナでハンドルされていない例外をスローして、無効になりました。”
    となります。どうなっているのでしょうか?
    (終わり、再度実行しなくても、テスト用のフォームをタブをクリックし表示させただけで、
     起こるテスト用のフォームもありますが、終わり、再度実行の時が一番確実に起こります。)

    また、本体のソリューションには複数のプロジェクトがあり幾つものフォームがあります。
    それらが表示されままま、終わり再度立ち上げても、別に問題は発生しませんが、
    これらテスト用のプロジェクトのフォームとの違いは何なんでしょうか?

     

    2010年2月17日 2:17

回答

  • 半信半疑で試したところ、こちらでも再現しました。

    ただ、DesignMode が正しく機能しないという再現性の確認でしたら、音が鳴ってしまうという現象を再現する必要があるのですけど、本来の問題も DesignMode は関係ないようですね。

    試しに、
    if (this.DesignMode == false) Wrapper.MyBeep();
    というコードを
    if (bool.Parse("False")) Wrapper.MyBeep();
    に変えても、同じエラーが発生しました。

    それと、最初は同じように C++ でアンマネージ DLL を作成して確認したのですが、DLL はなくても再現しました。これも再現条件には必須でないようです。

    次のような構成でテストしました。

    ソリューション
    -Wrapper のクラスライブラリ
      … MyDLL.dll は必須ではなく、単なるメソッドでも良い。
    -MyPicture のクラスライブラリ
      … Wrapper の dll を参照。
      … 確かに DoubleBuffered が false でなければ再現しません。
    -メインの WindowsFormsApplication1 プロジェクト
      … MyPicture の dll を参照。
      … MyPicture を画面に配置。
      … スタートアッププロジェクトかどうかは不問。
    -フォームだけの WindowsFormsApplication2 プロジェクト
      … こちらをデザイナでアクティブにしてから IDE を再起動。

    Wrapper.dll がどこにあることを期待しているのかを調べるため、手当たり次第に配置してみたところ、なぜか IDE のフォルダ(C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE など)に配置するとエラーが発生しなくなりました。
    なんとなく想像はつきますが、おかしな結果ですね。

    この情報を見られた方の反応を待ってもらってから、必要により Connect へフィードバックされると良いかもしれません。(Azulean さんのご意見とか気になります(^^;)

    • 編集済み TH01 2010年2月24日 10:00
    • 回答としてマーク クサキ 2010年2月26日 2:03
    2010年2月24日 9:32

すべての返信

  • 入れ子になったユーザーコントロールの場合、DesignMode が正しく判定できないようです。
    フィードバックで何度もこの問題が提示されてるようですが、修正できないようですね。
    以下のスレッドで回避方法が提示されてますのでご覧ください。

    http://social.msdn.microsoft.com/Forums/ja-JP/csharpexpressja/thread/d946a597-0ba4-4880-b99b-13c728e2f39f

    ちなみに私の場合、上記スレを参考にして以下のようなクラスを作って回避しております。(VB ですみませんが・・・)

    Public NotInheritable Class DesignerInfo
    
        Public Shared Function IsDesignMode() As Boolean
    
            Dim ret As Boolean = False
    
            If (LicenseManager.UsageMode = LicenseUsageMode.Designtime) Then
                ret = True
            ElseIf (Process.GetCurrentProcess().ProcessName.ToUpper().Equals("DEVENV")) Then
                ret = True
            End If
    
            Return ret
    
        End Function
    
    End Class
    2010年2月17日 2:40
    モデレータ
  • ASP.NETでも発生する事がありその解決としては Page の(コントロールツリーの一番上の)コントロールのSiteを経由してDesignModeを取るという形で解決しました。

    Parentをたどれるだけたどって、そこのSiteからDesignModeを取るとうまくいくと思います。


    Kazuhiko Kikuchi
    2010年2月17日 7:24
  • 今回の場合は入れ子なんでしょうか?
    コントロールをフォームの上に貼り付けているだけで入れ子ではないように思えますが。

    PictureBoxから派生させているので、入れ子と同じことになっているのでしょうか?
    本体のソリューション全体だけでやっている分には問題なく、DesignModeは正しく把握できています。
     
    ちなみに、以下のようにコーディングしましたが、上手く行きません。
               int ExeMode = 1;
                if (Process.GetCurrentProcess().ProcessName.ToUpper().Equals("DEVENV") )
                {
                    ExeMode = 0;
                }
                if (this.DesignMode == true) 
                {                                    
                    ExeMode = 0;
                }
                if (ExeMode == 1)
                {                              
                       // DLL関数コール
                }

    デザイナーでフォームが壊れ、本体のソリューションが知らぬ間に壊れたのでは
    ないかと心配しましたが、今回の場合はテスト用のプロジェクトのフォームを開け
    ていなければ問題なさそうで一安心です。が、折角ですので、もう少し勉強させてください。

    2010年2月17日 9:23
  • OnPaint で実行時に DesignMode が正しく判定できてないのでしょうね。
    通常デザイナで貼り付ける際に OnPaint が実行される場合は正しく判定できるけど、
    デザイナではなく VisualStudio 自体が立ち上がる際に OnPaint イベントが発生するのでおかしくなってる?

    正直よく判りませんが、内部的にはネストされているのと同じような状況になっているのかも知れません。

    可能であれば、「デバッグ」→「外部プログラムの開始」 に devenv.exe を指定しデバッグしてみるといいかもしれません。
    以下の記事では VS 2003 ですが、VS2008 でも設定はあるので、デバッグできそうな気がします。

    http://libaty.seesaa.net/article/4339489.html


    ちなみに 私の環境ですが、

    Process.GetCurrentProcess().ProcessName.ToUpper().Equals("DEVENV")

    だけだとうまくいかない場合があったので

    LicenseManager.UsageMode = LicenseUsageMode.Designtime

    を入れるようにしています。
    2010年2月17日 10:13
    モデレータ
  • もし、ここまでのアドバイスでも改善に向かわないのであれば、再現可能な最小限のコード・手順を示してください。
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年2月17日 14:30
    モデレータ
  • 原因は分かりました。コントロールのコンストラクタで    
    this.DoubleBuffered = false;  を入れることで起こります。
       
            public abc() 
            {
                InitializeComponent();
                this.DoubleBuffered = false; 
            }

     入れないと、 if (this.DesignMode == false)  だけでも現象は起こりません。

     

    2010年2月18日 2:30
  • クサキさん
    > デザインモードが正しく得られていないようで、利用DLLの関数が実行され、
    > ”コントロールabcがデザイナでハンドルされていない例外をスローして、無効になりました。”
    > となります。どうなっているのでしょうか?

    エラーの原因が、OnPaint 内での DLL の関数の呼び出しであるということは突き止められているのですね?
    上記のエラーメッセージだけではそうとは限りませんので。

    「別の簡単なテスト用の実行単位のプロジェクト」は何者なんでしょうか?
    「これらテスト用のプロジェクトのフォームとの違いは何なんでしょうか?」と書かれていますが、逆にこちらがお聞きしたいと思いました。
    そのテストプロジェクト側でも、abc コントロールは使用されているのでしょうか?

    以下のような簡単なクラスでも、デザイン時にエラーが発生するのでしょうか?
    こちらには「テスト用のプロジェクト」がありませんが、そのためか期待通りに動作します。
    DoubleBuffered を false にされている理由も、糸口になりそうな気もしました。

    public class MyPictureBox : PictureBox
    {
        public MyPictureBox()
        {
            this.DoubleBuffered = false;
        }

        [DllImport("存在しない.dll")]
        private static extern void 存在しないDLLのメソッド();

        protected override void OnPaint(PaintEventArgs pe)
        {
            if (!this.DesignMode) 存在しないDLLのメソッド();
            base.OnPaint(pe);
        }
    }


    ところで、リンク先の私のコード、あんなに短いコードなのに汚いので、
    今回は関係ないようなのですが、焼き直したのを書かせてもらいます。(^^;

    public static class ControlExtensions
    {
        public static bool TrueDesignMode(this Control control)
        {
            while (control != null)
            {
                if (control.Site != null && control.Site.DesignMode)
                    return true;
                control = control.Parent;
            }
            return false;
        }
    }

    2010年2月18日 8:51
  • > エラーの原因が、OnPaint 内での DLL の関数の呼び出しであるということは突き止められているのですね?
    > 上記のエラーメッセージだけではそうとは限りませんので。
    DLL の関数は事前に初期化の関数が呼ばれていないと致命的なエラーになる可能性があります。
    その結果、デザイナーで見ていると、Formに乗ったこのコントロールがおかしくなってしまいます。
    この関数をやめてビープ音を鳴らす関数に置き換えると、そういうことは無くビープ音だけがします。

    >「別の簡単なテスト用の実行単位のプロジェクト」は何者なんでしょうか?
    >「これらテスト用のプロジェクトのフォームとの違いは何なんでしょうか?」と書かれていますが、逆にこちらが
    > お聞きしたいと思いました。
    > そのテストプロジェクト側でも、abc コントロールは使用されているのでしょうか?
    ソリューション内の他のプロジェクトとは、まったく独立したもので、abc コントロールとも関係ありません。
    コントロールの勉強のため一時的に作ったものです。
    単に、ボタンを1個の乗せたフォームでも問題を起こします。


    > 以下のような簡単なクラスでも、デザイン時にエラーが発生するのでしょうか?
    > こちらには「テスト用のプロジェクト」がありませんが、そのためか期待通りに動作します。
    > DoubleBuffered を false にされている理由も、糸口になりそうな気もしました。
    起こりませんか。コントロールを乗せたフォームは選択されていますか?

    以下が全てのコーティングです。
    this.DoubleBuffered = false をコメントアウトすると起きなくなります。

        public partial class Abc : PictureBox
        {
            public Abc()
            {
                InitializeComponent();
                this.DoubleBuffered = false;
            }
           
            protected override void OnPaint(PaintEventArgs e)
            {
                if (this.DesignMode == false)
                {
                    // DLLの関数をコール (初期化が行われていないとどうなるかわからない関数)
            // ビープ音の関数に置き換えるとビープ音だけがする。別に問題は起こらない。
                    base.OnPaint(e);
                }
            }
        }

    2010年2月19日 6:17
  • Azulean さんが書かれていることですけど、クサキさんの環境では、新規作成したソリューションでも発生しますでしょうか?
    このとき、上記クラスは既存のものではなく、上で書かれただけのようなシンプルなクラスを新規作成し、そこへ問題のテストプロジェクトを追加して確認してください。

    あとは、影響があるかわからないですが、一般的な確認になります。
    ・Visual Studio 2008 には SP1 を適用されていますか?
    ・Visual Studio には何かアドインを追加されていませんか?
    ・何かの常駐ソフトが関係していませんか?

    2010年2月19日 9:01
  • おそらく、誰も問題を再現できるほど把握できないので、答えようがないのではないでしょうか。

    内容を見た限りで想像できた状況は、

    ソリューションに、

     * Windows Forms プロジェクト ProjA
     * クラスライブラリ ProjC

    の2つのプロジェクトがあり、

     * ProjC に PictureBox を派生した Abc というコントロールがある
     * ProjA に、Abc を使用した Form1 がある

    という状況にて、

     * テスト用の ProjT を追加し、そこにボタンを1つ置いただけの Form2 を作成
     * Form2 をデザイナで表示した状態で Visual Studio を終了
     * Visual Studio を起動して、Form1 をデザイナで開くと Abc がエラー状態

    となっている。

    これであっていますか?
    2010年2月20日 10:27
  • より簡単なもので現象が発生しました。

    ①コントロール MyPicture プロジェクト : PictureBox から派生したもの
      以下、そのままのコーディングです。

    namespace DesignErr
    {
        public partial class MyPicture : PictureBox
        {
            public MyPicture()
            {
                InitializeComponent();
                this.DoubleBuffered = false;    // ★
            }

            protected override void OnPaint(PaintEventArgs e)
            {
                if (this.DesignMode == false)
                {
                    //Microsoft.VisualBasic.Interaction.Beep(); //   こちらは問題なし
                    
                    MyDLL.Beep();                  // ★こちらの場合問題発生

                    base.OnPaint(e);
                }
            }
        }
    }

      マイクロソフトのビープの場合は実行時にはビープ音がして、
     デザイン時にはビープ音がせず、想定通りに動いています。

     私のDLLの関数のビープの場合は実行の時にビープ音がし、想定通りですが、
     デザイン時にもここを通り想定外の動きで、致命的なエラーになっているようです。

      this.DoubleBuffered = false と自分のDLL(C++で作成)の関数を記述した時に、
     デザイン時に this.DesignMode == false が正しく動かないものと考えられます。


    ②Windows フォームアプリケーションプロジェクト(スタートフォーム)
     ①のコントロールを乗せているだけ。
     このフォームはタブで選択できるような状態にしておく。
     (①を変更した時はここからリビルドしてください)

    ③まったく無関係なWindows フォームアプリケーション(単にフォームだけ)
      このフォームが表示された状態で、VS2008 を終了し、再立ち上げした時に起こる。
     (再立ち上げの時、このフォームが表示されるようになっている)
      このフォームがより複雑な場合は、単にこのフォームに切り替え表示しただけで、起こる場合もありました。

     

    2010年2月23日 2:51
  • もしも MyDLL が今回の問題に関係している場合、クサキさん以外には問題の再現性テストはできないですね・・・。

    MyDLL は C# で作成されたものでしょうか?
    今回上で書かれたコードでは、OnPaint 以外には MyDLL を使用する部分はないですよね?
    MyDLL クラスの静的コンストラクタには何か弊害が発生するコードはないでしょうか?

    MyDLL についても、問題が発生する最小限のコードに絞り込まれる必要があると思います。
    本来の MyDLL は参照設定から外し、以下のコードに差し替えた場合には、クサキさんの環境でも音はなりませんよね?

    public static class MyDLL
    {
        public static void Beep()
        {
            System.Media.SystemSounds.Beep.Play();
        }
    }

    もう1点気になっていることとして、コンストラクタの
    InitializeComponent();
    をコメントにすると状況は変わらないでしょうか?
    これがあるということは、MyPicture の上に、何かコントロールもしくはコンポーネントが乗っているのでしょうか?

    ところで base.OnPaint(e) ですが、デザインモードかどうかにかかわらず、常に実行した方が良いと思います。

    2010年2月23日 8:14
  •   マイクロソフトのビープの場合は実行時にはビープ音がして、
     デザイン時にはビープ音がせず、想定通りに動いています。

     私のDLLの関数のビープの場合は実行の時にビープ音がし、想定通りですが、
     デザイン時にもここを通り想定外の動きで、致命的なエラーになっているようです。

    この差から、その DLL に何かうまく動かない要因があるのでしょう。
    DoubleBuffered = false は一つのきっかけに過ぎないのではないでしょうか。

    その固有の差について、第三者には全く分かりません。
    故に、再現することも、適切な解決案を提示することもできません。


    私が以前に示すべきだと求めたのは、第三者にも再現できる最小限のコードです。
    既に作られたバイナリを使う手法は、それを入手できない第三者には再現が不可能であるため、(厳しい言い方ですが、)意味がありません。


    # 恐らく、MyDLL を使用した場合、かなり早い段階で OnPaint が呼ばれるのでしょう。
    # その時点では DesignMode を適切に返すための ISite が登録されていないだけのように思えます。
    # 原因は知りません。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年2月23日 14:04
    モデレータ
  • 多分、今回は皆さんの方でも確認できると思います。
    これまでの分をまとめるため繰り返しになりますが、条件を書き出します。

    ①VS2008で作成された、C++のMFCのDLL  (MyDLL.dll)
     デフォルトで作成し、cppファイルを1つ追加し、以下の関数を1つ追加しました。
    __declspec( dllexport)  void MyBeep( void )  
    {
         Beep(100, 1000);
    }

      このDLLと以下のC#との関係は、OSの環境設定のPathでなされています。


    以下はC#になります。

    ②Wrapperクラスを作成 (★このWrapperクラスを経由すると問題が発生します)
    namespace DesignErr
    {
        public class Wrapper
        {
            [DllImport("MyDLL", EntryPoint = "MyBeep")]
            public static extern void MyBeep();
        }
    }

    ③コントロール MyPicture プロジェクト : PictureBox から派生したもの
      以下、そのままのコーディングです。

    namespace DesignErr
    {
        public partial class MyPicture : PictureBox
        {
            //[DllImport("MyDLL", EntryPoint = "MyBeep")] // 直接ここに書くと
            //public static extern void MyBeep();                // 問題が発生しません。

            public static extern void MyBeep();
            {
                InitializeComponent();
                this.DoubleBuffered = false;     // ★
            }

            protected override void OnPaint(PaintEventArgs e)
            {
                if (this.DesignMode == false)
                {
                    //Microsoft.VisualBasic.Interaction.Beep(); //   こちらは問題なし
                    //MyBeep();             // こちらは問題なし  
     
                    Wrapper.MyBeep();  // ★こちらの場合問題発生 

                    base.OnPaint(e);
                }
            }
        }
    }

    ④Windows フォームアプリケーションプロジェクト(スタートフォーム)
     ①のコントロールを乗せているだけ。
     このフォームはタブで選択できるような状態にしておく。
     (①を変更した時はここからリビルドしてください)

    ⑤まったく無関係なWindows フォームアプリケーション(単にフォームだけ)
      このフォームが表示された状態で、VS2008 を終了し、再立ち上げした時に起こる。
     (再立ち上げの時、このフォームが表示されるようになっている)
      このフォームがより複雑な場合は、単にこのフォームに切り替え表示しただけで、起こる場合もありました。


    エラーの内容:
    コントロール DesignErr.MyPicture がデザイナでハンドルされていない
    例外をスローして、無効になりました。

    例外:
    ファイルまたはアセンブリ 'Wrapper, Version=1.0.0.0,
    Culture=neutral, PublicKey Token=null'、またはその依存関係の
    1つが読み込めませんでした。指定したファイルが見つかりませんでした。

    2010年2月24日 2:53
  • 半信半疑で試したところ、こちらでも再現しました。

    ただ、DesignMode が正しく機能しないという再現性の確認でしたら、音が鳴ってしまうという現象を再現する必要があるのですけど、本来の問題も DesignMode は関係ないようですね。

    試しに、
    if (this.DesignMode == false) Wrapper.MyBeep();
    というコードを
    if (bool.Parse("False")) Wrapper.MyBeep();
    に変えても、同じエラーが発生しました。

    それと、最初は同じように C++ でアンマネージ DLL を作成して確認したのですが、DLL はなくても再現しました。これも再現条件には必須でないようです。

    次のような構成でテストしました。

    ソリューション
    -Wrapper のクラスライブラリ
      … MyDLL.dll は必須ではなく、単なるメソッドでも良い。
    -MyPicture のクラスライブラリ
      … Wrapper の dll を参照。
      … 確かに DoubleBuffered が false でなければ再現しません。
    -メインの WindowsFormsApplication1 プロジェクト
      … MyPicture の dll を参照。
      … MyPicture を画面に配置。
      … スタートアッププロジェクトかどうかは不問。
    -フォームだけの WindowsFormsApplication2 プロジェクト
      … こちらをデザイナでアクティブにしてから IDE を再起動。

    Wrapper.dll がどこにあることを期待しているのかを調べるため、手当たり次第に配置してみたところ、なぜか IDE のフォルダ(C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE など)に配置するとエラーが発生しなくなりました。
    なんとなく想像はつきますが、おかしな結果ですね。

    この情報を見られた方の反応を待ってもらってから、必要により Connect へフィードバックされると良いかもしれません。(Azulean さんのご意見とか気になります(^^;)

    • 編集済み TH01 2010年2月24日 10:00
    • 回答としてマーク クサキ 2010年2月26日 2:03
    2010年2月24日 9:32
  • 追加の情報です。

    ②のWrapperクラスをは何れのクラスとも別のプロジェクトです。
    ③のコントロール MyPicture プロジェクト と同じプロジェクトにしたら起こりません。


    以下、TH01さんの前のコメントに対するものです。

    > もう1点気になっていることとして、コンストラクタの
    > InitializeComponent();
    > をコメントにすると状況は変わらないでしょうか?
    変わりません。

    > これがあるということは、MyPicture の上に、何かコントロールもしくはコンポーネントが乗っているのでしょうか?Window フォームコントロールライブラリーでプロジェクトを作り、
    public partial class Canvas : UserControl を
    public partial class Canvas : PictureBox   に変更しています。
    その後、ツールボックスのPictureBoxを乗せています。
    そうすると自然に提示のコーディングのようになります。

    2010年2月24日 9:41
  • 返信が重なったようですね。
    もしも私の返信を見逃されていましたら見てください。そんなことはないでしょうけど(^^;

    > Window フォームコントロールライブラリーでプロジェクトを作り、
    > public partial class Canvas : UserControl を
    > public partial class Canvas : PictureBox   に変更しています。
    > その後、ツールボックスのPictureBoxを乗せています。

    了解しました。
    とても不可解な現象についての話題でしたので、念のために確認させていただきました。
    ちなみに、最後の PictureBox を乗せるという手順は不要に思われます。

    2010年2月24日 11:58
  • この情報を見られた方の反応を待ってもらってから、必要により Connect へフィードバックされると良いかもしれません。

    手元の Visual Studio 2008 Professional SP1 + Windows XP SP3 の環境で再現を確認しました。
    現象が発生した場合は、デザイナで何か操作する前に一旦閉じて、デザイナを開き直すと復旧します。
    ただ、ソース管理されていない場合は、意図せぬ変更が保存されるリスクがある点にご留意ください。

    この現象については Connect に登録して問題なさそうに思えます。

    # 既知の問題かどうか Connect で検索をかけようとしたらエラーばかり…。
    # VS2010 RC でどうなるかを見れると良かったんですが、環境の準備の時間がない orz

    ただ、元々問題にしていた、DesignMode の件は再現を確認していませんので判断を保留します。

    (Azulean さんのご意見とか気になります(^^;)

    ご指名を頂いてもあまり良い答えをできるとは思っていませんから!


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年2月24日 15:09
    モデレータ
  • これは、ラッパークラスの作成方法の問題ですね。メソッド OnPaint が JIT コンパイルされるとき、その参照メソッドの Wrapper.Beep がロードされようとして LoadLibrary が呼び出されて失敗している…ですよね?

    DllImport を利用する場合、そのメソッドはすべて private に宣言し、Managed な public メソッドを別途用意するようにすれば解決するでしょう。こうすることの利点は、JIT の問題以外にも、DllImport によるネイティブな引数を、.NET の managed な範囲に公開しなくてよくなる、ということもあります。

    Visual Studio とか DesignMode, C# などの問題ではなく、.NET の IL が native 呼び出しをどのようにコンパイルし、それが実行時にどのように展開されるかという問題ではないかと思います。

    DoubleBuffered で再現性がかわるのは、PictureBox が AllPaintInWMPaint を true にしているため、DoubleBuffered を false にするとWM_PAINTの応答に対して例外ハンドラが設定されなくなるためではないか、と。 
    public static class Wrapper
    {
        public static void Beep()
        {
          BeepAPI();
        }
    
        [DllImport(...)]
        private static extern void BeepAPI();
    }
    
    2010年2月25日 4:03
  • > その参照メソッドの Wrapper.Beep がロードされようとして LoadLibrary が呼び出されて失敗している…ですよね?

    いえ、違うと私は考えています。
    私の検証結果の返信で書きましたように、Wrapper の中で DllImport をしなくても発生します。
    次の場合でもエラーが発生しました。

    public static class Wrapper
    {
        public static void Beep() { }
    }

    今回の現象としては、マネージ DLL(A) からマネージ DLL(B) を使っている場合(ともに GAC 未配置)、DLL(B) の検索パスが IDE のフォルダになってしまう場合があるということのようです。

    今回の場合、ソリューションを開いた際にアクティブになるフォームと DoubleBuffer が引き金でしたが、他にもあるのではと思います。
    (なぜ DoubleBuffer が?と思っていたのですが、K.Takaoka さんの話、関係ありそうですね。理解できてませんけど…。)
    ただ、開いた際の状況によって変わることから、私は Visual Studio の問題だと考えます。(誰が dll を呼び出すかについて、難しい話があるのかもしれませんけど。)

    試しに devenv.exe.config にて Wrapper.dll に対する codeBase の指定を行ってみたところ、「プライベート アセンブリは appbase ディレクトリ外部に見つかりました」というエラーに変わりました。

    Azulean さん(に限らないですが、)
    間違っているところをご指摘いただけるだけでもありがたいです。

    2010年2月25日 5:31
  • すいません、ちゃんと読んでませんで...

    WM_PAINT うんぬんも、どうやら見当はずれのようです
    PictureBox に限らず、Panel などの DoubleBuffered が false のコントロールから派生すると、DoubleBuffered プロパティを変更しなくとも OnPaint から外部アセンブリを参照したところで FileNotFoundException になります。

    ダブルバッファリングをオフにすると再現するというより、ダブルバッファリングがオンの場合だと、何らかの手順と順序が逆転してうまいことアセンブリがロードできているようですね。

    正常に動作する場合(コードタブがアクティブな場合)と、正常に動作しない場合(フォームデザイナタブがアクティブな場合)で、プロジェクト アセンブリ キャッシュを比較してみると、wrapper クラスの入ったアセンブリがコピーされていません。これが原因でアセンブリのロードに失敗しているのだと思いますが、ビルドしなおすなどでプロジェクト アセンブリ キャッシュの再構築がかかるまで、ずっとコピーされないのが問題ですね。


    ※ Azulean さんも書かれていますが、「アセンブリが正常にロードできない問題」と、「DesignMode が false になっている問題」は、まったく別の問題で、アセンブリのロードが失敗する状況でも、例外発生時の DesignMode プロパティはきちんと true になっていました。
    2010年2月25日 13:17
  • 変な現象が出ていて困っていた時、この現象も出て私のプロジェクトが
    おかしくなったのか心配していましたが、他でもでるということです。
    状況さえ把握できれば、私としてしては運用上は何も問題ありません。

    まだ、難しい話が続きそうですが、Connect への登録はTH01さん代行して頂けませんが。
    (以前にもそのように進められたことがあったのですが、そのまま、になっています)
    既に、TH01の方が私より十分に把握されていて、皆さんのためになるかと思うのですが。

    2010年2月26日 2:01
  • はい、いいですよ。
    (本当は全然得意じゃないんですけど)
    ただ、報告するまでに時間はかかると思います。忘れたころになるかもしれません。

    報告の前に、まずは Visual Studio 2010 RC(をインストールしてそれ)でも試してみようとも考えています。
    そちらで再現しなければ報告しなくてもよいかなあとか思ったりするかもしれません。

    それと、K.Takaoka さんの「プロジェクト アセンブリ キャッシュ」の確認方法を教えていただけませんでしょうか?
    はじめて聞く言葉でしたし、検索しても見つかりませんでした。
    とても重要な情報だと思うので、報告に含めたいと思っています。
    よろしくお願いします。

    2010年2月26日 6:46
  • Visual Studio 2008 だと、ユーザの非ローミングストレージの Application Data\Microsoft\VisualStudio\9.0\ProjectAssemblies などです。
    2010年2月26日 11:59
  • ありがとうございます。
    こちらでも K.Takaoka さんのご報告内容を確認できました。

    エラーが発生した場合には、ProjectAssemblies 内に Wrapper.dll はコピーされていませんが、次のいずれかの操作を行ったタイミングでコピーされるようでした。

    A. コントロールが配置されたフォームのデザインタブを閉じてから開く。
    B. 同デザインタブを開き、当該コントロールをクリックする。

    上記 A の場合、開きなおした際のコントロールは正常に表示されました。


    Visual Studio 2010 RC がインストールできたので試してみたところ、2010 では発生しませんでした。

    2010 でのアセンブリのキャッシュを確認すると、ソリューションを開いた時点(当該デザインタブは非アクティブ)では 2008 と同様に ProjectAssemblies にはコピーされていないのですが、タブを開くとその時点で Wrapper.dll が ProjectAssemblies にコピーされました。
    ProjectAssemblies にコピーされるタイミングはもしかすると 2008 から変わっていないのかもしれませんが、DLL が参照されるタイミングは(起動時間短縮等の別事情かもしれませんが)改善されたのかもしれません。

    ただ、発生させる手順もありました。
    状況としては、上記正常な場合から Wrapper.dll を参照から削除すると、タブを開く際にはコピーされなくなり、エラーが発生しました。(実は何度か確認していたときに、これと同じ状況になってエラーが発生したのですが、再現手順は不明です。もしかすると削除したのかもしれません。)
    当然のことかもしれませんし、無理やりな感じがしますので、問題ないと思います。

    ところで、2010 RC の動作が Bata1 に比べてとても速くなっていてびっくりしました(Bata2 は試してません)。
    Bata1 でとても不安になっていたのですが、これで安心して購入できます。(^^;
    (メモリの少ない仮想マシン内で動作させた際の個人的な感想です。)

    2010年2月28日 11:15