none
VisualBasic2005で作成したアプリケーションのトラブル RRS feed

  • 質問

  • VisualBasic2005についての質問です。

    わけあって、スタートアップサブルーチン(Sub Main)で、"Application.VisualStyleState" を、"VisualStyles.VisualStyleState.NonClientAreaEnabled"に設定し、クライアント領域のビジュアルスタイルを無効化しています。
    WindowsVistaHomePremium(SP1) 上で、この状態で起動したアプリケーション内において、SaveFileDialogクラスの"AutoUpgradeEnabled"プロパティを Trueにし、ShowDialogメソッドを呼び出すと、表示されたコモンダイアログ内でファイル名を入力及び、ファイルの種類を選択する入力エリアが表示されません。

    ~ サンプル ~

    'スタートアップ
    Sub Main()
     'ビジュアルスタイルを無効にする(途中で変更はできない)
    Application.VisualStyleState = VisualStyles.VisualStyleState.NonClientAreaEnabled

    DIm sfd As New System.Windows.Forms.SaveFileDialog

     'デフォルトでTrue。Falseにすると、XP以前のコモンダイアログが表示されるようになり発生しない。
    sfd.AutoUpgradeEnabled = True

     'SaveFileDialogを表示
    sfd.ShowDialog()

     'SaveFileDialogを破棄
    sfd.Dispose()
    End Sub

    ~ ここまで ~

    この現象は、OpenFileDialogクラスでは発生せず、Vista のSP1が適用されていない状態では、XP以前のコモンダイアログが表示される為、再現しません。再現される条件をまとめると以下のようになります。

    "Application.VisualStyleStateが"、"VisualStyles.VisualStyleState.NonClientAreaEnabled"
    ・"AutoUpgradeEnabled"が"True"
    ・実行環境がWindowsVistaでSP1が適用済み。
    ・実行環境のウインドウのテーマが"Vista"スタイル。

    上記条件が全て一致した場合に発生するようです。
    実行環境のFrameWorkのバージョンは3.0から3.5にアップしても特に変化は見られませんでした。
    "AutoUpgradeEnabled" プロパティをFalseにすることで、XP以前のコモンダイアログが表示されるようになり、一応の対策にはなるのですが、"Application.VisualStyleState" が、"VisualStyles.VisualStyleState.NonClientAreaEnabled"の状態で、Vistaで使用されている新しいコモンダイアログを正常に表示する方法はないのでしょうか?
    よろしくお願いします。

    2008年11月28日 5:32

回答

  • 環境が手元にないので、推測で申し訳ないのですが、

    アプリケーションのプロパティ画面を開き、[互換性]タブにある[互換モードでこのプログラムを実行する]をチェックしたら挙動に変化はないでしょうか?

    2008年11月28日 6:41
  •  RUNsys さんからの引用

    FrameWork2.0のSPなしがインストールされているケースを想定した場合、安易に"AutoUpgradeEnabled"を"False"にするわけにもいかなくなりました。

    リフレクションを使って下さい。

    そのプロパティが存在すればfalseに設定し、存在しなければ何もしないという形です。

     

    英語 & C#なサンプルですがリンクしておきます。

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3620611&SiteID=1

     

    ※C# to VBな変換ツールなどでVBに変換できます。

    Code Snippet
    Dim pi As PropertyInfo = GetType(OpenFileDialog).GetProperty("AutoUpgradeEnabled")
    If pi IsNot Nothing Then
      pi.SetValue(openFileDialog1, False, Nothing)
    End If

     

     

     RUNsys さんからの引用

    理想としましては、コモンダイアログのウインドウのみApplication.VisualStyleStateの影響を受けないようにしたいのです。
    コモンダイアログのウインドウ表示を別スレッドにすれば解決するかもしれませんが、何かもっと他にスマートな方法はないものでしょうか…

    この理想自体がスマートとはほど遠いように思えます。

    実現できたとしても、将来的に予測できない動作をする可能性を残します。

    (”現段階では”回避できるといったコードになり、将来のOS(Win7やそれ以降)で通用するとは限らない、裏道を使うような手法になりやすい)

     

     

    私的には、OSのVisualStyleに影響を受けるようなプログラムを作り込まないこと、OSの標準とされるユーザインターフェースに逆らうようなUI仕様を求めるべきではないと思います。

    凝りたいところは凝りたいのかもしれませんが、将来のバージョンアップで痛い目を見るのが見えていますので。。。。

     

    古いライブラリ・コンポーネントを使い続けることで受ける制約を引きずることもあるかもしれません。

    しかし、どこかのタイミングで見直ししないと、後になるほど苦しい思いをするかもしれません。

    2008年11月28日 14:40
    モデレータ

すべての返信

  • 環境が手元にないので、推測で申し訳ないのですが、

    アプリケーションのプロパティ画面を開き、[互換性]タブにある[互換モードでこのプログラムを実行する]をチェックしたら挙動に変化はないでしょうか?

    2008年11月28日 6:41
  • MK65536 さんありがとうございます。

    "AutoUpgradeEnabled"を"True"にし、互換モードで試してみましたところ、予想ではXP互換モードにすることでXP以前のコモンダイアログが表示されるだろうと思っていたのですが、予想に反して以下のような結果になりました。

    [XP互換モード]
    Vistaの新しいコモンダイアログが表示される。

    [Windows2000互換モード]
    WindowsXP以前のコモンダイアログが表示される。

    ( ※WindowsMe以前のモードは試していません。 )

    正直、何故??といった感じです。

    あと、"AutoUpgradeEnabled"プロパティですが、FrameWork2.0のSP1が適用されていないと、実行時にエラーになってしまいます。FrameWorkのインストールは、VB2005セットアッププロジェクトのFrameWork2.0ブートストラッパーを使用していますので、インストール時にFrameWork2.0(または3.0以上)がインストールされていれば問題ないのですが、FrameWork2.0のSPなしがインストールされているケースを想定した場合、安易に"AutoUpgradeEnabled"を"False"にするわけにもいかなくなりました。

    今回、教えて頂いた互換モードのやり方ですとWindows2000互換モードにすることで解決しそうですが、恐らくエミュレーションになってしまう為、今後の事を考えてもVistaで正式に対応しておきたいと考えています。(エミュレーションが嫌な理由としてはXP互換モードでVistaの新しいコモンダイアログが使用されてしまうといったように、予測できない動作をする場合があるからといった事もあります。

    理想としましては、
    コモンダイアログのウインドウのみApplication.VisualStyleStateの影響を受けないようにしたいのです。
    コモンダイアログのウインドウ表示を別スレッドにすれば解決するかもしれませんが、何かもっと他にスマートな方法はないものでしょうか…

    2008年11月28日 8:40
  •  RUNsys さんからの引用

    FrameWork2.0のSPなしがインストールされているケースを想定した場合、安易に"AutoUpgradeEnabled"を"False"にするわけにもいかなくなりました。

    リフレクションを使って下さい。

    そのプロパティが存在すればfalseに設定し、存在しなければ何もしないという形です。

     

    英語 & C#なサンプルですがリンクしておきます。

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3620611&SiteID=1

     

    ※C# to VBな変換ツールなどでVBに変換できます。

    Code Snippet
    Dim pi As PropertyInfo = GetType(OpenFileDialog).GetProperty("AutoUpgradeEnabled")
    If pi IsNot Nothing Then
      pi.SetValue(openFileDialog1, False, Nothing)
    End If

     

     

     RUNsys さんからの引用

    理想としましては、コモンダイアログのウインドウのみApplication.VisualStyleStateの影響を受けないようにしたいのです。
    コモンダイアログのウインドウ表示を別スレッドにすれば解決するかもしれませんが、何かもっと他にスマートな方法はないものでしょうか…

    この理想自体がスマートとはほど遠いように思えます。

    実現できたとしても、将来的に予測できない動作をする可能性を残します。

    (”現段階では”回避できるといったコードになり、将来のOS(Win7やそれ以降)で通用するとは限らない、裏道を使うような手法になりやすい)

     

     

    私的には、OSのVisualStyleに影響を受けるようなプログラムを作り込まないこと、OSの標準とされるユーザインターフェースに逆らうようなUI仕様を求めるべきではないと思います。

    凝りたいところは凝りたいのかもしれませんが、将来のバージョンアップで痛い目を見るのが見えていますので。。。。

     

    古いライブラリ・コンポーネントを使い続けることで受ける制約を引きずることもあるかもしれません。

    しかし、どこかのタイミングで見直ししないと、後になるほど苦しい思いをするかもしれません。

    2008年11月28日 14:40
    モデレータ
  • Azuleanさんありがとうございます。

    教えて頂いたリフレクションを使用することで、"Vista SP1"と"Vista以外のOSでFramework2.0 SPなし"の両方の環境でXP以前のコモンダイアログが正常に表示されることを確認できました。

     Azulean さんからの引用

    私的には、OSのVisualStyleに影響を受けるようなプログラムを作り込まないこと、OSの標準とされるユーザインターフェースに逆らうようなUI仕様を求めるべきではないと思います。


    まさに仰る通りだと思います。
    クライアント領域のビジュアルスタイル無効化は、使用している開発コンポーネントが、ビジュアルスタイルを適用した際にオーナードローを受け付けない仕様(これはコンポーネントの開発元に確認しましたので間違いないです)になっている為の苦肉の策です。
    ただ、それにこだわって推奨されない裏技的な実装をすることで、将来的なOSのバージョンアップやアップデートでに新しいバグの温床になる可能性は非常に高いと思います。

    とりあえず、今回は"AutoUpgradeEnabled"プロパティとリフレクションを組み合わせて対応したいと思います。

    Code Snippet

    'スタートアップ
    Sub Main()

    'ビジュアルスタイルを無効にする(途中で変更はできない)
    Application.VisualStyleState = VisualStyles.VisualStyleState.NonClientAreaEnabled
    Dim sfd As New System.Windows.Forms.SaveFileDialog
    Dim pi As System.Reflection.PropertyInfo
    'デフォルトでTrue。Falseにすると、XP以前のコモンダイアログが表示されるようになり発生しない。
    'sfd.AutoUpgradeEnabled = True
    pi = GetType(System.Windows.Forms.SaveFileDialog).GetProperty("AutoUpgradeEnabled")
    If Not pi Is Nothing Then
    pi.SetValue(sfd, False, Nothing)
    End If
    'SaveFileDialogを表示
    sfd.ShowDialog()
    'SaveFileDialogを破棄
    sfd.Dispose()

    End Sub




    2008年11月29日 1:12
  • MK65536さん、Azuleanさんありがとうございました。
    2008年11月29日 1:15