初めてご質問させていただきます。
分からないことが出てきたのでお教えください。
現在下記のページを見てObjectFromLresultの使い方の勉強をしています。
http://msdn.microsoft.com/en-us/library/dd373605(VS.85).aspx
実験的にExcelのVBAから自分自身(ワークブック)のウインドウハンドルを取得して、自分自身のウインドウオブジェクトを取得するというサンプルをつくりましたが、ObjectFromLresultの使い方が間違っているようでうまくいきません。だめな部分をご指摘していただけないでしょうか?
Public Const WM_GETOBJECT = &H3D&
Public Const OBJID_NATIVEOM = &HFFFFFFF0
Public Declare Function ObjectFromLresult Lib "oleacc" _
(ByVal lResult As Long, riid As Any, _
ByVal wParam As Long, ppvObject As Any) As Long
Public Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, lParam As Any) As Long
Public Declare Function FindWindowEx Lib "user32" _
Alias "FindWindowExA" _
(ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Long
Public Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Option Explicit
Sub test()
Dim wkw As Excel.Window
Dim IID_IAccessible As GUID
Dim hwndApp As Long
Dim hwndClient As Long
Dim hwndBook As Long
Dim lngResult As Long
Dim lngRtnCode As Long
Dim strMsg As String
With IID_IAccessible
.Data1 = &H618736E0
.Data2 = &H3C3D
.Data3 = &H11CF
.Data4(0) = &H81
.Data4(1) = &HC
.Data4(2) = &H0
.Data4(3) = &HAA
.Data4(4) = &H0
.Data4(5) = &H38
.Data4(6) = &H9B
.Data4(7) = &H71
End With
hwndApp = FindWindowEx(0, hwndApp, "XLMAIN", vbNullString)
hwndClient = FindWindowEx(hwndApp, 0, "XLDESK", vbNullString)
hwndBook = FindWindowEx(hwndClient, 0, "EXCEL7", vbNullString)
lngResult = SendMessage(hwndBook, WM_GETOBJECT, 0, ByVal OBJID_NATIVEOM)
If lngResult Then
lngRtnCode = ObjectFromLresult(lngResult, IID_IAccessible, 0, wkw)
Else
strMsg = "SendMessage Error "
exit sub
End If
If Not wkw Is Nothing Then
strMsg = "確認できたよ " & wkw.Caption & vbTab 'OK
Else
strMsg = strMsg & "駄目でした"
End If
MsgBox strMsg
End Sub
# 回答ではありません。
WM_GETOBJECT って、システムが送るメッセージであって、アプリ側が
直接使うものとは想定されていないメッセージだったような。
Accessible なオブジェクトを取得するのならば、AccessibleObjectFromPoint、
AccessibleObjectFromEvent、AccessibleObjectFromWindow
がなどがあります。特に今回は最後のを使うべきではないかと。
> Option Explicit
が妙な位置にあるのはご愛嬌として。
> ObjectFromLresult
は何の戻り値を返しますか?
変数に受けてそれを評価しないのでは意味がありませんね。
で、今回はE_NOINTERFACE(0x80004002)を返しています。
継承関係の無いiidを渡しているのが間違いということに気付くでしょう。
IID_IDispatch等を指定してください。
# 他所で以前、同様の質問をしたはずなのに。
K.J.K.様ごかいとうありがとうございます。
accessibleobjectfromwindowについては、
http://msdn.microsoft.com/en-us/library/dd317978(VS.85).aspx
を読んで以下のようにすればうまくオブジェクトがとれました。
Option Explicit
Public Const OBJID_NATIVEOM = &HFFFFFFF0
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" _
(ByVal hWnd As Long, ByVal dwId As Long, _
riid As Any, ppvObject As Any) As Long
Public Declare Function FindWindowEx Lib "user32" _
Alias "FindWindowExA" _
(ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Long
Public Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Sub test2()
Dim wkw As Excel.Window
Dim IID_Idispatch As GUID
Dim hwndApp As Long
Dim hwndClient As Long
Dim hwndBook As Long
Dim lngResult As Long
Dim lngRtnCode As Long
Dim strMsg As String
With IID_Idispatch
.Data1 = &H20400
.Data4(0) = &HC0
.Data4(7) = &H46
End With
hwndApp = FindWindowEx(0, hwndApp, "XLMAIN", vbNullString)
hwndClient = FindWindowEx(hwndApp, 0, "XLDESK", vbNullString)
hwndBook = FindWindowEx(hwndClient, 0, "EXCEL7", vbNullString)
AccessibleObjectFromWindow hwndBook, OBJID_NATIVEOM, _
IID_Idispatch, wkw
If Not wkw Is Nothing Then
strMsg = "確認できたよ " & wkw.Caption & vbTab 'OK
Else
strMsg = strMsg & "駄目でした"
End If
MsgBox strMsg
End Sub
ただリンク先を読む限りIID_Iaccessibleを引き渡してもうまくいくと思いましたがうまくいきませんでした。私の誤訳でしょうか?
熊谷隆史様いつもありがとうございます。
># 他所で以前、同様の質問をしたはずなのに。
以前ご提示頂いたサンプルは以下のような感じだったと思いますが、
Public Const WM_GETOBJECT = &H3D&
Public Const OBJID_NATIVEOM = &HFFFFFFF0
Public Declare Function ObjectFromLresult Lib "oleacc" _
(ByVal lResult As Long, riid As Any, _
ByVal wParam As Long, ppvObject As Any) As Long
Public Declare Function SendMessage Lib "user32" _
Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, lParam As Any) As Long
Public Declare Function IIDFromString Lib "ole32" _
(lpsz As Any, lpiid As Any) As Long
Public Declare Function FindWindowEx Lib "user32" _
Alias "FindWindowExA" _
(ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Long
Public Const IID_IDispatch = "{00020400-0000-0000-C000-000000000046}"
Option Explicit
Sub test3()
Dim wkw As Excel.Window
Dim hwndApp As Long
Dim hwndClient As Long
Dim hwndBook As Long
Dim lngResult As Long
Dim lngRtnCode As Long
Dim strMsg As String
Dim bytID() As Byte
Dim IID(0 To 3) As Byte
hwndApp = FindWindowEx(0, hwndApp, "XLMAIN", vbNullString)
hwndClient = FindWindowEx(hwndApp, 0, "XLDESK", vbNullString)
hwndBook = FindWindowEx(hwndClient, 0, "EXCEL7", vbNullString)
lngResult = SendMessage(hwndBook, WM_GETOBJECT, 0, ByVal OBJID_NATIVEOM)
If lngResult Then
bytID = IID_IDispatch & vbNullChar
IIDFromString bytID(0), IID(0)
lngRtnCode = ObjectFromLresult(lngResult, IID(0), 0, wkw)
Else
strMsg = "SendMessage Error "
End If
If Not wkw Is Nothing Then
strMsg = "確認できたよ " & wkw.Caption & vbTab 'OK
Else
strMsg = strMsg & "駄目でした"
End If
MsgBox strMsg
End Sub
iidfromstringというAPIがmsdnを読んでもどうしても理解できなかったので、自分なりにサンプルを書き換え実験をして今回の質問にいたりました。
熊谷隆史様がおっしゃるとおりIID_IaccessibleをIID_IDispatchにかえると私が始めに提示したtestもうまく動作しましたが、http://msdn.microsoft.com/en-us/library/dd373605(VS.85).aspx
にはIID_Iaccessibleを引き渡してくださいと書いてあるように見えますがこれも私の誤訳でしょうか?
> Dim wkw As Excel.Window
> lngRtnCode = ObjectFromLresult(lngResult, IID(0), 0, wkw)
ですので、IAccessible型の変数でないのでは。
タイプライブラリを用意して、
Dim oAccessible As IAccessible
lngRtnCode = AccessibleObjectFromWindow(hwndBook, OBJID_NATIVEOM, _
IID_IAccessible, oAccessible)
とでもすべきなのでは。
K.J.K様お付き合いくださって本当にありがとうございます。
アドバイスに従い以下のようなコードを組みましたが、うまく取れませんでした。
Option Explicit
Public Const OBJID_NATIVEOM = &HFFFFFFF0
Private Declare Function AccessibleObjectFromWindow Lib "oleacc" _
(ByVal hWnd As Long, ByVal dwId As Long, _
riid As Any, ppvObject As Any) As Long
Public Declare Function FindWindowEx Lib "user32" _
Alias "FindWindowExA" _
(ByVal hwndParent As Long, ByVal hwndChildAfter As Long, _
ByVal lpszClass As String, ByVal lpszWindow As String) As Long
Public Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Sub test4()
Dim oAccessible As IAccessible
Dim IID_IAccessible As GUID
Dim hwndApp As Long
Dim hwndClient As Long
Dim hwndBook As Long
Dim lngResult As Long
Dim lngRtnCode As Long
Dim strMsg As String
With IID_IAccessible
.Data1 = &H618736E0
.Data2 = &H3C3D
.Data3 = &H11CF
.Data4(0) = &H81
.Data4(1) = &HC
.Data4(2) = &H0
.Data4(3) = &HAA
.Data4(4) = &H0
.Data4(5) = &H38
.Data4(6) = &H9B
.Data4(7) = &H71
End With
hwndApp = FindWindowEx(0, hwndApp, "XLMAIN", vbNullString)
hwndClient = FindWindowEx(hwndApp, 0, "XLDESK", vbNullString)
hwndBook = FindWindowEx(hwndClient, 0, "EXCEL7", vbNullString)
AccessibleObjectFromWindow hwndBook, OBJID_NATIVEOM, _
IID_IAccessible, oAccessible
If Not oAccessible Is Nothing Then
strMsg = "確認できたよ " & oAccessible.Caption & vbTab 'OK
Else
strMsg = strMsg & "駄目でした"
End If
MsgBox strMsg
End Sub
ものによってはIID_IAccessibleを引き渡すとうまくいくので、取る対象によってIdispatchを引き渡したり、Iaccessibleを引き渡したり選ばないといけないということなのでしょうか。msdnを見る限りどちらでもよさそうですが、なにか法則があると理解しました。
お邪魔します。
>ものによってはIID_IAccessibleを引き渡すとうまくいくので、
>取る対象によってIdispatchを引き渡したり、Iaccessible を
>引き渡したり選ばないといけないということなのでしょうか。
>msdnを見る限りどちらでもよさそうですが、なにか法則が
>あると理解しました。
リンク先MSDNに下記のような記述があります。
To obtain an IDispatch interface pointer to a class
supported by the native object model, specify OBJID_NATIVEOM
in dwObjectID.
なのでご提示のコードを最小限修正するのなら、OBJID_NATIVEOMを
OBJID_WINDOWもしくはOBJID_CLIENTに変更すればよいと思います。
しかし、
Dim oAccessible As IAccessible
の宣言で
oAccessible.Captionは実行時エラーになりますよ。
Abyss様いつもお世話になっております。
まさかこの板でご回答をいただけると思っていませんでした。
>OBJID_WINDOWもしくはOBJID_CLIENT
なるほど確かにAccExplorer32.exeで調べるとワークブック(Excel7)には、role textがウィンドウのものとクライアントのものしかないので、IID_Iaccessibleを引き渡す場合、OBJID_WINDOW、OBJID_CLIENTのどちらかを
設定するのが正しいということですね。
Excel.window型のオブジェクトを得る場合はmsdnに書いてあるようにIID_IdispatchとOBJID_NATIVEOMを引き渡すとよいということですか。
かなりすっきりしました。
最後に一つだけご教示ください。
最初に私が提示したtestのようにObjectFromLresultにIID_IAccessibleを引き渡すのはまちがいでしょうか?(dim wkw as objectとか色々変更したけどうまく取れませんでした。IID_Iaccessibleを引き渡すというmsdnの記述がよく分かりません。)
>最初に私が提示したtestのようにObjectFromLresultに
>IID_IAccessibleを引き渡すのはまちがいでしょうか?
上級者からのレスがないですが、K.J.Kさんからのレス同様
WM_GETOBJECTメッセージはクライアント側で弄れる
メッセージではないです。そもそも、wParam値がなにに
なるかも分かりませんし。
クライアント側よりAccessibleObjectFromWindowなどの要求があったら、
システムのWindowProcにてWM_GETOBJECTメッセージ処理の結果、
IDispatchなりIAccessibleインターフェースポインタが
帰ってくるのでは?
分かりました。今回色々教えていただいたことでまえより随分理解が進みました。
K.J.K様、熊谷隆史様、Abyss様本当にありがとうございました。
今後ともよろしくお願いします。
チェックを忘れました
# 解決済みですが。
MSDNに明記されてないから腑に落ちないのでしょうけど。
そういうものだと思って頂くしかないかなと。
逆にObjectFromLresultの第一引数に指定するLRESULT値を
どうやって得るのかを考えてみてください。
lngLresult = LresultFromObject(IID_IAccessible, 0, ThisWorkbook.Windows(1))
では、同様にE_NOINTERFACEが返りますね。
lngLresult = LresultFromObject(IID_IDispatch, 0, ThisWorkbook.Windows(1))
では、きちんとLresult値が得られます。
(必ずしもLresultFromObjectが使われるわけではありませんが)
これは異プロセス/異スレッド間で使われる間接的なオブジェクトのマーシャリングです。
こちらのリンク先にあるのが直接的な手法ですね。
http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200703/07030025.txt
熊谷隆史様、ありがとうございます。
解決後に書き込めることを知りませんでした。
マーシャリングという言葉が検索してもよく分かりませんでした。(IIDFromStringが私が理解できない原因もそこにあります。)もう少し勉強してみます。
ツイート | ![]() |