[リストへもどる]
一括表示

投稿時間:2003/04/02(Wed) 19:17
投稿者名:やまだ
Eメール:toru.yamada@seh.co.jp
URL :
タイトル:
コモンダイアログの表示
コモンダイアログを使ってファイルを選択するプログラムで、ダイアログを
「詳細表示」「日付降順」で「ファイル名の表示幅を広く」表示させたいのですが
その方法がわかりません。

ダイアログが表示されてからボタンで表示を切り替えることは出来ますが、
何度もファイルを選ぶ必要があるのではじめからそのように表示させたいのです。

書籍やネットで調べたのですが見つかりませんでした。
ご存じの方がありましたらお教えください。

投稿時間:2003/04/03(Thu) 09:21
投稿者名:peta
Eメール:
URL :
タイトル:
Re: コモンダイアログの表示
> コモンダイアログを使ってファイルを選択するプログラムで、ダイアログを
> 「詳細表示」「日付降順」で「ファイル名の表示幅を広く」表示させたいのですが
> その方法がわかりません。
>
> ダイアログが表示されてからボタンで表示を切り替えることは出来ますが、
> 何度もファイルを選ぶ必要があるのではじめからそのように表示させたいのです。

OCXでは無理ですが、GetOpenFileName()APIから作成するコモンダイアログ
なら可能です。
この場合、フックプロシージャでメッセージ処理をする必要があります。
APIを多用することになりますが、それでもやってみますか?

それと、「ファイル名の表示幅を広く」とは、選択ファイルが表示される
EditBoxですか?それとも、ファイル一覧が表示されるListViewっですか?

投稿時間:2003/04/03(Thu) 19:12
投稿者名:やまだ
Eメール:toru.yamada@seh.co.jp
URL :
タイトル:
Re^2: コモンダイアログの表示
返信ありがとうございます。

> OCXでは無理ですが、GetOpenFileName()APIから作成するコモンダイアログ
> なら可能です。

コモンダイアログと同じようなものを自分で作るということでしょうか?

> この場合、フックプロシージャでメッセージ処理をする必要があります。
> APIを多用することになりますが、それでもやってみますか?

現在不便で仕方がないので是非とも実現したいと思っています。

> それと、「ファイル名の表示幅を広く」とは、選択ファイルが表示される
> EditBoxですか?それとも、ファイル一覧が表示されるListViewっですか?

リストの方です。半角で30文字くらい表示させる必要があります。

投稿時間:2003/04/04(Fri) 05:29
投稿者名:peta
Eメール:
URL :
タイトル:
Re^3: コモンダイアログの表示
花ちゃん さん から紹介があった Visual Basic Station 
http://www1.harenet.ne.jp/~unaap/
[ライブラリ]-[サンプル] の 47, 49: コモンダイアログの拡張
が大変参考になりますので、解析してみて下さい。

お望みの機能を実現するにはフックプロシージャ(OFNHookProc)に少し手を
入れる必要がありますので、説明します。

1.「ファイル名の表示幅を広く」
(1)ダイアログ幅の変更
  ファイル名の表示幅(ListViewの幅)を変更する前に、先ずダイアログの幅を
  変更します。WM_NOTIFY 通知メッセージの通知コード CDN_INITDONE で変更
  処理します。例えば、こんな感じ。
    hDlg = GetParent(hwnd)
    Call GetWindowRect(hDlg, rcDlg)
    Call SetWindowPos(hDlg, 0, 0, 0, lngDlgWidth, _
                      rcDlg.Bottom - rcDlg.Top, SWP_NOMOVE)
(2)ListView幅の変更
  CDN_INITDONE ではListViewのウィンドウハンドルが得られない様なので、
  CDN_FOLDERCHANGE で取得します。ListViewは、"SHELLDLL_DefView"クラス
  の子ウィンドウの様なので、こんな感じ。
    hWndDef = FindWindowEx(hDlg, 0, "SHELLDLL_DefView", vbNullString)
    hwndLV = FindWindowEx(hWndDef, 0, "SysListView32", vbNullString)
  ウィンドウハンドルを得たら、上記(1)と同様の方法で幅を変更します。
  変更は、hWndDef と hwndLV の両方を同じ幅にして下さい。
2.「詳細表示」
  ListViewのビュースタイルを LVS_REPORT に変更する方法もありですが
  ここは、CDN_FOLDERCHANGE で、ListView幅の変更後、詳細ボタンに
  WM_COMMAND メッセージを送るのが簡単でしょう。こんな感じ。
    hWndTB = FindWindowEx(hDlg, 0, "ToolBarWindow32", vbNullString)
    Call SendMessage(hDlg, WM_COMMAND, &HA004, ByVal hWndTB)
    この処理は、初期表示に1回だけ実行する様にして下さい。
3.「日付降順」
  ヘッダーのマウスクリックをシミュレートする方法が簡単ですが、確実に
  やるなら、リストビューの LVM_SORTITEMS メッセージを使用して日付型
  ソートを行います。この処理は、CDN_FOLDERCHANGEにて、初期表示の
  「詳細表示」の後、1回だけ実行すればいいと思います。
  ソートの内容は、以下のサンプルを参考にして下さい。
  http://www.mvps.org/vbnet/code/callback/lvsortcallback.htm

  フックプロシージャの作成は危険を伴いますので、必ずエラーを潰して
  から実行する様にして下さい。

投稿時間:2003/04/07(Mon) 18:09
投稿者名:peta
Eメール:
URL :
タイトル:
Re^2: コモンダイアログの表示
> OCXでは無理ですが、

と、思ったんですが実験してみたら、それなりに可能な様です。
ただ、確実な方法かどうかは疑問ですので機能しない場合があるかも?
参考程度に。

' フォームモジュール
Option Explicit

Private Sub Command1_Click()
    Call Hook
    With CommonDialog1
        .InitDir = App.Path
        .Flags = cdlOFNHideReadOnly
        .ShowOpen
    End With
    Call UnHook
End Sub


' 標準モジュール
Option Explicit

Private m_hHook As Long

Private Type CWPSTRUCT
    lParam  As Long
    wParam  As Long
    Message As Long
    hwnd    As Long
End Type

Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _
        (ByVal idHook As Long, ByVal lpfn As Long, _
         ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Private Const WH_CALLWNDPROC = 4&
Private Declare Function UnhookWindowsHookEx Lib "user32" _
        (ByVal hHook&) As Long
Private Declare Function CallNextHookEx Lib "user32" _
        (ByVal hHook As Long, ByVal nCode As Long, _
         ByVal wParam As Long, lParam As Any) As Long

Private Declare Function GetParent Lib "user32" _
        (ByVal hwnd As Long) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
        (ByVal hWnd1 As Long, ByVal hWnd2 As Long, _
         ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
        (ByVal hwnd As Long, ByVal wMsg As Long, _
         ByVal wParam As Long, lParam As Any) As Long

Private Const WM_NOTIFY = &H4E&
Private Const WM_WINDOWPOSCHANGED = &H47&
Private Const WM_COMMAND = &H111&
Private Const WM_LBUTTONDOWN = &H201&
Private Const WM_LBUTTONUP = &H202&
Private Const MK_LBUTTON = &H1&

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Const HDM_FIRST = &H1200&
Private Const HDM_GETITEMRECT = (HDM_FIRST + 7)

Private Const LVM_FIRST = &H1000&
Private Const LVM_GETHEADER = (LVM_FIRST + 31)
Private Const LVM_SETCOLUMNWIDTH = (LVM_FIRST + 30)
Private Const LVSCW_AUTOSIZE = -1


Public Sub Hook()
    If (m_hHook <> 0) Then Call UnHook
    m_hHook = SetWindowsHookEx(WH_CALLWNDPROC, AddressOf FileDlgHookProc, _
                               App.hInstance, App.ThreadID)
End Sub

Public Sub UnHook()
    If (m_hHook = 0) Then Exit Sub
    Call UnhookWindowsHookEx(m_hHook)
    m_hHook = 0
End Sub

Private Function FileDlgHookProc(ByVal nCode As Long, _
                                 ByVal wParam As Long, _
                                 cwp As CWPSTRUCT) As Long
    If (nCode >= 0) Then
        Static hDlg As Long
        Static hwndLV As Long
        Static fReadyLV As Boolean
        Select Case cwp.Message
        Case WM_NOTIFY
            Dim hwndDef As Long
            Dim hwndTB As Long
            If (hwndLV = 0) Then
                hDlg = GetParent(cwp.hwnd)
                hwndDef = FindWindowEx(hDlg, 0, "SHELLDLL_DefView", vbNullString)
                hwndLV = FindWindowEx(hwndDef, 0, "SysListView32", vbNullString)
                If (hwndLV <> 0) Then
                    hwndTB = FindWindowEx(hDlg, 0, "ToolBarWindow32", vbNullString)
                    Call SendMessage(hDlg, WM_COMMAND, &HA004&, ByVal hwndTB)
                    Call SetLVColumnWidth(hwndLV, 0, 10)
                    fReadyLV = True
                End If
            End If
        Case WM_WINDOWPOSCHANGED
            If (fReadyLV) Then
                Call SetLVColumnClick(hwndLV, 3)
                Call SetLVColumnWidth(hwndLV)
                fReadyLV = False
                hDlg = 0
                hwndLV = 0
                Call UnHook
            End If
        End Select
    End If
    FileDlgHookProc = CallNextHookEx(m_hHook, nCode, wParam, cwp)
End Function

Private Sub SetLVColumnWidth(ByVal hwndLV As Long, _
                             Optional ByVal iItemHD As Long = 0, _
                             Optional ByVal dwWidth As Long = LVSCW_AUTOSIZE)
    Call SendMessage(hwndLV, LVM_SETCOLUMNWIDTH, iItemHD, ByVal dwWidth)
End Sub

Private Sub SetLVColumnClick(ByVal hwndLV As Long, _
                             ByVal iItemHD As Long)
    Dim hwndHD As Long
    Dim rcItem As RECT
    Dim lParam As Long
    hwndHD = SendMessage(hwndLV, LVM_GETHEADER, 0, ByVal 0&)
    Call SendMessage(hwndHD, HDM_GETITEMRECT, iItemHD, rcItem)
    lParam = ((rcItem.Left + rcItem.Right) / 2) Or _
             ((rcItem.Top + rcItem.Bottom) / 2) * &H10000
    Call SendMessage(hwndHD, WM_LBUTTONDOWN, MK_LBUTTON, ByVal lParam)
    Call SendMessage(hwndHD, WM_LBUTTONUP, MK_LBUTTON, ByVal lParam)
End Sub

投稿時間:2003/04/08(Tue) 17:57
投稿者名:やまだ
Eメール:toru.yamada@seh.co.jp
URL :
タイトル:
Re^3: コモンダイアログの表示
> > OCXでは無理ですが、
>
> と、思ったんですが実験してみたら、それなりに可能な様です。
> ただ、確実な方法かどうかは疑問ですので機能しない場合があるかも?
> 参考程度に。

ありがとうございます。
内容を理解するのには相当時間がかかりそうです。
とりあえずそのまま利用させてもらおうと思うのですが、
あとから教えていただいた方法でも「危険」があるのでしょうか。

投稿時間:2003/04/09(Wed) 10:37
投稿者名:Esc
Eメール:
URL :
タイトル:
Re^3: コモンダイアログの表示(WinXPでは)
私も興味があり、試させて頂きました。
Win98ではうまく詳細表示されるのですがWinXPではメッセージが違うのか
動作しません。WEB上でも検索して見たのですが、解りませんでした。

WinXPでは、どのように変更すればいいのでしょうか?
申し訳ありませんが、教えて頂けないでしょうか

投稿時間:2003/04/09(Wed) 13:06
投稿者名:peta
Eメール:
URL :
タイトル:
Re^4: コモンダイアログの表示(WinXPでは)
> Win98ではうまく詳細表示されるのですがWinXPではメッセージが違うのか
> 動作しません。

元来、まともな方法ではないので、そういうこともあるでしょう。
XP環境が用意できないので、調べることが出来ません。

詳細表示は、
    Call SendMessage(hDlg, WM_COMMAND, &HA004, ByVal hwndTB)
なので、推定として、
(1) ウィンドウハンドル hDlg, hwndDef, hwndLV, hwndTB の内、
1つ以上がゼロである。
(2) ツールバー詳細ボタンIDが &HA004 ではない。
と思われます。
調べれば直ぐ判ると思います。

もし実験されるであれば、元コードの一部を以下に変更した方が安全です。

Private Sub SetLVColumnWidth(ByVal hwndLV As Long, _
                             Optional ByVal iItemHD As Long = 0, _
                             Optional ByVal dwWidth As Long = LVSCW_AUTOSIZE)
    If (hwndLV = 0) Then Exit Sub
    Call SendMessage(hwndLV, LVM_SETCOLUMNWIDTH, iItemHD, ByVal dwWidth)
End Sub

Private Sub SetLVColumnClick(ByVal hwndLV As Long, _
                             ByVal iItemHD As Long)
    Dim hwndHD As Long
    Dim rcItem As RECT
    Dim lParam As Long
    If (hwndLV = 0) Then Exit Sub
    hwndHD = SendMessage(hwndLV, LVM_GETHEADER, 0, ByVal 0&)
    If (hwndHD = 0) Then Exit Sub
    If (SendMessage(hwndHD, HDM_GETITEMRECT, iItemHD, rcItem) <> 0) Then
        lParam = ((rcItem.Left + rcItem.Right) / 2) Or _
                 ((rcItem.Top + rcItem.Bottom) / 2) * &H10000
        Call SendMessage(hwndHD, WM_LBUTTONDOWN, MK_LBUTTON, ByVal lParam)
        Call SendMessage(hwndHD, WM_LBUTTONUP, MK_LBUTTON, ByVal lParam)
    End If
End Sub

投稿時間:2003/04/09(Wed) 14:05
投稿者名:Esc
Eメール:
URL :
タイトル:
Re^5: コモンダイアログの表示(WinXPでは)
早速の回答ありがとうございます。

> (1) ウィンドウハンドル hDlg, hwndDef, hwndLV, hwndTB の内、
> 1つ以上がゼロである。

ハンドルはすべて取得できております。

> (2) ツールバー詳細ボタンIDが &HA004 ではない。

詳細ボタンはWin98とWinXPでは少し違うようなので多分こちらかと思うのですが
詳細ボタンのIDはどのようにして調べればいいのでしょうか?
ご教授のほどお願いします。

投稿時間:2003/04/09(Wed) 19:43
投稿者名:peta
Eメール:
URL :
タイトル:
Re^6: コモンダイアログの表示(WinXPでは)
> > (1) ウィンドウハンドル hDlg, hwndDef, hwndLV, hwndTB の内、
> > 1つ以上がゼロである。
>
> ハンドルはすべて取得できております。
>
> > (2) ツールバー詳細ボタンIDが &HA004 ではない。
>
> 詳細ボタンはWin98とWinXPでは少し違うようなので多分こちらかと思うのですが
> 詳細ボタンのIDはどのようにして調べればいいのでしょうか?

詳細ボタンを押すと、hDlgにWM_COMMANDが送られるので、
そのwParamのLOWORD値を調べれば判ります。

' ツールバー詳細ボタンID確認用に改造
Private Function FileDlgHookProc(ByVal nCode As Long, _
                                 ByVal wParam As Long, _
                                 cwp As CWPSTRUCT) As Long
    If (nCode >= 0) Then
        Static hDlg As Long
        Static hwndLV As Long
        Static fReadyLV As Boolean
        Select Case cwp.Message
        Case WM_NOTIFY
            Dim hwndDef As Long
            '  -----------------
            ' Dim hwndTB As Long   ' コメントアウト
            Static hwndTB As Long  ' Static に変更
            '  -----------------
            If (hwndLV = 0) Then
                hDlg = GetParent(cwp.hwnd)
                hwndDef = FindWindowEx(hDlg, 0, "SHELLDLL_DefView", vbNullString)
                hwndLV = FindWindowEx(hwndDef, 0, "SysListView32", vbNullString)
                If (hwndLV <> 0) Then
                    hwndTB = FindWindowEx(hDlg, 0, "ToolBarWindow32", vbNullString)
                    '  ------- ここから、コメントアウト -------
                    ' Call SendMessage(hDlg, WM_COMMAND, &HA004&, ByVal hwndTB)
                    ' Call SetLVColumnWidth(hwndLV, 0, 10)
                    ' fReadyLV = True
                    '  ------- ここまで、コメントアウト -------
                End If
            End If
        Case WM_WINDOWPOSCHANGED
            If (fReadyLV) Then
                Call SetLVColumnClick(hwndLV, 3)
                Call SetLVColumnWidth(hwndLV)
                fReadyLV = False
                hDlg = 0
                hwndLV = 0
                Call UnHook
            End If
        '  ------- ここから、追加 -------
        Case WM_COMMAND
            If (cwp.lParam = hwndTB) Then
                Debug.Print "&H" & Hex(cwp.wParam And &HFFFF&)
            End If
        '  ------- ここまで、追加 -------
        End Select
    End If
    FileDlgHookProc = CallNextHookEx(m_hHook, nCode, wParam, cwp)
End Function

投稿時間:2003/04/10(Thu) 14:20
投稿者名:Esc
Eメール:
URL :
タイトル:
Re^7: コモンダイアログの表示(WinXPでは)
取得コードを作って頂きありがとうございました。
WinXPでは構造が違うので[表示メニュー]をクリックしてから[詳細]を
選ぶようになっていますので[表示メニュー]のクラス名に変更すれば
詳細メニューのIDは取得できたのですが、今度は[表示メニュー]を開ける
事ができません。
私にはちょっと無理なようです。もう少し勉強してから再挑戦します。
色々ご指導頂きありがとうございました。

 

投稿時間:2003/04/10(Thu) 23:12
投稿者名:peta
Eメール:
URL :
タイトル:
Re^8: コモンダイアログの表示
> WinXPでは構造が違うので[表示メニュー]をクリックしてから[詳細]を
> 選ぶようになっていますので[表示メニュー]のクラス名に変更すれば
> 詳細メニューのIDは取得できたのですが、今度は[表示メニュー]を開ける
> 事ができません。

コードからメニューを実行する場合、メニューを開く必要ありません。
メニュー項目のID(MenuID)が判れば可能と思います。
    Call SendMessage(hwnd, WM_COMMAND, MenuID, ByVal 0&)
ただ、WM_COMMANDをどのウィンドウ(hwnd)に送るか調べる必要がありますが、
多分、hDlg でしょう。

以下で確認できると思います。
(1)前に載せたボタンID取得コードの一部を下記と差し替える。
        '  ------- ここから、追加 -------
        Case WM_COMMAND
            If (cwp.lParam = 0) Then
                Debug.Print "MenuID = &H" & Hex(cwp.wParam And &HFFFF&)
                Debug.Print "hwnd = " & cwp.hwnd, hDlg
            End If
        '  ------- ここまで、追加 -------
(1)メニューを開いて、詳細項目を選択して、そのIDとhwndを確認。

投稿時間:2003/04/11(Fri) 01:17
投稿者名:Esc
Eメール:
URL :
タイトル:
Re9:コモンダイアログの表示
>         Case WM_COMMAND
>             If (cwp.lParam = 0) Then
>                 Debug.Print "MenuID = &H" & Hex(cwp.wParam And &HFFFF&)
>                 Debug.Print "hwnd = " & cwp.hwnd, hDlg
>             End If

最初 If 文をコメントアウトして取得したIDと同じIDが取得できhwnd も取得できましたが
やはり、Call SendMessage(hDlg, WM_COMMAND, &H702C, ByVal 0&) でも詳細にできません
でした。hDlg の部分を変更しても同じくなにも変化ありませんでした。

投稿時間:2003/04/11(Fri) 04:15
投稿者名:peta
Eメール:
URL :
タイトル:
Re:コモンダイアログ...
> 最初 If 文をコメントアウトして取得したIDと同じIDが取得できhwnd も取得できましたが
> やはり、Call SendMessage(hDlg, WM_COMMAND, &H702C, ByVal 0&) でも詳細にできません
> でした。hDlg の部分を変更しても同じくなにも変化ありませんでした。

Win98も同様に、LOWORD(cwp.wParam) = &H702 が検出されました。
但し、hwnd は、"SHELLDLL_DefView"クラスの hwndDef です。
試しに、Call SendMessage(hDlg, WM_COMMAND, &HA004, ByVal hwndTB)
の代わりに、Call SendMessage(hwndDef, WM_COMMAND, &H702C, ByVal 0&)
を使用したら、詳細表示されました。

もし、これでもダメでしたら、リストビューのビュースタイルを直接変更する方法  
    Call SetLVViewStyle(hwndLV)
があります。但し、有効なのは初期表示のみです。

Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
        (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
        (ByVal hWnd As Long, ByVal nIndex As Long, _
         ByVal dwNewLong As Long) As Long
Private Const GWL_STYLE = (-16)
Private Const LVS_TYPEMASK = &H3&
Private Const LVS_REPORT = &H1&

Private Sub SetLVViewStyle(ByVal hwndLV As Long, _
                           Optional ByVal dwViewStyle As Long = LVS_REPORT)
    If (dwViewStyle < 0 Or dwViewStyle > 3) Then Exit Sub
    If (hwndLV = 0) Then Exit Sub
    Dim dwStyle As Long
    dwStyle = GetWindowLong(hwndLV, GWL_STYLE)
    If ((dwStyle And LVS_TYPEMASK) <> dwViewStyle) Then
        dwStyle = (dwStyle Xor LVS_TYPEMASK) Or dwViewStyle
        Call SetWindowLong(hwndLV, GWL_STYLE, dwStyle)
    End If
End Sub