初めての店舗開業を成功させよう>>

アドバイスをお願いします。
Excel-VBAで起動しているエクスプローラに対してハンドルを取得してクリックしたり、テキストボックスに文字をセットするプログラムを作って動かしています。
WindowsXPのときはできていたのですが、Windows7になったらエクスプローラが変わったため正しく動作しなくなりました。

やりたいのはエクスプローラに検索文字列(添付ファイル参照)をセットして検索をさせたいのです。
「windows7のエクスプローラをVBAで操作-1」「windows7のエクスプローラをVBAで操作-2」のタイトルで質問させていただき、下のコードを考えましたが、★のところでハンドルが返らず0でした。InspectObjectsで見ると「読み込み専用」と。これが原因ですか?どうしたらいいのだろう・・・。
またこのハンドルを取得して、AccessibleObjectFromWindowでIAccessible を取り出して、accDoDefaultActionしたいのですが、UUIDの値が分かりません。OLEViewで見たのですがExplorer関連がいくつかあり(添付ファイル参照)どれを使っていいものやら。ボタンクリックの後に文字列セットがあるのですが、まだたどり着けず。
IAccessible初心者です。
質問ばかりで済みませんがコーディングのアドバイスお願いします。

Option Explicit
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
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" _
(ByVal hWnd As Long, _
ByVal dwObjectID As Long, _
ByRef riid As Any, _
ByRef ppvObject As Any) As Long

Const WM_SETTEXT = &HC '文字列送信
Const BM_CLICK = &HF5 'クリック
Const OBJID_CLIENT As Integer = &HFFFFFFFC
Private Type UUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(7) As Byte
End Type
Private IID_IAccessible As UUID
Private oShell
Private ie
Private hWnd As Long
Private SearchBoxハンドル As Long
Private Search_Folder As String
Private RC As Long
'Private objAcc As IAccessible
Private objAcc As UUID
Private varChild As Variant
Private cnt
Private fullnames As String

Sub 検索指定のインプット()

Search_Folder = "c:\xxx"
Set oShell = CreateObject("Shell.Application")
For cnt = oShell.Windows().Count - 1 To 0 Step -1
' On Error Resume Next
Set ie = oShell.Windows().Item(cnt)
fullnames = ie.FullName
' On Error GoTo 0
If fullnames = "C:\Windows\Explorer.EXE" Then
ie.Navigate (Search_Folder)
hWnd = FindWindow("CabinetWClass", vbNullString)
hWnd = FindWindowEx(hWnd, 0, "WorkerW", vbNullString)
hWnd = FindWindowEx(hWnd, 0, "ReBarWindow32", vbNullString)
hWnd = FindWindowEx(hWnd, 0, "UniversalSearchBand", vbNullString)
hWnd = FindWindowEx(hWnd, 0, "Search Box", vbNullString)
hWnd = FindWindowEx(hWnd, 0, "SearchEditBoxWrapperClass", vbNullString)
hWnd = FindWindowEx(hWnd, 0, "SearchBox", vbNullString) ' ★--> 0 return
SearchBoxハンドル = hWnd
hWnd = FindWindowEx(SearchBoxハンドル, 0, "Button", "検索")
hWnd = FindWindowEx(SearchBoxハンドル, 0, "SearchEditBox", vbNullString)
' "SearchEditBox" に検索文字列入力の予定だった

With IID_IAccessible
.Data1 = &H68284FAA
.Data2 = &H6A48
.Data3 = &H11D0
.Data4(0) = &H8C
.Data4(1) = &H78
.Data4(2) = &H0
.Data4(3) = &HC0
.Data4(4) = &H4F
.Data4(5) = &HD9
.Data4(6) = &H18
.Data4(7) = &HB4
End With

RC = AccessibleObjectFromWindow(hWnd, OBJID_CLIENT, IID_IAccessible, objAcc)
' 80004005が返る
varChild = 2 ' Class="Button", Name="検索"のコントロールをクリックしたいが・・・
' RC = objAcc.accDoDefaultAction(varChild) ' 書き方が違うみたい・・・
' Class="SearchEditBox" に検索する文字列を入れたいが・・・
Exit Sub
End If
Set ie = Nothing
Next
End Sub

「windows7のエクスプローラをVBA」の質問画像

このQ&Aに関連する最新のQ&A

A 回答 (11件中1~10件)

ご報告ありがとうございました。



>2時間かかる検索もあります。
MsgWaitForMultipleObjectsを出した意図はDoEventsだけのループだと負荷が高くなるからなのですが、
使われないなら、Sleep APIぐらいは挟んでおいた方がいいですよ。

>検索したい設計書にはExcel、Word、PDF等があり、
了解です。

>WindowObject
不必要にVariant型を使うと遅くなるので固有型の方がいいのでは。
    • good
    • 1
この回答へのお礼

kumatti1さん
コメントありがとうございます。

> 使われないなら、Sleep APIぐらいは挟んでおいた方がいいですよ。
アドバイスありがとうございます、入れときました。

>>WindowObject 不必要にVariant型を使うと遅くなるので固有型の方がいいのでは。
as Object で定義しました。As InternetExplorerは自分的になじみが少ないので。

これでクローズしたいと思います。
いろいろとありがとうございました。感謝!

お礼日時:2014/05/30 05:27

>ネットワーク越しの検索をやっていて、1つの検索はMax2時間くらいで、


>トータルで1昼夜かかっています。
いや、違くてトータルの時間でなくて、一回の検索に時間が掛かるならと言う意味で書きました。

(今更ですが)そもそも、エクスプローラで検索しなくてはいけない状況は不思議な気がします。
FileSystemObjectで遅ければ、Dir関数とかコマンドプロンプトのDirとかAPIのFindFirstFileとか使えばいいのではと。
    • good
    • 0
この回答へのお礼

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

お礼日時:2014/05/28 21:26
    • good
    • 0

Microsoft Internet Controlsにも参照設定を行って、UserFormモジュールに貼り付けて、


リンク先の回答通りに直せば期待した動作をします。
フィルタリングに時間が掛かる状況は想像出来ませんが、もしそうならMsgWaitForMultipleObjectsを使うのもありかもしれません。
(再利用性を考慮すると)クラスモジュールもありかもしれませんが、その辺は適宜直してください。
    • good
    • 0
この回答へのお礼

kumatti1さん
回答ありがとうございました。
UserFormモジュールに貼り付けでできました。感謝!
kumatti1さんには大変お世話になりました。

> フィルタリングに時間が掛かる状況は想像出来ませんが、

ネットワーク越しの検索をやっていて、1つの検索はMax2時間くらいで、
トータルで1昼夜かかっています。

殆どクローズできる状況ですが、あと1~2日だけ開けさせて置いてください。

お礼日時:2014/05/26 21:21
    • good
    • 0
この回答へのお礼

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

クラスモジュールを使ったことがなく、基本的なところの質問で申し訳ありませんが
よろしくお願いします。

お礼日時:2014/05/24 07:55

ShellFolderViewOC.EnumDoneイベントですが、タイミングがシビアみたいでこちらではまだ、上手く行ってません。


http://msdn.microsoft.com/en-us/library/windows/ …

# 参照設定は「Microsoft Shell Controls And Automation」
    • good
    • 0
この回答へのお礼

kumatti1 さん、アドバイスありがとうございます。

> ShellFolderViewOC.EnumDoneイベントですが、タイミングがシビアみたいでこち
らではまだ、上手く行ってません。

ExcelVBA側でエクスプローラのイベントをハンドルすること自体から難しそうです
ね。
ShellFolderViewOC.EnumDoneno のネット上の例題もあまりありませんでした。
クラスモジュールに書かないといけない・・・?
エクスプローラを起動しないといけない・・・?
Windows7でテストしたいと思いますので(もしかして問題なく動くかも)コードを
お教え戴けないでしょうか。
以上よろしくお願いします。

お礼日時:2014/05/22 21:16

Win.document.FilterView "hoge"


の一文で済む様です。

IShellFolderViewDual3::FilterView method
http://msdn.microsoft.com/en-us/library/windows/ …
    • good
    • 0
この回答へのお礼

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

お礼日時:2014/05/20 20:18

こちらはWin8.1ですが、ここは


>hWnd = FindWindowEx(hWnd, 0, "SearchBox", vbNullString) ' ★--> 0 return
DirectUIHWND
になってますね。
    • good
    • 0
この回答へのお礼

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

お礼日時:2014/05/20 20:23

こちらでも確認したところ、Application.SendKeysでなくて、SendKeysなら 漢字文字列 もセット出来ました。


https://gist.github.com/kumatti1/9b6eac43e294db9 …

>UUID(IAccessible?)の値
継承関係のあるインターフェースIDならOKです。
IAccessible以外には IDispatch とか IUnknown とか。

---
Visual Studio評価版は3ヶ月利用できるようなので、C++を入れればSpy++も入るのでそちらからも確認されるとか。
IAccessibleの他にUI Automationてのもありますよ。
    • good
    • 0

アドレスバーと同じ理屈でクリックさせてからでないと無理なのかも。


(調査用と言うわけでもないが)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 …
http://www.activebasic.com/forum/viewtopic.php?t …

この回答への補足

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なのかな?どなたか教えて戴ければ有難いです。
また、よろしくお願いします。

補足日時:2014/05/17 17:02
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qエクセル マクロで指定フォルダを開く

エクセルにて
指定フォルダを開く、マクロがあれば教えて頂けないでしょうか。
よろしくお願いいたします。

Aベストアンサー

こんにちは。

こういうものですか?
開くフォルダを変えたいときは targ に与えるパスを変更します。

Sub OpenFolders()
Dim targ As String
targ = "C:\"
Shell "C:\Windows\Explorer.exe " & targ, vbNormalFocus
End Sub

QvbaでIEの名前を付けて保存(A)をしたい

VBA で IEの通知バー を操作したいです。
SendKeys で 通知バーの 保存(S) はできたのですが、
保存(s)の右隣の ▼ をクリックするとでてくる、 名前を付けて保存(A) の方法がわかりません。

どのようなキーをおくればよいのでしょうか。


他の質問をみると、SendKeysではなく ○○がよいですよ みたいな内容しか見つからず、
回答をみつけることができなくて困っておりますのでよろしくお願いいたします。

Aベストアンサー

VBAでインターネット上のファイルをダウンロードする方法をまとめてみました。 | 初心者備忘録
http://www.ka-net.org/blog/?p=4855
とか。

QIE操作時、ファイルのダウンロードボタンの押下

IEをvb.netから操作しています。
webからファイルのダウンロードを自動で行いたいのですが、どのようにすればいいのかわからず悩んでいます。

画像の赤枠で括ってあるボタンの押下を、vb.netからの操作で行いたいのですが、どのようにすれば良いでしょうか。
InternetExplorer.Applicationに何らかのメンバ関数のようなものがあるのか、sendkeysを使うしかないのか、sendkeysを使うなら、具体的にどのキー操作を送れば良いのかなど、お教えいただけないでしょうか。

よろしくお願いします!

Aベストアンサー

Windows7 IE9ですが、↓で動きました

Private Delegate Function D_EnumChildWindowsProc(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As IntPtr

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

Private Const WM_ACTIVATE = &H6
Private Const BM_CLICK = &HF5
Private Const WM_GETTEXT = &HD
Private Const WM_QUIT = &H10

Private Const NAVDIR_NEXT = &H5
Private Const NAVDIR_FIRSTCHILD = &H7
Private Const CHILDID_SELF = &H0
Private Const OBJID_CLIENT = &HFFFFFFFC

Private Declare Function AccessibleObjectFromWindow Lib "oleacc" _
(ByVal hWnd As IntPtr, ByVal dwId As IntPtr, _
ByRef riid As Guid, <MarshalAs(UnmanagedType.IUnknown)> ByRef ppvObject As Object) As IntPtr
Declare Function AccessibleChildren Lib "oleacc" _
(ByVal paccContainer As IAccessible, ByVal iChildStart As IntPtr,
ByVal cChildren As IntPtr, <[Out]()> ByVal rgvarChildren() As Object, ByRef pcObtained As IntPtr) As IntPtr

Private IID_IAccessible As Guid = New Guid(&H20400, 0, 0, {&HC0, 0, 0, 0, 0, 0, 0, &H46})

Sub FileDownLoad_Proc()
Dim strCaption As String
Dim PWnd As IntPtr
Dim cWnd As IntPtr

' 親ウィンドウ取得
strCaption = "○○○○ - Windows Internet Explorer"
While PWnd = 0
PWnd = FindWindowEx(0, 0, "IEFrame", strCaption)
System.Threading.Thread.Sleep(50)
End While

' 通知バーのハンドル
While cWnd = 0
cWnd = FindWindowEx(PWnd, 0&, "Frame Notification Bar", vbNullString)
System.Threading.Thread.Sleep(50)
End While

' 通知バーボタン群のハンドル
Dim hChild As IntPtr = FindWindowEx(cWnd, 0&, "DirectUIHWND", vbNullString)
Dim objAcc As IAccessible = Nothing

AccessibleObjectFromWindow(hChild, OBJID_CLIENT, IID_IAccessible, objAcc)

If Not IsNothing(objAcc) Then
ClickPreserve(objAcc)
While cWnd = 0
cWnd = FindWindowEx(PWnd, 0&, "Frame Notification Bar", vbNullString)
System.Threading.Thread.Sleep(50)
End While
SendMessage(cWnd, WM_QUIT, 0, 0&)

End If

End Sub
Private Sub ClickPreserve(ByVal acc As IAccessible)

Dim i As Long
Dim count = acc.accChildCount
Dim lst(count - 1) As Object

If count > 0 Then
AccessibleChildren(acc, 0, count, lst, 0)
If Not IsNothing(lst) Then
For i = LBound(lst) To UBound(lst)
With lst(i)
'On Error Resume Next
'Debug.Print("ChildCount: " & .accChildCount)
'Debug.Print("Value: " & .accValue(CHILDID_SELF))
'Debug.Print("Name: " & .accName(CHILDID_SELF))
'Debug.Print("Description: " & .accDescription(CHILDID_SELF))
'On Error GoTo 0
'保存ボタンを見つけたらクリック(デフォルトアクション)する
If .accName(CHILDID_SELF) = "保存" Then

System.Threading.Thread.Sleep(500)
.accDoDefaultAction(CHILDID_SELF)
System.Threading.Thread.Sleep(500)
End If
End With
ClickPreserve(lst(i)) '再帰
Next
End If
End If
End Sub

Windows7 IE9ですが、↓で動きました

Private Delegate Function D_EnumChildWindowsProc(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As IntPtr

Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As IntPtr, ByVal hWnd2 As IntPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As IntPtr
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As IntPtr, ByVal wMsg As IntPtr, ByVal wParam As IntPtr, ByVal lP...続きを読む

QVBAで既に開いている別アプリケーションのオブジェクトを得る

 VBAで別のアプリケーションにアクセスするには、CreateObject関数を使ってアプリケーションのオブジェクトを作るようにすると思います。例えば、ワード文書にアクセスするなら次の構文になると思います。
  Set appWord = CreateObject("Word.Application")
  appWord.Visible = True
 しかしこれだと新しいワード文書を作ったり、既存のワードファイルを開いて扱うことしかできません。GetObject関数を用いても同様のようです。既に別ウィンドウで開いているワード文書があって、そこへアクセスするにはどうしたらよいのでしょうか。
 また、同じアプリで複数のファイルを開いている場合には、どうやって目的のファイルへのオブジェクトを得るのでしょうか。(ファイル名などを参照して判断?)

Aベストアンサー

Internet Explorerで開いているWindowを取得することはできますよ。

そのためには、まず開いているWindowを順番に取得し、それがInternet Explorerならばそれをオブジェクトに代入し、ひとつもIEウィンドウが存在しない場合は新規作成(CreateObject)すればいいのです。
Windowを取得するにはShell.Applicationというのを使います。

Dim ObjIE As Object
Dim ObjShell As Object
Dim ObjWindow As Object
Dim WinExist As Boolean

WinExist = False
Set ObjShell = CreateObject("Shell.Application")
For Each ObjWindow In ObjShell.Windows
If TypeName(ObjWindow.Document) = "HTMLDocument" Then
 WinExist = True
 Set ObjIE = ObjWindow
End If
Next
Set ObjShell = Nothing

If Not WinExist = True Then
Set ObjIE = CreateObject("InternetExplorer.Application")
End If

ObjIE.Navigate "http://nantokakantoka.html"
ObjIE.Visible = True


というような感じです。
Wordの場合はわからなくてすみません。
独学なのでもっといい方法があるかもしれないですが。

Internet Explorerで開いているWindowを取得することはできますよ。

そのためには、まず開いているWindowを順番に取得し、それがInternet Explorerならばそれをオブジェクトに代入し、ひとつもIEウィンドウが存在しない場合は新規作成(CreateObject)すればいいのです。
Windowを取得するにはShell.Applicationというのを使います。

Dim ObjIE As Object
Dim ObjShell As Object
Dim ObjWindow As Object
Dim WinExist As Boolean

WinExist = False
Set ObjShell = CreateObject("Shell.Applicatio...続きを読む

QEXCEL VBA で現在開いているブックのファイル名を取得する方法

EXCEL2003 VBAで業務を簡素化するために、現在開いているブックのファイル名を取得する方法が分かりません。
作業手順をマクロを使って処理していますが、オリジナルのワークブックをファイル名を変えて保存し、以後、このワークブックを読み込んで使用しています。
このときのVBAは、オリジナルのファイル名を使っているため、ファイル名を変更するとエラーになり、以後の業務に使用できません。
常にファイル名を取得出来るVBAをどなたか、教えて下さい。

Aベストアンサー

>現在開いているブックのファイル名
 ちょっと曖昧な表現かなぁという気もいたしますが、VBAが書いてあるブックのブック名は
ThisWorkbook.Name
で、現在 "アクティブにして" 操作対象になっているブックの名前は
ActiveWorkbook.Name
ですね。

 しかし、
>VBAは、オリジナルのファイル名を使っているため、ファイル名を変更するとエラーになり
というような文脈からすると、
ThisWorkbook.Name
の方ですかね。

QWEBページからのメッセージをVBAで

いつもお世話になっております。
エクセルVBAでIE制御についてです。
環境はWIN7、IE 9or11とエクセル2010です。

あるページのリンクをクリックすると、
WEBからのメッセージというダイアログボックスが出てきて、
続行しますか? はい いいえ を聞かれます。

その「はい」をVBAで押したいのですが、
sendkeysメソッドで押そうとしてもうまくいきません。

以下に記載したサイトのOKボタンを押すと出てくるものです。
http://kamicha1.web.fc2.com/Excel/Test20090726.html


以下が書いたコードです。


Declare Sub Sleep Lib "KERNEL32" (ByVal dwMilliseconds As Long)


Sub test()

Dim ie As Object

Set ie = CreateObject("InternetExplorer.Application")

ie.Visible = True
ie.navigate "http://kamicha1.web.fc2.com/Excel/Test20090726.html"
      
Do While ie.Busy Or ie.readyState < 4
DoEvents
Loop

ie.document.getElementsByClassName("bt2")(0).Click '-ここで止まる

Sleep 2000

SendKeys "{Enter}"

End Sub

ステップ実行していくと、ここで止まると書いた所で、
IE上にダイアログは表示されるのですが、
それ以上ステップ実行ができなくなってしまいます。

ダイアログを自分でOKかキャンセルで消すと続きが動くようになります。
その間はVBEはビジー状態となり操作できません。

そのためそれ以降のsendkeysメソッドに
たどり着けない状況かと思われます。

いろいろ調べたところIE8以降はダイアログボックスは
IEから出ているのではなくOS?から出ているとの事でした。

上記のサイトはHTML本体にjavaスクリプトが記載されており、
それをVBAから操作すればどうにかOKボタンが押せるらしいのですが、
自分が操作したいページにはそれらしき記載がありませんでした。

対象のアンカータグは
<a herl=URL 中略 data-comfirm=続行しますか? >
のような感じで記載がありました。

完全に煮詰まっております。
自動でOKをクリックするかEnterキーでOKを押すでも構いません。
どうかご教授お願いいたします。

いつもお世話になっております。
エクセルVBAでIE制御についてです。
環境はWIN7、IE 9or11とエクセル2010です。

あるページのリンクをクリックすると、
WEBからのメッセージというダイアログボックスが出てきて、
続行しますか? はい いいえ を聞かれます。

その「はい」をVBAで押したいのですが、
sendkeysメソッドで押そうとしてもうまくいきません。

以下に記載したサイトのOKボタンを押すと出てくるものです。
http://kamicha1.web.fc2.com/Excel/Test20090726.html


以下が書いたコードです。


Dec...続きを読む

Aベストアンサー

ご参考
https://gist.github.com/kumatti1/4028479

QEXPLORERで開いているフォルダがどこかを知りたいです VB.NET

Labelにフォルダのパスが入っていて、開くのボタンを押した時に
すでに開いていればそれを表示させたいのですが、
エクスプローラがどこのフォルダを開いているか調べる方法で苦戦しております。

実行中のプロセスをすべて取得して、ひとずつプロセス名を調べて
EXPLORERだったらメインウィンドウタイトルを取得しようと思った
のですが、EXPLORERはフォルダが複数あっても1つしか出ないので
この方法ではだめだと思いました。

そこで、FindWindowというAPIでLabelにある文字列を使って
ウィンドウを探して特定しようと思ったのですが、
これだとC:\だった場合、ウィンドウタイトルに不明なボリューム名が
入るので、まずドライブのボリューム名を調べないとならないのかと
思っているのですが、これ以外の方法で開いているフォルダを調べて
System.Diagnostics.Process型の変数に割り当てる方法がありましたら、
ご教授頂ければ幸いです。

Aベストアンサー

Shell32.dllとShDocVw.dllを参照設定して
  Dim sh As New Shell32.Shell
  Dim objWins As SHDocVw.IShellWindows = sh.Windows
  For Each oWeb As SHDocVw.InternetExplorer In objWinds
    Debug.Print(oWeb.LocationName & " " & oWeb.FullName)
  Next
といった具合で取得できますよ

Q起動済みのIEをハンドルから操作するには

既に起動済みのIEブラウザをWSH(VBS)などから、ハンドルを取得して
HTMLソース内のフォームに値をセット(Document forms elementなどで)
する事はできますでしょうか?
出来るとすれば、IEを捕まえて操作するには、どのようにすれば良い
でしょうか?

■補足
起動したIEは、自身のスクリプトからオブジェクトを生成したもの
では無く、ウインドウタイトルくらいしか解りません。

Aベストアンサー

とりあえず
Set ie = GetObject("", "InternetExplorer.Application")
Set ie = GetObject(, "InternetExplorer.Application")
のどちらかで取得できると思います。
Set ie = CreateObject("Shell.Application").Windows(0)
で取得する方法もあるらしいのですが、普通のフォルダもieとして認識してしまうため、純粋にieだけを取得する場合はチェックが必要だと思います。
取得したieでyahooで"おいしいラーメン"の検索結果の件数を表示します。
Sub sample()
Const READYSTATE_COMPLETE = 4
Dim ie As Object
Dim obj As Object
For Each obj In CreateObject("Shell.Application").Windows
If TypeName(obj.Document) = "HTMLDocument" Then
Set ie = obj
Exit For
End If
Next
If ie Is Nothing Then
MsgBox "ありません"
Exit Sub
End If
MsgBox "取得したieの情報" & vbCrLf & ie.LocationName & vbCrLf & ie.LocationURL & vbCrLf & TypeName(ie.Document)
ie.Navigate "www.yahoo.co.jp" 'yahooへ
Do While (ie.ReadyState <> READYSTATE_COMPLETE) Or ie.Busy: Loop '表示待ち
ie.Document.forms("sf1").elements("srchtxt").Value = "おいしいラーメン" '検索文字
ie.Document.forms("sf1").submit '検索
Do While (ie.ReadyState <> READYSTATE_COMPLETE) Or ie.Busy: Loop '表示待ち
If InStr(ie.Document.body.innertext, "に一致するウェブページは見つかりませんでした") > 0 Then
MsgBox "0件"
Else
MsgBox ie.Document.all("yschinfo").all(6).innertext & "件"
End If
Set ie = Nothing
End Sub

とりあえず
Set ie = GetObject("", "InternetExplorer.Application")
Set ie = GetObject(, "InternetExplorer.Application")
のどちらかで取得できると思います。
Set ie = CreateObject("Shell.Application").Windows(0)
で取得する方法もあるらしいのですが、普通のフォルダもieとして認識してしまうため、純粋にieだけを取得する場合はチェックが必要だと思います。
取得したieでyahooで"おいしいラーメン"の検索結果の件数を表示します。
Sub sample()
Const READYSTATE_COMPLETE = 4
Dim ie As Ob...続きを読む

QEnumChildWindowsの使い方(VBA)

64bit版ExcelのVBAでEnumChildWindowsを使用して、子ウィンドウのウィンドウハンドルを
取得したいと考えています。
下記のようなサンプルを作ってみましたが、コールバック関数でExcelが異常終了します。
(05行目にブレークポイントを設定、各変数の値を参照しようとした時点でExcelが異常終了)

また、コールバック関数の第3引数(lParam)の型をInteger,Long,LongPtr等変えてみましたが、
いずれもExcelの異常終了となりました。

つきまして、64bit Excelでの本APIの使い方を教えていただきたくよろしくお願いいたします。
(なお、32bit版のExcelでは正常に動作しました)

<以下サンプルコード>
行 コード
01   Declare PtrSafe Function EnumChildWindows Lib "user32.dll" (ByVal ParenthWnd as LongPtr, ByVal EnumWindosPROC as LongPtr,ByVal lParam as Long) as Integer
02
03
04 Function ListupChildWindows(hWnd as LongPtr,lParam as Long) as Boolean
05 MsgBox hWnd
06 ListupChildWIndows =True
07 End Function
08
09 Sub test_CwinList
10 Dim ThishWnd as LongPtr
11
12 ThishWnd=Excel.Application.hWnd
13 Call EnumChildWindows (ThishWnd , AddressOf ListupChildWindows ,0)
14 End Sub

64bit版ExcelのVBAでEnumChildWindowsを使用して、子ウィンドウのウィンドウハンドルを
取得したいと考えています。
下記のようなサンプルを作ってみましたが、コールバック関数でExcelが異常終了します。
(05行目にブレークポイントを設定、各変数の値を参照しようとした時点でExcelが異常終了)

また、コールバック関数の第3引数(lParam)の型をInteger,Long,LongPtr等変えてみましたが、
いずれもExcelの異常終了となりました。

つきまして、64bit Excelでの本APIの使い方を教えていただきたくよろしくお...続きを読む

Aベストアンサー

こんにちは。

ご提示のサンプルですが、当方のVBA7x64環境でも
(実行の度に無条件で必ず)Excelの異常終了を再現できました。

この問題の解決については、私の力量を越えていますので、
情報提供、という形でお応えします。

『APPS PRO > VBA Tips > How Can I Locate a Specific Child Window Handle?』
http://www.appspro.com/Tips/VBA%20Tips.htm
こちらのページの一番下の[EnumChildWindows]をクリックすると
x32|x64両方対応のサンプルコードが入手できます。
そのままこちらで試してみた処、
(このサンプルは、ThisWorkbook.Windows(1)のハンドル'だけ'を取得するものなので)
エラーにはなりませんでした。
コールバック関数側で、条件分岐を書き換えてみたり、
無条件でWindowClassやWindowTitleを取得するよう試みたりして、
約30(重複を含む)の子ウィンドウのウィンドウハンドルが取得出来る所までは確認しましたが、
すべてを取得出来ていないか、うまく終了させることが出来ていないか、どちらかで、
完全な動作を確認するには至りませんでした。
デバッグのヒントにはなりそうな気はしますので、サンプル試してみては如何でしょう。

もしうまく行く方法があるとすれば、
WindowClassとWindowTitleでの条件分岐を整理して、
適切に列挙を終了させることになるような気がしています。
例えばThisWorkbook.Windows(1)のWindowClassとWindowTitleが確認できたら、
(そこから数えてx番目の子ウィンドウで、、、x = 0 かも?)
コールバック関数の戻りを0にして列挙を終了する、、、、みたいな?
或いは、特定の子ウィンドウに限定できるなら、同様にうまく扱えるようにも思えます。

実践的には、同じハンドルが重複して戻る場合があることを考慮して、
ハンドル列挙の受け皿としてCollectionオブジェクト等を用いることになるかと思いますが、
もしかしたら、この戻り値の重複についてもチェックしてみた方がいいのかも??知れません。

参考になるか解りませんが、以上です。

こんにちは。

ご提示のサンプルですが、当方のVBA7x64環境でも
(実行の度に無条件で必ず)Excelの異常終了を再現できました。

この問題の解決については、私の力量を越えていますので、
情報提供、という形でお応えします。

『APPS PRO > VBA Tips > How Can I Locate a Specific Child Window Handle?』
http://www.appspro.com/Tips/VBA%20Tips.htm
こちらのページの一番下の[EnumChildWindows]をクリックすると
x32|x64両方対応のサンプルコードが入手できます。
そのままこちらで試してみた処、
(このサ...続きを読む

QIEのダウンロード通知バーのVBA制御(保存他)

以前投稿された表題の質問をマネしてVBAから通知バーの制御を試みたらエラーになりました。
原因がわからず困っています。どこに問題があるか教えて頂けないでしょうか?
http://okwave.jp/qa/q8121989.html
■実行エラー91
「オブジェクト変数またはWithブロック変数が設定されていません」
■エラー停止箇所
Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
■補足
・参照設定はしています。
・下記2点に示すようにお尻の数字を削除しています。(他のエラーがでてしまうため)
  Dim o As IUIAutomation2→IUIAutomation
  Set o = New CUIAutomation8→CUIAutomation

---【http://okwave.jp/qa/q8121989.html】------------------------------------------------------
Option Explicit
'参照設定 UIAutomationClient
'C:\Windows\System32\UIAutomationCore.dll
Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr

Sub hoge2()

Const url As String = ""
Dim ie As Object
Set ie = CreateObject("Shell.Application").Windows.findwindowSW(url, Empty, 1, 0, 1)
If ie Is Nothing Then Exit Sub

Dim o As IUIAutomation2
Dim e As IUIAutomationElement
Set o = New CUIAutomation8
Dim h As LongPtr

h = ie.Hwnd
h = FindWindowEx(h, 0, "Frame Notification Bar", vbNullString)
If h = 0 Then Exit Sub
Set e = o.ElementFromHandle(ByVal h)

Dim iCnd As IUIAutomationCondition
Set iCnd = o.CreatePropertyCondition(UIA_NamePropertyId, "保存")

Dim Button As IUIAutomationElement
Set Button = e.FindFirst(TreeScope_Subtree, iCnd)

Dim InvokePattern As IUIAutomationInvokePattern
Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
InvokePattern.Invoke

DoEvents
Set iCnd = o.CreatePropertyCondition(UIA_NamePropertyId, "通知バーのテキスト")
Dim iElemFound As IUIAutomationElement
Set iElemFound = e.FindFirst(TreeScope_Subtree, iCnd)
Dim iValuePattern As IUIAutomationValuePattern
Set iValuePattern = iElemFound.GetCurrentPattern(UIA_ValuePatternId)

Do
DoEvents
If iValuePattern.CurrentValue Like "*のダウンロードが完了しました。*" Then
Set iCnd = o.CreatePropertyCondition(UIA_NamePropertyId, "閉じる")
Set iElemFound = e.FindFirst(TreeScope_Subtree, iCnd)
Set InvokePattern = iElemFound.GetCurrentPattern(UIA_InvokePatternId)
InvokePattern.Invoke
Exit Do
End If
Loop

End Sub

以前投稿された表題の質問をマネしてVBAから通知バーの制御を試みたらエラーになりました。
原因がわからず困っています。どこに問題があるか教えて頂けないでしょうか?
http://okwave.jp/qa/q8121989.html
■実行エラー91
「オブジェクト変数またはWithブロック変数が設定されていません」
■エラー停止箇所
Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
■補足
・参照設定はしています。
・下記2点に示すようにお尻の数字を削除しています。(他のエラーがでてしまうため)
...続きを読む

Aベストアンサー

そのコードは通知バーが完全に表示されている状態での実行を期待しています。
なので、ループで参照がセット出来るまで、待ち合わせてみるとか。

Dim Button As IUIAutomationElement
Dim InvokePattern As IUIAutomationInvokePattern

While Not InvokePattern Is Nothing
DoEvents
Set Button = e.FindFirst(TreeScope_Subtree, iCnd)
Set InvokePattern = Button.GetCurrentPattern(UIA_InvokePatternId)
Wend
InvokePattern.Invoke


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング

おすすめ情報