柔軟に働き方を選ぶ時代に必要なこと >>

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

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

A 回答 (1件)

こんにちは。



ご提示のサンプルですが、当方の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オブジェクト等を用いることになるかと思いますが、
もしかしたら、この戻り値の重複についてもチェックしてみた方がいいのかも??知れません。

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

この回答への補足

教えていただいた参照先のサンプルコードを確認し、
本質問の異常終了の原因がわかりました。
(原因)
4行目のコールバック関数引数の宣言が間違っていました(「ByVal」が抜けていました)。
下記のように修正することでうまく動作することが確認できました。大変お世話になりありがとうございました。
04 Function ListupChildWindows(ByVal hWnd as LongPtr, ByVal lParam as Long) as Boolean

補足日時:2014/09/08 21:15
    • good
    • 0
この回答へのお礼

早速、大変ご丁寧な回答をいただき、
ありがとうございます。
示していただいた参照先についてはまだ確認できていませんが、回答いただいた内容と合わせ、試してみたいと思います。

取り急ぎお礼まで。

お礼日時:2014/09/08 19:57

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

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

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

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

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

QExcelVBAでAPIを使って外部ウインドウのエディットテキストを取得する方法

●やりたいこと
ExcelVBAで、APIを実行し、外部ソフトのウィンドウに含まれている
エディットテキストを取得して、セルに出力したい

使用する関数・宣言、できればコードを教えていただけませんでしょうか。

イメージはこちらをご参考いただけると幸いです。
​http://situmon-img.blogspot.com/2008/08/1.html​

変数hwindowに親ウィンドウのハンドルが取得されています。
エディットボックスのハンドル、IDは分かりません。


エディットボックスのハンドルを取得し、
分かっているクラス・ハンドルの文字列を取得
といった流れになるのではと思っております。

変数にさえ文字列が取得できれば、
当然ですが、Range("B2")=変数 で大丈夫です。
変数は、ひとつを使いまわしで構いません。
変数をエディットテキストの数だけ用意しても構いません。

Aベストアンサー

あの QNo.4256138の質問でも、同じ様な事を質問されていたと思います。
出来たらそちらで質問された方がよかったのではと思います。

テキストボックスの取得も、私の回答した全く同じ方法で
取得出来ると思います。クラス名が Edit になるだけです。

 EnumChildWindows(hWnd,lpEnumFunc,0&) は、親ウィンドウに含まれる

子ウィンドウがすべて返ってきます。ボタンもテキストボックスも、その他の
子ウィンドウがすべて、何個あっても、取得できます。

ただ EnumChildWindows(hWnd,lpEnumFunc,0&) で与える子ウィンドウを
受け取る関数は、コールバック関数なので、1回のコールで1個の子ウィンドウ
しか返ってきません。ただ、子ウィンドウがある分だけ何度も同じ関数が
呼び出されます。よび出される度に

 GetClassName(hWnd,lpClassName,nMaxCount) でクラス名を取得し

クラス名が Edit ならテキストボックスになります。

SendMessage(テキストボックスハンドル, &HD, 240, ByVal cbuf)

で cbuf にテキストボックスの文字が取得出来ます。

尚、cbuf は文字長を多い目に事前に確保しておきましょう。

cbufのNULL値までが実際の文字となります。

また、コールバック関数はデバッグモードで、ブレークさすと、
フリーズするので注意して下さい。通常はデバッグしにくいので、
コールバック関数内では、配列変数にハンドルをためこんでいきます。
その後で、配列にためこんでいるハンドルを順番にクラス名を取得し
テキストがボタンか判断していきます。

あの QNo.4256138の質問でも、同じ様な事を質問されていたと思います。
出来たらそちらで質問された方がよかったのではと思います。

テキストボックスの取得も、私の回答した全く同じ方法で
取得出来ると思います。クラス名が Edit になるだけです。

 EnumChildWindows(hWnd,lpEnumFunc,0&) は、親ウィンドウに含まれる

子ウィンドウがすべて返ってきます。ボタンもテキストボックスも、その他の
子ウィンドウがすべて、何個あっても、取得できます。

ただ EnumChildWindows(hWnd,lpEnumFunc,0...続きを読む

Q親ウインドウにあるOKボタンを押す方法

非常に基本的なことを質問して申し訳ございません。

●やりたいこと●
ある親ウィンドウに「テキスト」と「OKボタン」があります。
OKボタンはひとつだけです。
このOKボタンを押して、親ウィンドウを閉じるだけです。
OKボタンを押せば、親ウィンドウは勝手に閉じます。


親ウィンドウのハンドルは取得できたのですが、
子ウィンドウ(ボタン"OK")のハンドルが取得できず、
その後の処理もできておりません。

ボタンはひとつだけなので、ボタンのハンドルを検索したりしなくても、
押すことはできるような気がするのですが・・・
初心者の浅知恵で申し訳ございません。

やはり、ボタンのハンドルを取得して、押すコマンドを実行しないといけないのでしょうか?

ボタンのハンドルを取得して、押すコマンドを実行する場合、
その方法を教えていただけると幸いです。

親ウィンドウのハンドルは変数「hWindow」に入っているとして、
コードをお願いいたします。

親ウィンドウのハンドル取得に使ったFindWindow以外に宣言が必要であればご教授お願いいたします。

非常に基本的なことを質問して申し訳ございません。

●やりたいこと●
ある親ウィンドウに「テキスト」と「OKボタン」があります。
OKボタンはひとつだけです。
このOKボタンを押して、親ウィンドウを閉じるだけです。
OKボタンを押せば、親ウィンドウは勝手に閉じます。


親ウィンドウのハンドルは取得できたのですが、
子ウィンドウ(ボタン"OK")のハンドルが取得できず、
その後の処理もできておりません。

ボタンはひとつだけなので、ボタンのハンドルを検索したりしなくても、
押すことはでき...続きを読む

Aベストアンサー

子ウィンドウを探すには、下の2つのAPIの使います。

  EnumChildWindows(hWnd,lpEnumFunc,0&)
  GetClassName(hWnd,lpClassName,nMaxCount)

EnumChildWindows が、親ウィンドウのハンドルと、子ウィンドウを受け取る関数を
与えます。ただし、子ウィンドウを受け取る関数はフォームモジュールではなく、
標準モジュールにないと駄目です。

すると与えた子ウィンドウを受け取る関数に、親ウィンドウに含まれる全ての子ウィンドウの
ハンドルが返ってきます。

返ってきたハンドルを元に GetClassName で、クラス名を取得し、ボタンのウィンドウを
特定します。今回の場合は、ボタンが1個しかないとのことなので、取得したクラス名が
Buttonであればそのハンドルがボタンのハンドルになります。
参考までに、複数個のボタンがあれば、この場合、どのボタンがOKボタンなのかを特定しない
といけません。「スパイ」とか言うソフトがあれば簡単に特定できるのですが、ない場合は、
子ウィンドウに含まれる、上記の手順で得た全てのボタンのハンドルに対して、プログラムで
BM_CLICKのメッセージを送り一つづつ確認していくしかありません。ただこの場合でも、
特性があって、親ウィンドウに複数個のボタンがあっても、子ウィンドウを受け取る関数には
必ず一定の順番にしか、ハンドルが返ってきないので、最初に一度だけ何番目のボタンかを特定
すればよいです。対象のアプリケーションを再度起動してもこの順番は変わりません。

あと、ボタンのクリックは、SendMessageで、BM_CLICK を送ればOKです。

今回は、簡単な他アプリの制御なので、そんなに問題がないですが、複雑な制御だと、
更に、ウエイトの方法だとか、制御するアプリが確実に動作しているか、確認する操作を
1ステップずつ挿入していかないと駄目です。そうすれば、全ての他のアプリケーションを
自由に操る事ができます。

本格的に作るとなると大変なので、フリーのソフトで沢山でていると思います。一度さがされたら
よいと思います。DLLタイプになっているのがよいとは思います。
以前私も使ったことがありますが、憶えていません。あしからず。現在は自作しております。
自作のがよりきめ細かく制御出来るからです。

子ウィンドウを探すには、下の2つのAPIの使います。

  EnumChildWindows(hWnd,lpEnumFunc,0&)
  GetClassName(hWnd,lpClassName,nMaxCount)

EnumChildWindows が、親ウィンドウのハンドルと、子ウィンドウを受け取る関数を
与えます。ただし、子ウィンドウを受け取る関数はフォームモジュールではなく、
標準モジュールにないと駄目です。

すると与えた子ウィンドウを受け取る関数に、親ウィンドウに含まれる全ての子ウィンドウの
ハンドルが返ってきます。

返ってきたハンドルを元に G...続きを読む

QAlt+P,Alt+NをPostmessageで送るには

あるアプリがあり、そのハンドルを取得してからメッセージを送るプログラムを作っています。
PageUp,PageDownをそれぞれAlt+P,Alt+Nに変換して送るものです。
関数・定数宣言部は省略しています。

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
  Dim hTest As Long
  hTest = FindWindow(vbNullString, "Test")
  If KeyCode = 33 Then 'PageUp
    PostMessage MPL, WM_SYSKEYDOWN, VK_ALT, 0
    PostMessage MPL, WM_KEYDOWN, VK_N, 0
    PostMessage MPL, WM_KEYUP, VK_N, 0
    PostMessage MPL, WM_SYSKEYUP, VK_ALT, 0
  ElseIf KeyCode = 34 Then 'PageDown
    PostMessage MPL, WM_SYSKEYDOWN, VK_ALT, 0
    PostMessage MPL, WM_KEYDOWN, VK_P, 0
    PostMessage MPL, WM_KEYUP, VK_P, 0
    PostMessage MPL, WM_SYSKEYUP, VK_ALT, 0
  End If
End Sub

送り先(Test.exe)では、
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
  Dim L As String
  L = ""
  If Shift = 4 Then L = "Alt + "
  Label1.Caption = L & KeyCode
End Sub

ラベルで「Alt+P」などが来ているかどうか見ています。こちらのウィンドウで「Alt+P」を押すとちゃんと表示されます。

しかし、この2つを組み合わせるとPのみやNのみしか送られてきません。どこかおかしいのでしょうか。

Alt+PなどをPostMessageで送る方法でよい方法があれば、お教え下さい。
よろしくお願いします。

あるアプリがあり、そのハンドルを取得してからメッセージを送るプログラムを作っています。
PageUp,PageDownをそれぞれAlt+P,Alt+Nに変換して送るものです。
関数・定数宣言部は省略しています。

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
  Dim hTest As Long
  hTest = FindWindow(vbNullString, "Test")
  If KeyCode = 33 Then 'PageUp
    PostMessage MPL, WM_SYSKEYDOWN, VK_ALT, 0
    PostMessage MPL, WM_KEYDOWN, VK_N, 0
    PostMessage MPL,...続きを読む

Aベストアンサー

ALTキーとの組み合わせでしたら、WM_SYSCHARのほうがいいのでは?
たぶん、送り先もVB製でしたら内部でTranslateMessageような感じですし。


あと、
>PostMessage MPL, WM_SYSKEYDOWN, VK_ALT, 0

MPLってなんですか?
>hTest = FindWindow(vbNullString, "Test")
で取得したウィンドウにPostMessageするんじゃないんですか?


次に、
>Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

KeyDownイベントに処理が書かれてますが、このイベント自体は呼ばれてますか?キー操作を受け付けるコントロールが張り付いてるのにKeyPreviewプロパティがFalseなんてことは無いですか?

#ちなみに、普通はVK_ALTではなくVK_MENUですので。

Q他アプリの操作(メニューバー)

市販されているアプリケーションを自分で作成しているソフトで操作したいのですが、どの様に制御したらいいのか判りません。プログラムはVB6.0で作成しております。
したい事は他のアプリケーションでメニューバーの中の項目の
印刷項目を選択したいのですが、メニューバーのハンドルを取得
出来ず困っております。
そもそもメニューバーのハンドルって取得できるのでしょうか?

Aベストアンサー

ウィンドウハンドルの取得については割愛します。

Option Explicit

Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As MENUITEMINFO) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Const WM_COMMAND = &H111

Private Type MENUITEMINFO
cbSize As Long
fMask As Long
fType As Long
fState As Long
wID As Long
hSubMenu As Long
hbmpChecked As Long
hbmpUnchecked As Long
dwItemData As Long
dwTypeData As String
cch As Long
End Type

' hWndに指定したウィンドウのメニュークリックをエミュレート
' Menusには、メニューを辿る順序を文字列配列で定義
' ファイル -> 印刷 であれば Menus() = {"ファイル", "印刷"}
Private Sub EmulateMenuClick(ByVal hWnd As Long, Menus() As String)
Dim hMenu As Long, lngID As Long, intMenuIndex As Integer
hMenu = GetMenu(hWnd)

' メニュー階層をたどる
For intMenuIndex = 0 To UBound(Menus)

If ContainMenu(hMenu, Menus(intMenuIndex), lngID) = False Then
Call MsgBox("一致するメニューはありません。")
Exit Sub
End If

Next

' 最終的に見つかったメニューのIDをWM_COMMANDでPostMessage
Call PostMessage(hWnd, WM_COMMAND, lngID, 0&)
End Sub

' hMenuのメニューハンドル内でTextの文字列と一致するメニューがあるかどうかを返す
' 見つかればTrue。このとき、hMenuにはサブメニューのハンドル、IDにはメニューのIDが返される
' 見つからなければFalse
Private Function ContainMenu(hMenu As Long, ByVal Text As String, ID As Long) As Boolean
Dim lngCount As Long, lngPos As Long
Dim typMenuItem As MENUITEMINFO
lngCount = GetMenuItemCount(hMenu)

' メニューの個数でループ
For lngPos = 0 To lngCount - 1
typMenuItem.fMask = &H3F&

typMenuItem.dwTypeData = vbNullChar
typMenuItem.cch = 0
typMenuItem.cbSize = Len(typMenuItem)
Call GetMenuItemInfo(hMenu, lngPos, 1, typMenuItem)

typMenuItem.dwTypeData = String(typMenuItem.cch, " ")
typMenuItem.cch = typMenuItem.cch + 1
typMenuItem.cbSize = Len(typMenuItem)
Call GetMenuItemInfo(hMenu, lngPos, 1, typMenuItem)

Debug.Print typMenuItem.dwTypeData

' メニューの文字列を比較(比較方法はどちらでも)
'If typMenuItem.dwTypeData = Text Then
If typMenuItem.dwTypeData Like Text Then

' 一致したらIDとサブメニューハンドルを返す
ID = typMenuItem.wID
hMenu = typMenuItem.hSubMenu
ContainMenu = True
Exit Function
End If
Next

ContainMenu = False
End Function

EmulateMenuClickにウィンドウハンドルと実行したいメニューを辿る文字列配列を渡してください。
画像は、このコードを利用してAPIビューアのバージョン情報をForm1から実行して表示させたものです。

ウィンドウハンドルの取得については割愛します。

Option Explicit

Private Declare Function GetMenu Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetMenuItemCount Lib "user32" (ByVal hMenu As Long) As Long
Private Declare Function GetMenuItemInfo Lib "user32" Alias "GetMenuItemInfoA" (ByVal hMenu As Long, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As MENUITEMINFO) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA...続きを読む

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...続きを読む

QWinAPIで電卓をクリック

現在、WinAPIを勉強しており、練習としてVBAを用いて、電卓アプリのボタンをクリックしようとしています。

キーを送るのではなく、クリックで行いたいたいと
考えています。

ボタンのハンドルを取得するところまではできましたが、sendMessageでクリックできず、EditBoxに数字が
入りません。

どのようにすればよいのかご教授ください。
よろしくお願い致します。

環境:
WinXP home、 Excel2002、Win付属アプリの電卓v5.1

---作成したプログラム----
'標準モジュールの中身
Option Explicit

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) 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 Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hWnd As Long) As Long

Private Const WM_LBUTTONDOWN = &H201
Private Const WM_LBUTTONUP = &H202

Sub Main()
Dim lngWindWnd As Long 'ウィンドウハンドル
Dim ret As Long
Dim hCalc As Long

'アプリケーションタイトルより、ウィンドウハンドルを得ます
lngWindWnd = FindWindow(vbNullString, "電卓")

'8ボタンのハンドル(確実に取れていることを確認
hCalc = FindWindowEx(lngWindWnd, 0, "Button", "8")

ret = SetForegroundWindow(lngWindWnd)
ret = SendMessage(hCalc, WM_LBUTTONDOWN, 0, 0)
End Sub

現在、WinAPIを勉強しており、練習としてVBAを用いて、電卓アプリのボタンをクリックしようとしています。

キーを送るのではなく、クリックで行いたいたいと
考えています。

ボタンのハンドルを取得するところまではできましたが、sendMessageでクリックできず、EditBoxに数字が
入りません。

どのようにすればよいのかご教授ください。
よろしくお願い致します。

環境:
WinXP home、 Excel2002、Win付属アプリの電卓v5.1

---作成したプログラム----
'標準モジュールの中身
Option Explicit...続きを読む

Aベストアンサー

>ret = SendMessage(hCalc, WM_LBUTTONDOWN, 0, 0)
>ret = SendMessage(hCalc, WM_LBUTTONUP, 0, 0)
>
>の順に送ってみましたが,電卓ウィンドウが前面に出>てくるだけで,EditBoxに変化が起きませんでした。

まず、PostMessageにしましょう。
しなくても動くかもしれませんが、するべきです。

で、第3引数には、左ボタンをあらわすMK_LBUTTON、
第4引数は、ByVal 0とする必要があります。
#Declareステートメントで、As Anyと宣言しているため。
Win32api.txtのPostMessageの宣言をそのまま使うんだったら、ByVal lParam As Longなので、そのまま0でかまいません。



Const MK_LBUTTON = &H1


ret = PostMessage(hCalc, WM_LBUTTONDOWN, MK_LBUTTON, ByVal 0)
ret = PostMessage(hCalc, WM_LBUTTONUP, MK_LBUTTON, ByVal 0)

>ret = SendMessage(hCalc, WM_LBUTTONDOWN, 0, 0)
>ret = SendMessage(hCalc, WM_LBUTTONUP, 0, 0)
>
>の順に送ってみましたが,電卓ウィンドウが前面に出>てくるだけで,EditBoxに変化が起きませんでした。

まず、PostMessageにしましょう。
しなくても動くかもしれませんが、するべきです。

で、第3引数には、左ボタンをあらわすMK_LBUTTON、
第4引数は、ByVal 0とする必要があります。
#Declareステートメントで、As Anyと宣言しているため。
Win32api.txtのPostMessageの宣言をそのまま使うん...続きを読む

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

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

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


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

Aベストアンサー

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

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...続きを読む

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でIEの操作→サブウインドウを操作するには

以下の「oya.html」「ko.html」があります。
それを、VBAで「oya.html」を開き、「子ウインドウを開く」リンクをクリックさせて、開いた「ko.html」の「子ウィンドウを閉じる」リンクをクリックさせたいのだがどうすればよろしいでしょうか?
---------VBA ↓---------------------------------------------
Private Sub CommandButton1_Click()
Dim objIE As Object 'Object型
'IEのオブジェクトを作る
Set objIE = CreateObject("InternetExplorer.application")
objIE.Visible = True
objIE.Navigate "file:///C:/oya.html"'「oya.html」を開く
'----表示待ち↓--------
Do While objIE.Busy
 DoEvents
Loop
Do While objIE.document.ReadyState <> "complete"
DoEvents
Loop
'----表示待ち↑----------
For Each linkitem In objIE.document.all.tags("A") 'Aタグ
If linkitem.innerText = "子ウインドウを開く" Then
linkitem.Click
End If
Next
'----表示待ち↓--------
Do While objIE.Busy
DoEvents
Loop
Do While objIE.document.ReadyState <> "complete"
DoEvents
Loop
'----表示待ち↑----------
  For Each linkitem In objIE.document.all.tags("A") 'Aタグ
If linkitem.innerText = "子ウィンドウを閉じる" Then
linkitem.Click
End If
Next
End Sub
---------------↑-------------------------------------------
--------oya.html ↓-----------------------------------------
<html>
<head><script>
function showModal(){
var value = showModalDialog('ko.html');
}
</script></head>
<TITLE>親ウィンドウ</TITLE>
<body>
<a href="javascript://" onclick="showModal()">子ウインドウを開く</a><br>
</body>
</html>
-----------------↑-----------------------------------------
--------ko.html ↓--------------------------------------------
<html>
<TITLE>子ウィンドウ</TITLE>
<body>
<a href="#" onClick="window.close(); return false;">子ウィンドウを閉じる</a><br>
</body>
</html>
------------------↑-----------------------------------------

以下の「oya.html」「ko.html」があります。
それを、VBAで「oya.html」を開き、「子ウインドウを開く」リンクをクリックさせて、開いた「ko.html」の「子ウィンドウを閉じる」リンクをクリックさせたいのだがどうすればよろしいでしょうか?
---------VBA ↓---------------------------------------------
Private Sub CommandButton1_Click()
Dim objIE As Object 'Object型
'IEのオブジェクトを作る
Set objIE = CreateObject("InternetExplorer.application")
objIE.Visible = Tru...続きを読む

Aベストアンサー

状況を理解しました。
子ウィンドウを、showModalDialog で開いている為に、子ウィンドウを閉じるまで Excel に制御が返ってこないワケですね。
VBA で制御できるレベルではなさそうです。一応参考 URL を添付しておきますが。。。

http://www.usefullcode.net/2006/12/ieihtmldocument2.html
http://rararahp.cool.ne.jp/cgi-bin/lng/vc/vclng.cgi?print+200509/05090016.txt


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

人気Q&Aランキング

おすすめ情報