C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

■103690 / 1階層)  EXCEL VBAからのWindows.Forms呼出方法
□投稿者/ 魔界の仮面弁士 (3846回)-(2025/05/23(Fri) 14:09:31)
No103689 (PATIO さん) に返信
> EXCEL VBAからWindows.Formsのクラスライブラリを操作したいのですが、可能でしょうか?
> とある自動化案件で対象のプログラムが.net Frameworkをベース開発した独自GUIライブラリを使用しており、
その .NET Framework 製の「独自GUIライブラリ」というのは、どういったものなのでしょうか。

それが VSTO なのか ActiveX DLL なのか分かりませんが、
そのライブラリ内から System.Windows.Forms.Form を呼んでいるのではないのでしょうか。

> Win32APIを使ったファンクションでは、情報が拾えないケースが出てきています。
何に対して、どんな情報を拾おうとしているのでしょうか?
相手が System.Windows.Forms 名前空間のコントロールなのであれば、
その DLL 自体に操作用のメソッドを追加するのが手っ取り早いと思うのですが…。

既存の DLL に手を入れらないまま外部操作を試みているなら、
Win32、WinForms、WPF を外部操作可能な「Codeer Friendly」で操作できるか試してみるとか。
https://ishikawa-tatsuya.hatenablog.com/entry/2014/12/12/011333
https://github.com/Codeer-Software/Friendly/blob/master/README.jp.md
https://qiita.com/murasuke/items/936c4e12af314777e7b2
VBA からの操作が必要となると、Codeer Friendly をカプセル化する必要があるかもしれないので
今回の要件を満たすかどうかは何とも言えませんが。


> 具体的には対象のコントロールのウインドウハンドルを取得しようとしても特定が出来ない。
その「対象のコントロール」というのが、どこにある何者なのかも不明ですし、
どうやって hWnd を取得しようとしているのかについての言及も無いので、
すべて憶測でしか答えられませんが、もしもウィンドウハンドルが得られないのだとすれば、
そもそもウィンドウレスコントロールという可能性もありますね。
その場合は、UI Automation か MSAA に頼ることになりそう。


> 使用されているコントロールの内、同時実装分の物でWM_GETTEXTが全く効かない為、判別が出来ません。
ウィンドウハンドルは取得できるが、WM_GETTEXT で情報が得られかったという話をしているのでしょうか。
ウィンドウハンドルがあるからといって、WM_GETTEXT で情報が得られる保証は無いですよね。
それはターゲットのウィンドウ次第なわけで。

> Accessibility Insights For Windowsでみた所、Nameプロパティで拾えるケースがある事はわかりましたが、
> EXCEL VBAから拾う方法がわかりません。
VBA からであれば、MSAA の IAccessible インターフェイスで取得できると思います。
VBA からだと、IAccessible の accName プロパティかな。

IAccessible を得るには、
 方法1) 座標が分かっている場合は、AccessibleObjectFromPoint API
 方法2) hWnd が分かっている場合は、AccessibleObjectFromWindow API
 方法3) hWnd が無い場合は、ウィンドウを持つ祖先オブジェクトから子孫要素を辿る
といった方法があります。
昔は、OLEACC.DLL を参照設定する必要がありましたが、
最近の Excel なら、標準で Dim objAcc As Office.IAccessible と書けるので、そっちでも良いかも。
 'Call AccessibleObjectFromPoint32(x, y, objAcc, vnt)
 'Call AccessibleObjectFromPoint64(y * &H100000000^ Or x, objAcc, vnt)
 Call AccessibleObjectFromWindow(ByVal hWnd, OBJID_NATIVEOM, guidIDispatch, objAcc)
 Debug.Print objAcc.accName

※AccessibleObjectFromPoint の第一引数は POINT 構造体を「値渡し」する仕様なので、
 32bit VBA から呼ぶ場合は、第一引数を X 引数と Y 引数に分割したり、
 64bit VBA から呼ぶ場合は、X と Y を単一の 64bit 整数型にまとめてから値渡しするなどの工夫が必要。


あるいは、MSAA の後継たる UI Automation 経由でも得られるかと。
参照設定で UIAutomationClient を加えておいたうえで、
UIAutomationClient クラスの ElementFromHandle メソッドか ElementFromPoint メソッドを使うと、
操作対象の IUIAutomationElement を得られるので、そこから
 Dim objUIAuto As UIAutomationClient.CUIAutomation
 Set objUIAuto = New UIAutomationClient.CUIAutomation
 Dim objIUIAutomationElement As UIAutomationClient.IUIAutomationElement
 Set objIUIAutomationElement = objUIAuto.ElementFromHandle(ByVal hWnd) 'もしくは ElementFromPoint
 Dim objlegacy As UIAutomationClient.IUIAutomationLegacyIAccessiblePattern
 Set objlegacy = objIUIAutomationElement.GetCurrentPattern(UIA_LegacyIAccessiblePatternId)
 Debug.Print legacy.CurrentName
といった感じかと。


> 拾ったウインドウハンドルからForm.FromHandleで紐づけて拾えるのではと思っていますが、
NativeWindows.FromHandle メソッドや Control.FromHandle の話をされているのですか?
編集キー/

前の記事(元になった記事) 次の記事(この記事の返信)
←EXCEL VBAからのWindows.Forms呼出方法 /PATIO →Re[2]: EXCEL VBAからのWindows.Forms呼出方法 /PATIO
 
上記関連ツリー

EXCEL VBAからのWindows.Forms呼出方法 / PATIO (25/05/23(Fri) 11:53) #103689
EXCEL VBAからのWindows.Forms呼出方法 / 魔界の仮面弁士 (25/05/23(Fri) 14:09) #103690 ←Now
  └ Re[2]: EXCEL VBAからのWindows.Forms呼出方法 / PATIO (25/05/26(Mon) 09:30) #103692
    └ Re[3]: EXCEL VBAからのWindows.Forms呼出方法 / 魔界の仮面弁士 (25/05/26(Mon) 10:44) #103694

上記ツリーを一括表示 / 上記ツリーをトピック表示
 
上記の記事へ返信