web-dev-qa-db-ja.com

FolderBrowserDialogダイアログが選択したフォルダーにスクロールしないのはなぜですか?

このスクリーンショットに示すように、選択したフォルダーはビューにありません。選択したフォルダーを表示するには、下にスクロールする必要があります。

enter image description here

同じダイアログで、選択したフォルダーが別のコンピューターに表示される

enter image description here

両方ともWindows 7を搭載した2台のコンピューターで実行しました。1台では正常に動作しますが、2台では動作しません。それはいくつかのコードの問題の代わりにWindows環境で何かに見えますか?誰でも修正を提案できますか?

コードに変更はありません。異なるドライブからの長いパスを使用しましたが、結果は同じです。

private void TestDialog_Click ( object sender, EventArgs e )
        {
            //Last path store the selected path, to show the same directory as selected on next application launch.
            //Properties.Settings.Default.LastPath

            FolderBrowserDialog dlgFolder = new FolderBrowserDialog ();

            dlgFolder.RootFolder = Environment.SpecialFolder.DesktopDirectory;

            dlgFolder.SelectedPath = Properties.Settings.Default.LastPath;

            if (dlgFolder.ShowDialog () == System.Windows.Forms.DialogResult.OK)
            {

                Properties.Settings.Default.LastPath = dlgFolder.SelectedPath;               

                Properties.Settings.Default.Save ();
            }

        }
69
Munawar

基本的な問題は、FolderBrowserDialogでの不十分な設計決定です。まず、FolderBrowserDialogは.NETコントロールではなく、Common Dialogであり、Windowsの一部であることを認識する必要があります。このダイアログのデザイナーは、ダイアログが表示され、初期フォルダーが選択された後、TreeViewコントロールにTVM_ENSUREVISIBLEメッセージを送信しないことを選択しました。このメッセージにより、TreeViewコントロールがスクロールされ、現在選択されているアイテムがウィンドウに表示されます。

したがって、これを修正するために必要なことは、FolderBrowserDialog the TVM_ENSUREVISIBLEメッセージの一部であるTreeViewを送信することだけです。右?まあ、それほど速くありません。これは確かに答えですが、私たちの邪魔になるものがいくつかあります。

  • まず、FolderBrowserDialogは実際には.NETコントロールではないため、内部Controlsコレクションがありません。つまり、.NETからTreeView子コントロールを見つけてアクセスすることはできません。

  • 次に、.NET FolderBrowserDialogクラスの設計者は、このクラスをsealに決定しました。この不幸な決定により、そこから派生してウィンドウメッセージハンドラをオーバーライドすることができなくなります。これを行うことができた場合、メッセージハンドラでTVM_ENSUREVISIBLEメッセージを取得したときに、WM_SHOWWINDOWメッセージを投稿しようとした可能性があります。

  • 3番目の問題は、ツリービューコントロールが実際のウィンドウとして実際に存在するまでTVM_ENSUREVISIBLEメッセージを送信できず、ShowDialogメソッドを呼び出すまで存在しないことです。ただし、このメソッドはブロックされるため、このメソッドが呼び出された後にメッセージを投稿する機会はありません。

これらの問題を回避するために、FolderBrowserDialogを表示するために使用できる単一のメソッドを持つ静的ヘルパークラスを作成し、選択したフォルダーまでスクロールさせます。これを管理するには、ダイアログのTimerメソッドを呼び出す直前に短いShowDialogを開始し、TreeView内のTimerコントロールのハンドルを追跡します。ハンドラー(ダイアログが表示された後)およびTVM_ENSUREVISIBLEメッセージの送信。

このソリューションは、FolderBrowserDialogに関する事前知識に依存するため、完全ではありません。具体的には、ウィンドウタイトルを使用してダイアログを見つけます。これは、英語以外のインストールでは壊れます。タイトルテキストやクラス名ではなく、ダイアログのアイテムIDを使用してダイアログ内の子コントロールを追跡します。これは、時間の経過とともに信頼性が高まると感じたためです。

このコードは、Windows 7(64ビット)およびWindows XPでテストされています。

コードは次のとおりです:(必要な場合:using System.Runtime.InteropServices;

public static class FolderBrowserLauncher
{
    /// <summary>
    /// Using title text to look for the top level dialog window is fragile.
    /// In particular, this will fail in non-English applications.
    /// </summary>
    const string _topLevelSearchString = "Browse For Folder";

    /// <summary>
    /// These should be more robust.  We find the correct child controls in the dialog
    /// by using the GetDlgItem method, rather than the FindWindow(Ex) method,
    /// because the dialog item IDs should be constant.
    /// </summary>
    const int _dlgItemBrowseControl = 0;
    const int _dlgItemTreeView = 100;

    [DllImport("user32.dll", SetLastError = true)]
    static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    static extern IntPtr GetDlgItem(IntPtr hDlg, int nIDDlgItem);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    /// <summary>
    /// Some of the messages that the Tree View control will respond to
    /// </summary>
    private const int TV_FIRST = 0x1100;
    private const int TVM_SELECTITEM = (TV_FIRST + 11);
    private const int TVM_GETNEXTITEM = (TV_FIRST + 10);
    private const int TVM_GETITEM = (TV_FIRST + 12);
    private const int TVM_ENSUREVISIBLE = (TV_FIRST + 20);

    /// <summary>
    /// Constants used to identity specific items in the Tree View control
    /// </summary>
    private const int TVGN_ROOT = 0x0;
    private const int TVGN_NEXT = 0x1;
    private const int TVGN_CHILD = 0x4;
    private const int TVGN_FIRSTVISIBLE = 0x5;
    private const int TVGN_NEXTVISIBLE = 0x6;
    private const int TVGN_CARET = 0x9;


    /// <summary>
    /// Calling this method is identical to calling the ShowDialog method of the provided
    /// FolderBrowserDialog, except that an attempt will be made to scroll the Tree View
    /// to make the currently selected folder visible in the dialog window.
    /// </summary>
    /// <param name="dlg"></param>
    /// <param name="parent"></param>
    /// <returns></returns>
    public static DialogResult ShowFolderBrowser( FolderBrowserDialog dlg, IWin32Window parent = null )
    {
        DialogResult result = DialogResult.Cancel;
        int retries = 10;

        using (Timer t = new Timer())
        {
            t.Tick += (s, a) =>
            {
                if (retries > 0)
                {
                    --retries;
                    IntPtr hwndDlg = FindWindow((string)null, _topLevelSearchString);
                    if (hwndDlg != IntPtr.Zero)
                    {
                        IntPtr hwndFolderCtrl = GetDlgItem(hwndDlg, _dlgItemBrowseControl);
                        if (hwndFolderCtrl != IntPtr.Zero)
                        {
                            IntPtr hwndTV = GetDlgItem(hwndFolderCtrl, _dlgItemTreeView);

                            if (hwndTV != IntPtr.Zero)
                            {
                                IntPtr item = SendMessage(hwndTV, (uint)TVM_GETNEXTITEM, new IntPtr(TVGN_CARET), IntPtr.Zero);
                                if (item != IntPtr.Zero)
                                {
                                    SendMessage(hwndTV, TVM_ENSUREVISIBLE, IntPtr.Zero, item);
                                    retries = 0;
                                    t.Stop();
                                }
                            }
                        }
                    }
                }

                else
                {
                    //
                    //  We failed to find the Tree View control.
                    //
                    //  As a fall back (and this is an UberUgly hack), we will send
                    //  some fake keystrokes to the application in an attempt to force
                    //  the Tree View to scroll to the selected item.
                    //
                    t.Stop();
                    SendKeys.Send("{TAB}{TAB}{DOWN}{DOWN}{UP}{UP}");
                }
            };

            t.Interval = 10;
            t.Start();

            result = dlg.ShowDialog( parent );
        }

        return result;
    }
}
80

私はこのスレッドが非常に古いことを知っていますが、拡張メソッドを使用すると、これをFolderBrowserDialog.ShowDialogメソッドに追加し、必要に応じて繰り返し使用できます。

サンプル(以下)は、簡単なSendKeysメソッドを使用しているだけです(これは実行するのが嫌いですが、この場合はうまく機能します)。 SendKeysメソッドを使用してダイアログで選択したフォルダーにジャンプする場合、Visual Studioでこれをデバッグしている場合、SendKeys呼び出しは現在のウィンドウ(アクティブなVSウィンドウ)に適用されます。より確実に、間違ったウィンドウがSendKeysメッセージを取得しないようにするために、拡張メソッドには、Marc Fが投稿したがC#に変換したものと同様の特定のウィンドウにメッセージを送信する外部メソッド呼び出しが含まれます。

internal static class FolderBrowserDialogExtension
{
    public static DialogResult ShowDialog(this FolderBrowserDialog dialog, bool scrollIntoView)
    {
        return ShowDialog(dialog, null, scrollIntoView);
    }

    public static DialogResult ShowDialog(this FolderBrowserDialog dialog, IWin32Window owner, bool scrollIntoView)
    {
        if (scrollIntoView)
        {
            SendKeys.Send("{TAB}{TAB}{RIGHT}");
        }

        return dialog.ShowDialog(owner);
    }
}
8
Brien Halstead

https://www.daniweb.com/software-development/csharp/threads/300578/folderbrowserdialog-expanding-the-selected-directory- から回避策を使用しました

FolderBrowserDialog^ oFBD = gcnew FolderBrowserDialog;
oFBD->RootFolder = Environment::SpecialFolder::MyComputer;
oFBD->SelectedPath = i_sPathImport;
oFBD->ShowNewFolderButton = false;     // use if appropriate in your application
SendKeys::Send ("{TAB}{TAB}{RIGHT}");  // <<-- Workaround
::DialogResult oResult = oFBD->ShowDialog ();

それは最も良い方法ではありませんが、私にとってはうまくいきます。
RootFolderなしでは、最初の呼び出しでは機能しませんが、2番目以降の呼び出しでは機能します。これにより、常に機能します。

他の人がこの障害はオペレーティングシステムに依存していることを観察したように:
Win 7 Pro x64 SP1を使用しています

7
Tobias Knauss

vB.Netコードでは、ダイアログを表示する直前にこのコード行を置くだけです。

SendKeys.Send ("{TAB}{TAB}{RIGHT}")
4
Loi Condes

SelectedPathとRootFolderは相互に排他的であるため、RootFolderが原因である可能性があることを別のフォーラムで読んでいます。つまり、両方は共存できませんが、デフォルトのRootFolder(。/folders)。

ただし、RootFolderをデスクトップ以外に変更すると、UNCパスに移動できなくなります。

Hans Passantへの回答:私はこのDialog Extensionを試しました。これにはTextBoxがありますが、運はありません。

フォルダーの参照ダイアログをカスタマイズしてパスを表示する

3
Munawar

私はそれを見つけました:

  1. .SelectedPathが「\」で終わる場合、ダイアログは下にスクロールしてパスを表示します。
  2. .SelectedPathの末尾が「\」ではないため、パスは選択されたままですが、表示されているとは限りません。
3
René

VB.NETで計算したので、C#に簡単に変換できます。私はフランス人で、VBの初心者です。とにかく、あなたは私の解決策を試すことができます。

私のアイデアは、folderBrowserDialogを表示する直前に非同期タスクを起動することです。

私はこれを自分で見つけましたが、ブラッドの投稿に触発されました。私のコードは次のとおりです。

Imports System.Threading.Tasks
Imports Microsoft.VisualBasic.FileIO.FileSystem

Public Enum GW
    HWNDFIRST = 0
    HWNDLAST = 1
    HWNDNEXT = 2
    HWNDPREV = 3
    OWNER = 4
    CHILD = 5
    ENABLEDPOPUP = 6
End Enum

Public Declare Function SendMessageW Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal msg As UInteger, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As String) As IntPtr
Public Declare Function FindWindowExW Lib "user32.dll" (ByVal hWndParent As IntPtr, ByVal hWndChildAfter As IntPtr, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszClass As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszWindow As String) As IntPtr
Public Declare Function GetWindow Lib "user32" (ByVal hwnd As IntPtr, ByVal wCmd As Long) As Long
Public Declare Function GetDesktopWindow Lib "user32" () As IntPtr
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As IntPtr, ByVal lpClassName As System.Text.StringBuilder, ByVal nMaxCount As Integer) As Integer

Private Sub FolderBrowserDialog_EnsureVisible(FB As FolderBrowserDialog, _Owner As IntPtr)
    Dim hwnd As IntPtr
    Dim sClassname As New System.Text.StringBuilder(256)
    Thread.Sleep(50)                                     'necessary to let FolderBrowserDialog construct its window
    hwnd = GetDesktopWindow()                            'Desktop window handle.
    hwnd = GetWindow(hwnd, GW.CHILD)                     'We will find all children.
    Do Until hwnd = 0
        If GetWindow(hwnd, GW.OWNER) = _Owner Then       'If one window is owned by our main window...
            GetClassName(hwnd, sClassname, 255)
            If sClassname.ToString = "#32770" Then       'Check if the class is FolderBrowserDialog.
                Exit Do                                  'Then we found it.
            End If
        End If
        hwnd = GetWindow(hwnd, GW.HWNDNEXT)              'Next window.
    Loop                                                 'If no found then exit.
    If hwnd = 0 Then Exit Sub
    Dim hChild As IntPtr = 0
    Dim hTreeView As IntPtr = 0
    Dim i As Integer = 0
    Do
        i += 1
        If i > 1000 Then Exit Sub                                       'Security to avoid infinite loop.
        hChild = FindWindowExW(hwnd, hChild, Nothing, Nothing)          'Look for children windows of FolderBrowserDialog.
        hTreeView = FindWindowExW(hChild, 0, "SysTreeView32", Nothing)  'Look for treeview of FolderBrowserDialog.
        Thread.Sleep(5)                                                 'delay necessary because FolderBrowserDialog is in construction, then treeview maybe not yet exist.
    Loop While hTreeView = 0
    If SendMessageW(hwnd, &H46A, 1, FB.SelectedPath) = 0 Then           'Send message BFFM_SETEXPANDED to FolderBrowserDialog.
        SendMessageW(hTreeView, &H7, 0, Nothing)                        'Send message WM_SETFOCUS to the treeeview.
    End If
End Sub


Dim My_save_dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) & "\My-Saves"

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim FolderBrowserDialog1 As New FolderBrowserDialog
    FolderBrowserDialog1.Description = "Choose your save files path."
    If Directory.Exists(My_save_dir) Then
        FolderBrowserDialog1.SelectedPath = My_save_dir
    Else
        FolderBrowserDialog1.SelectedPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
    End If

    Dim Me_handle = Me.Handle         'Store the main handle to compare after with each windows owner.
    Task.Run(Sub() FolderBrowserDialog_EnsureVisible(FolderBrowserDialog1, Me_handle))      'Here's the trick, run an asynchronous task to modify the folderdialog.
    If FolderBrowserDialog1.ShowDialog(Me) = System.Windows.Forms.DialogResult.OK Then
        My_save_dir = FolderBrowserDialog1.SelectedPath
    End If
End Sub

あなたの提案を待っています。 C#がわからないので、誰かがそれをC#に翻訳できます。

2
Marc F

C++/mfcでも同じ問題が発生します。 TVF_ENSUREVISIBLE msgを配置するために、BFFM_INITIALIZEDコールバックで:: SendMessageではなく:: PostMessageを使用することができました

    case BFFM_INITIALIZED: 
{
// select something
::SendMessage(m_hDialogBox, BFFM_SETSELECTION, TRUE, (LPARAM) pszSelection);


// find tree control
m_hTreeCtrl = 0;
HWND hchild = GetWindow(hWnd, GW_CHILD) ;
while (hchild != NULL)
{
  VS_TChar classname[200] ;
  GetClassName(hchild, classname, 200) ;

  if (VS_strcmp(classname, _T("SHBrowseForFolder ShellNameSpace Control")) == 0)
  {
    HWND hlistctrl = GetWindow(hchild, GW_CHILD) ;
    do
    { 
      GetClassName(hlistctrl, classname, 200) ;
      if (lstrcmp(classname, _T("SysTreeView32")) == 0)
      {
        m_hTreeCtrl = hlistctrl;
        break ;   
      }

      hlistctrl = GetWindow(hlistctrl, GW_HWNDNEXT) ;
    } while (hlistctrl != NULL);
  }      
  if (m_hTreeCtrl)
    break;
  hchild = GetWindow(hchild, GW_HWNDNEXT);      
}

if (m_hTreeCtrl)
{
  int item = ::SendMessage(m_hTreeCtrl, TVM_GETNEXTITEM, TVGN_CARET, 0);
  if (item != 0)             
    ::PostMessage(m_hTreeCtrl, TVM_ENSUREVISIBLE,0,item);
}
break;
}
2
Stefan_l_01

上記の議論と解決策を読みました。特にBrat Oestreicherは私を正しい方向に導いた。本質的に、最初にSHBrowseForFolderダイアログでTreeViewコントロールを見つけ、そのウィンドウにTVM_ENSUREVISIBLEメッセージ。以下はCでこれを行います。

#include <windows.h>
#include <objbase.h>
#include <objidl.h>
#include <Shlobj.h>
#include <Dsclient.h>
#include <wchar.h>
// 
//  EnumCallback - Callback function for EnumWindows 
// 
static BOOL CALLBACK EnumCallback(HWND hWndChild, LPARAM lParam)
{
   char szClass[MAX_PATH];
   HTREEITEM hNode;
   if (GetClassName(hWndChild, szClass, sizeof(szClass))
   &&  strcmp(szClass,"SysTreeView32")==0) {
      hNode = TreeView_GetSelection(hWndChild);    // found the tree view window
      TreeView_EnsureVisible (hWndChild, hNode);   // ensure its selection is visible
      return(FALSE);   // done; stop enumerating
   }
   return(TRUE);       // continue enumerating
}
// 
//  BrowseCallbackProc - Callback function for SHBrowseForFolder 
// 
static INT CALLBACK BrowseCallbackProc (HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData) 
{
    switch (uMsg) 
    { 
        case BFFM_INITIALIZED:
            SendMessage (hWnd, BFFM_SETEXPANDED, TRUE, lpData);    // expand the tree view
            SendMessage (hWnd, BFFM_SETSELECTION, TRUE, lpData);   // select the item
            break;
        case BFFM_SELCHANGED:
            EnumChildWindows(hWnd, EnumCallback,0);
            break;
    } 
    return 0; 
} 
// 
//  SelectDirectory - User callable entry point 
// 
int SelectDirectory (HWND hWndParent, char *path, int pathSize) 
{ 
    BROWSEINFO bi = {0};
    LPITEMIDLIST pidl = NULL;
    wchar_t ws[MAX_PATH];

    CoInitialize(0);
    if (pathSize < MAX_PATH) return(FALSE);

    swprintf(ws, MAX_PATH, L"%hs", path);

    bi.hwndOwner = hWndParent; 
    bi.lpszTitle = "Select Directory"; 
    bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
    bi.lpfn = BrowseCallbackProc;
    bi.lParam = (LPARAM) ws;

    pidl = SHBrowseForFolder (&bi); 
    if (pidl != NULL) 
    { 
        LPMALLOC pMalloc = NULL; 
        SHGetPathFromIDList (pidl, path);
        path[pathSize-1]= '\0';

        SHGetMalloc(&pMalloc);
        pMalloc->lpVtbl->Free(pMalloc,pidl);    // deallocate item 
        pMalloc->lpVtbl->Release(pMalloc);

        return (TRUE);
    } 
    return (FALSE);
} 

Gary Beene に感謝します。

1
Paul Ogilvie

このリンクには簡単に答えられる答えがあります(Windowsがあります8.1

FolderBrowserDialog:選択したディレクトリを展開する

0
user1760527

dlgFolder.RootFolder = Environment.SpecialFolder.DesktopDirectory;

とは異なります

dlgFolder.RootFolder = Environment.SpecialFolder.Desktop;

SpecialFolder.DesktopとSpecialFolder.DesktopDirectoryの違いは何ですか?

リンクされたスレッドは、パスとして同じ結果が得られることを示しています。ただし、1つは論理パスであり、もう1つは物理パスであるため、両者は同じではありません。

どちらかがフォルダーを開くダイアログのRootFolderに割り当てられている場合、結果の動作が異なることがあります。

.RootFolder割り当てとして、win7などの一部のバージョンのウィンドウは、どちらかを「デスクトップ」として扱います。つまり、「コンピューター」サブエントリを表示し、それを開いて個々のドライブ文字を表示できます。 .SelectedPathはどちらの方法でも選択されますが、選択されたパスは、デスクトップの論理パスが.RootFolderに割り当てられている場合にのみ表示されます。

さらに悪いことに、win10プレリリースでフォルダーの参照ダイアログを使用すると、「DesktopDirectory」がデスクトップディレクトリのコンテンツのみであり、論理デスクトップディレクトリへのリンクはまったくないように見えます。そして、その下のサブアイテムをリストしません。 win7用に作成されたアプリをwin10で使用しようとすると、非常にイライラします。

OPが抱えている問題は、論理デスクトップを使用すべきだったときに、ルートとして物理デスクトップを使用したことです。

OPの2つの異なるマシンが異なる応答をする理由については説明がありません。私は彼らがインストールされている.NETフレームワークの2つの異なるバージョンを持っていると推測します。

Win10プレリリースに[フォルダーの参照]ダイアログに「デスクトップでスタック」問題があるという事実は、win10プレリリースに同梱されている最新の.NETフレームワークが原因である可能性があります。残念ながら、私はまだ更新していないので、この(win10)ケースのすべての事実について無知のままです。

追伸win8でも「デスクトップでスタック」という症状が発生することがわかりました。

https://superuser.com/questions/869928/windows-8-1-folder-selection-dialog-missing-my-computer-and-sub-items

そこでの回避策は、win8で代替GUIを選択することでした。おそらく、win10プレリリースでも同様のことができます。

0
an odder guest

Marc Fの投稿に応えて-VB.NetをC#に変換しました

    public enum GW
    {
        HWNDFIRST = 0,
        HWNDLAST = 1,
        HWNDNEXT = 2,
        HWNDPREV = 3,
        OWNER = 4,
        CHILD = 5,
        ENABLEDPOPUP = 6
    }

    [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SendMessageW", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern IntPtr SendMessageW(IntPtr hWnd, uint msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
    [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindowExW", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern IntPtr FindWindowExW(IntPtr hWndParent, IntPtr hWndChildAfter, [MarshalAs(UnmanagedType.LPWStr)] string lpszClass, [MarshalAs(UnmanagedType.LPWStr)] string lpszWindow);
    [System.Runtime.InteropServices.DllImport("user32", EntryPoint = "GetWindow", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern UInt32 GetWindow(IntPtr hwnd, UInt32 wCmd);
    [System.Runtime.InteropServices.DllImport("user32", EntryPoint = "GetDesktopWindow", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern IntPtr GetDesktopWindow();
    [System.Runtime.InteropServices.DllImport("user32", EntryPoint = "GetClassNameA", ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Ansi, SetLastError = true)]
    public static extern int GetClassName(IntPtr hwnd, System.Text.StringBuilder lpClassName, int nMaxCount);

    private void FolderBrowserDialog_EnsureVisible(FolderBrowserDialog FB, IntPtr _Owner)
    {
        IntPtr hwnd = System.IntPtr.Zero;
        System.Text.StringBuilder sClassname = new System.Text.StringBuilder(256);
        Thread.Sleep(50); //necessary to let FolderBrowserDialog construct its window
        hwnd = GetDesktopWindow(); //Desktop window handle.
        hwnd = (System.IntPtr)GetWindow(hwnd, (UInt32)GW.CHILD); //We will find all children.
        while (!(hwnd == (System.IntPtr)0))
        {
            if (GetWindow(hwnd, (UInt32)GW.OWNER) == (UInt32)_Owner) //If one window is owned by our main window...
            {
                GetClassName(hwnd, sClassname, 255);
                if (sClassname.ToString() == "#32770") //Check if the class is FolderBrowserDialog.
                {
                    break; //Then we found it.
                }
            }
            hwnd = (System.IntPtr)GetWindow(hwnd, (UInt32)GW.HWNDNEXT); //Next window.
        } //If no found then exit.
        if (hwnd == (System.IntPtr)0)
        {
            return;
        }
        IntPtr hChild = (System.IntPtr)0;
        IntPtr hTreeView = (System.IntPtr)0;
        int i = 0;
        do
        {
            i += 1;
            if (i > 1000) //Security to avoid infinite loop.
            {
                return;
            }
            hChild = FindWindowExW(hwnd, hChild, null, null); //Look for children windows of FolderBrowserDialog.
            hTreeView = FindWindowExW(hChild, (System.IntPtr)0, "SysTreeView32", null); //Look for treeview of FolderBrowserDialog.
            Thread.Sleep(5); //delay necessary because FolderBrowserDialog is in construction, then treeview maybe not yet exist.
        } while (hTreeView == (System.IntPtr)0);
        if (SendMessageW(hwnd, 0x46A, 1, FB.SelectedPath) == (System.IntPtr)0) //Send message BFFM_SETEXPANDED to FolderBrowserDialog.
        {
            SendMessageW(hTreeView, 0x7, 0, null); //Send message WM_SETFOCUS to the treeeview.
        }
    }

これをテストし、正常に動作します。必ずSystem.Runtime.InteropServices、System.Threading、System.Threading.Tasksを参照してください。

0
MC9000

これは私のために働く

folderBrowserDialog1.Reset();  
folderBrowserDialog1.RootFolder = Environment.SpecialFolder.MyComputer;
folderBrowserDialog1.SelectedPath = WorkingFolder;

ただし、ダイアログを2回使用した後のみ

0
oferb