• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:windows7のエクスプローラをVBAで操作-3)

windows7のエクスプローラをVBAで操作

このQ&Aのポイント
  • Excel-VBAで起動しているWindows7のエクスプローラに対してハンドルを取得し、クリックやテキストボックスへの入力を行いたい。
  • WindowsXPでは正常に動作していたが、Windows7でエクスプローラが変わったため、動作しなくなった。
  • ハンドルが取得できず、読み込み専用と表示されている。また、IAccessibleのUUID値が分からず、ボタンクリックや文字列のセットができない。

質問者が選んだベストアンサー

  • ベストアンサー
  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.11

ご報告ありがとうございました。 >2時間かかる検索もあります。 MsgWaitForMultipleObjectsを出した意図はDoEventsだけのループだと負荷が高くなるからなのですが、 使われないなら、Sleep APIぐらいは挟んでおいた方がいいですよ。 >検索したい設計書にはExcel、Word、PDF等があり、 了解です。 >WindowObject 不必要にVariant型を使うと遅くなるので固有型の方がいいのでは。

kootsuki4
質問者

お礼

kumatti1さん コメントありがとうございます。 > 使われないなら、Sleep APIぐらいは挟んでおいた方がいいですよ。 アドバイスありがとうございます、入れときました。 >>WindowObject 不必要にVariant型を使うと遅くなるので固有型の方がいいのでは。 as Object で定義しました。As InternetExplorerは自分的になじみが少ないので。 これでクローズしたいと思います。 いろいろとありがとうございました。感謝!

その他の回答 (10)

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.10

>ネットワーク越しの検索をやっていて、1つの検索はMax2時間くらいで、 >トータルで1昼夜かかっています。 いや、違くてトータルの時間でなくて、一回の検索に時間が掛かるならと言う意味で書きました。 (今更ですが)そもそも、エクスプローラで検索しなくてはいけない状況は不思議な気がします。 FileSystemObjectで遅ければ、Dir関数とかコマンドプロンプトのDirとかAPIのFindFirstFileとか使えばいいのではと。

kootsuki4
質問者

お礼

kumatti1さん いろいろとありがとうございました。 ご提供のコードにNavigate処理を入れて、標準モジュールからCallして一応完了する ことができました。 最後にUserformモジュールに書いたコードを載せています。 一応と言うのは、Navigateしたときに★(2)のie_DocumentCompleteのイベントは2回 発生しますが、SUB検索処理が★(1)のステップまで到達しているときに2回目の ie_DocumentCompleteのイベントを受けることがあり、誤動作してしまうことがあります。 この誤動作を検知したときはNavigateからリトライすることで回避しています。 とは言え、ここまで来れたのはkumatti1さんのおかげです。 ありがとうございました。 >いや、違くてトータルの時間でなくて、一回の検索に時間が掛かるならと言う意味 で書きました。 10秒で終わる検索もありますが、2時間かかる検索もあります。 >(今更ですが)そもそも、エクスプローラで検索しなくてはいけない状況は不思議な 気がします。 仕事で納品されたシステムの設計書から文字列を探したいときに使います。 検索したい設計書にはExcel、Word、PDF等があり、これらは検索できなければなりません。 Excelで言えば、セルの中の文字だけではなく、吹き出しの図形の中の文字列も検索 させたくあります。 エクスプローラの検索ではこれらができますので使用しています。(フリーソフトは使用禁止です) あっ、もしかしてFileSystemObjectとかFindFirstFileでも同様のことができるのかな? Option Explicit Private WithEvents EventHandler As Shell32.ShellFolderViewOC Private WithEvents ie As SHDocVw.InternetExplorer Private Filter_Done_flg As Boolean Private Navigate_Done_flg As Boolean Private Sub EventHandler_EnumDone() Filter_Done_flg = True EventHandler.SetFolderView Nothing End Sub Private Sub ie_DocumentComplete(ByVal pDisp As Object, URL As Variant)  ★ (2) If Not EventHandler Is Nothing Then EventHandler.SetFolderView pDisp.Document   End If End Sub Private Sub ie_NavigateComplete2(ByVal pDisp As Object, URL As Variant) Navigate_Done_flg = True End Sub Public Sub 検索処理(WindowObject, 検索フォルダ As String, 検索文字列 As String) Dim doc As IShellFolderViewDual3 Set EventHandler = Nothing Set ie = WindowObject Navigate_Done_flg = False ie.Navigate (検索フォルダ) While ie.Busy Or ie.ReadyState <> 4 DoEvents Wend Do DoEvents Loop Until Navigate_Done_flg = True  Filter_Done_flg = False Set EventHandler = New Shell32.ShellFolderViewOC ★(1) Set doc = ie.Document doc.FilterView 検索文字列 While ie.Busy Or ie.ReadyState <> 4 DoEvents Wend Do DoEvents Loop Until Filter_Done_flg = True Set EventHandler = Nothing Set ie = Nothing End Sub

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.9
  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.8

Microsoft Internet Controlsにも参照設定を行って、UserFormモジュールに貼り付けて、 リンク先の回答通りに直せば期待した動作をします。 フィルタリングに時間が掛かる状況は想像出来ませんが、もしそうならMsgWaitForMultipleObjectsを使うのもありかもしれません。 (再利用性を考慮すると)クラスモジュールもありかもしれませんが、その辺は適宜直してください。

kootsuki4
質問者

お礼

kumatti1さん 回答ありがとうございました。 UserFormモジュールに貼り付けでできました。感謝! kumatti1さんには大変お世話になりました。 > フィルタリングに時間が掛かる状況は想像出来ませんが、 ネットワーク越しの検索をやっていて、1つの検索はMax2時間くらいで、 トータルで1昼夜かかっています。 殆どクローズできる状況ですが、あと1~2日だけ開けさせて置いてください。

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.7
kootsuki4
質問者

お礼

kumatti1 さん、コードの提供ありがとうございました。 余り確認する時間がなかったのですが、コードのすべてを標準モジュールに 貼り付けたところ、以下の2行が赤く反転しました。 こちらExcel2010です。 Private WithEvents d As Shell32.ShellFolderViewOC Private WithEvents ie As SHDocVw.InternetExplorer 一部をクラスモジュール、一部を標準モジュールに置くのでしょうか。 以下の部分をクラスモジュールに置き、Private Sub UserForm_Initialize()以下を 標準モジュールに置くと、dとかieの変数の宣言が足りません。 Option Explicit Public WithEvents d As Shell32.ShellFolderViewOC Public WithEvents ie As SHDocVw.InternetExplorer Private flg As Boolean Private Sub d_EnumDone() flg = True Debug.Print "d_EnumDone" d.SetFolderView Nothing End Sub Private Sub ie_DocumentComplete(ByVal pDisp As Object, URL As Variant) d.SetFolderView pDisp.Document End Sub クラスモジュールを使ったことがなく、基本的なところの質問で申し訳ありませんが よろしくお願いします。

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.6

ShellFolderViewOC.EnumDoneイベントですが、タイミングがシビアみたいでこちらではまだ、上手く行ってません。 http://msdn.microsoft.com/en-us/library/windows/desktop/bb774010%28v=vs.85%29.aspx # 参照設定は「Microsoft Shell Controls And Automation」

kootsuki4
質問者

お礼

kumatti1 さん、アドバイスありがとうございます。 > ShellFolderViewOC.EnumDoneイベントですが、タイミングがシビアみたいでこち らではまだ、上手く行ってません。 ExcelVBA側でエクスプローラのイベントをハンドルすること自体から難しそうです ね。 ShellFolderViewOC.EnumDoneno のネット上の例題もあまりありませんでした。 クラスモジュールに書かないといけない・・・? エクスプローラを起動しないといけない・・・? Windows7でテストしたいと思いますので(もしかして問題なく動くかも)コードを お教え戴けないでしょうか。 以上よろしくお願いします。

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.5

Win.document.FilterView "hoge" の一文で済む様です。 IShellFolderViewDual3::FilterView method http://msdn.microsoft.com/en-us/library/windows/desktop/bb761289%28v=vs.85%29.aspx

kootsuki4
質問者

お礼

kumatti1さん、驚きの回答ありがとうございます。 >Win.document.FilterView "hoge" >の一文で済む様です。 と、あったので「何が一文で済むのか」分からないまま動かしてみると 検索文字列として hoge が入るじゃないですか。 びっくりしました。 ありがとうございました。 もう自分のスキルが届くところではないですね。 最後にもうひとつアドバイス戴けたらと思います。 検索させる部分と検索結果を取り出す部分の骨格は以下のようになりましたが、 検索が終わったことをどのようにして判断するかが分かっておりません。   (Sleep 10000 の部分) 定期的に検索結果を取得するとしても、終了を表す文字列も無さそうですし・・・。 何かのプロパティがあれば嬉しいのですが。 長い間お付き合いして戴き申し訳ありませんがよろしくお願いします。 Option Explicit Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Declare Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" ( _ ByVal hwndParent As Long, _ ByVal hwndChildAfter As Long, _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Sub 検索() Dim Win As Object Dim Search_Folder As String Dim Oshell As Object Dim Gyo As Long Dim Col As Long Dim hWnd As Long Dim Works As String Dim Folder As Object Dim Folderitem As Object Dim Folder_title As String Set Oshell = CreateObject("Shell.Application") Set Win = Nothing For Each Win In Oshell.Windows() If Win.FullName = "C:\Windows\Explorer.EXE" Then Exit For End If Set Win = Nothing Next If Win Is Nothing Then Exit Sub ThisWorkbook.Sheets("sheet1").Cells.ClearContents Win.Navigate ("c:\xxx") Sleep 500 Win.document.FilterView "検索文字列" Sleep 10000 ' ここで検索終了を待ちたい ThisWorkbook.Sheets("sheet1").Cells(1, 1).Value = "結果なし" Set Folder = Win.document.Folder On Error Resume Next Folder_title = Folder.Items().Item().Path On Error GoTo 0 If Left(Folder_title, 4) = "検索場所" Then If Folder.Items().Count <> 0 Then Gyo = 1 For Each Folderitem In Folder.Items() For Col = 0 To 7 ThisWorkbook.Sheets("sheet1").Cells(Gyo, Col + 1).Value = Folder.GetDetailsOf(Folderitem, Col) Next Gyo = Gyo + 1 Next End If End If End Sub

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.4

こちらはWin8.1ですが、ここは >hWnd = FindWindowEx(hWnd, 0, "SearchBox", vbNullString) ' ★--> 0 return DirectUIHWND になってますね。

kootsuki4
質問者

お礼

ありがとうございます。 Windows7ですが、hWnd = FindWindowEx(hWnd, 0, "DirectUIHWND", vbNullString) でハンドルが確かに返ってきました。 InspectObjectsで見るとClass="SearchBox"なのですが、Classが"DirectUIHWND"みたいな文言もあります。 よく分かりません。

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.3

こちらでも確認したところ、Application.SendKeysでなくて、SendKeysなら 漢字文字列 もセット出来ました。 https://gist.github.com/kumatti1/9b6eac43e294db94e837 >UUID(IAccessible?)の値 継承関係のあるインターフェースIDならOKです。 IAccessible以外には IDispatch とか IUnknown とか。 --- Visual Studio評価版は3ヶ月利用できるようなので、C++を入れればSpy++も入るのでそちらからも確認されるとか。 IAccessibleの他にUI Automationてのもありますよ。

  • kumatti1
  • ベストアンサー率60% (73/121)
回答No.2

アドレスバーと同じ理屈でクリックさせてからでないと無理なのかも。 (調査用と言うわけでもないが)AccessibleObjectFromPointとかもありますよ。 hwndプロパティでハンドルが得られるので、「Ctrl + F」相当のキー送信をWM_KEYDOWN辺りで送れば、検索ボックスにフォーカスされるので、 (他プロセスであっても)AttachThreadInputでGetFocus(APIの方)でハンドルが得られるのでWM_SETTEXTやらWM_CHARを送信するとか。で確定はWM_KEYDOWNでVK_RETURNとか。 ↓コメントアウトしてる方が正しいです。 'Private objAcc As IAccessible Private objAcc As UUID >Const OBJID_CLIENT As Integer = &HFFFFFFFC Long型 --- ただ、この辺を見るとIUnknown_QueryService(提示のコードで言えば引数にieを指定)で IFolderView2インターフェースを得て制御するのが本来の実装なんでしょうね。 まあでもVBA向けのタイプライブラリがありませんので、C++でDLLを作ってVBAから呼び出すとかになるのかなと。 http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1496271564 http://www.activebasic.com/forum/viewtopic.php?t=1828

kootsuki4
質問者

補足

kumatti1さん 引き続きアドバイスありがとうございます。 >アドレスバーと同じ理屈でクリックさせてからでないと無理なのかも。 上位の"Search Box"のハンドルと "SearchEditBoxWrapperClass"のハンドルに対して SendMessage(hWnd, BM_CLICK, 0, 0)を実行してみましたが、やはり結果は同じで "SearchBox",のハンドルは取得できませんでした。 >(調査用と言うわけでもないが)AccessibleObjectFromPointとかもありますよ。 あるポイントのAccessibleObjectを取得できるみたいですね。まだ試しておりません。 >「Ctrl + F」相当のキー送信をWM_KEYDOWN辺りで送れば、検索ボックスにフォーカスされるので、 Navigateしたあとに、以下のコードを実行したら検索文字列"ABC"は入りました。 AppActivate ("xxx") ・・・検索フォルダの最下位のフォルダ名 Sleep 1000 Application.SendKeys "^f" Sleep 1000 Application.SendKeys "abc" しかし、漢字文字列を検索したいので、やはり"SearchEditBox"に対して文字を入れないとダメかなと思っています。またSendKeysは動作時点にフォーカスされているところにSendkeyされるので操作の制約ができてしまうかなと思っています。 と言うことで、 IAccessibleの攻略が必須のようです。 まだ分かっていないのですが、今回場合、UUID(IAccessible?)の値には何を与えるのでしょうか? OLEViewで見たのですがExplorer関連がいくつかありました(添付ファイル参照)。 Explorer Browser、Explorer Browser Results Folder、Explorer Navigation Bar、 Explorer Search Band、Explorer Travel Band、ExplorerCommandEnumeratorのどれ かとは思うのですが・・・。DLL名から推測するとか・・・? 試しにExplorerBrowserを展開するとIAccssibleObjectと言う如何にもそれっぽいものもあります。表示されるInterface=に続く数字がUUIDなのかな?どなたか教えて戴ければ有難いです。 また、よろしくお願いします。

回答No.1

If fullnames = "C:\Windows\Explorer.EXE" Then internetExplorer じゃないの? あと、参照設定がどうなってるか

kootsuki4
質問者

お礼

2014itochanさん アドバイスありがとうございました。 >internetExplorer じゃないの?   変数名をIEとしていたのが紛らわしかったですね。   Explorerです >あと、参照設定がどうなってるか 参照設定は次のようになっていました。   Visual Basic For Applications   Microsoft Excel 14.0 Object Library   OLE Automation   Microsoft Office 14.0 Object Library またよろしくお願いします。