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

わんくま同盟

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

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

■103694 / 3階層)  EXCEL VBAからのWindows.Forms呼出方法
□投稿者/ 魔界の仮面弁士 (3847回)-(2025/05/26(Mon) 10:44:40)
2025/05/26(Mon) 10:56:33 編集(投稿者)

No103692 (PATIO さん) に返信
> 某社が.net frameworkベースで開発してるGUIライブラリです。
その会社に協力を要請できないのでしょうか。

> そもそもライブラリの仕様すら公開されていません。
dnSpy を使えば、.NET や .NET Framework の EXE/DLL に対してデバッグや実装解析が可能です。
それを許容しない会社の場合、難読化されていて読み解けない可能性もありますが。
https://qiita.com/Tokeiya/items/54fbf30cb21c77c05c41
https://hakase0274.hatenablog.com/entry/2019/09/11/222621

> リストに基づいて処理を進めるようなインターフェイスが無いので
> EXCELマクロを利用してその部分の自動化をしようとしています。
.NET においては、無人操作のために Codeer Friendly を利用している所は見かけます。
https://www.nuget.org/packages?q=Codeer.Friendly

ただ、これは COM インターフェイスは搭載していなかったはずなので、VBA から呼び出したいのであれば、
先述の通り、VBA から呼び出すためのラッパーを C# 等で別途作成する必要があるでしょう。


No103689 (PATIO さん) に返信
> Accessibility Insights For Windowsでみた所、Nameプロパティで拾えるケースがある
ソースコードはこちら。
https://github.com/microsoft/accessibility-insights-windows


No103690 (魔界の仮面弁士) に追記
> Set objIUIAutomationElement = objUIAuto.ElementFromHandle(ByVal hWnd) 'もしくは ElementFromPoint
ElementFromHandle の呼び出しは可能ですが、VBA からだと
ElementFromPoint は直接呼び出せないことを忘れていました…。
ElementFromPoint の引数定義が「ByVal As ユーザー定義型」のため、VBA からは直接呼べません。

COM の低レベルAPI(DispCallFunc 関数)を使えば呼び出せますけれどね。
http://blog.livedoor.jp/tarboh_w-inko/archives/39939041.html

AccessibleObjectFromPoint API の方も「ByVal As ユーザー定義型」な引数ですが、
Declare 宣言を変更することで、同等の呼び出しスタックを再現できるため、
API 版の方が融通が利きます。

UIAutomation の ElementFromPoint メソッドで IUIAutomationElement を得る代わりに
AccessibleObjectFromPoint API でカーソル配下の IAccessible を得るようにしてみたサンプル。

'ThisWorkbook
Option Explicit

Private Declare PtrSafe Function GetCursorPos Lib "user32" (ByVal lpPoint As LongPtr) As Long

#If Win64 Then
Private Declare PtrSafe Function AccessibleObjectFromPoint Lib "Oleacc" (ByVal ptScreen As LongLong, ByRef ppacc As IAccessible, ByRef pvarChild As Variant) As Long
#Else
Private Declare PtrSafe Function AccessibleObjectFromPoint Lib "Oleacc" (ByVal x As Long, ByVal y As Long, ByRef ppacc As IAccessible, ByRef pvarChild As Variant) As Long
#End If

Public Sub ExampleWankuma103689()
  Dim pos(0 To 1) As Long
  Dim endTime As Double
  
  Dim accProp(0 To 2) As Variant
  Dim acc As Office.IAccessible
  Const CHILDID_SELF As Variant = &H0&
  Dim vnt As Variant
  vnt = CHILDID_SELF
  
  '10 秒間繰り返し
  Dim msg As String
  endTime = Timer + 10#
  Do Until endTime <= Timer
    GetCursorPos VarPtr(pos(0))
    msg = Format(endTime - Timer, "0.000") & "秒 (" & CStr(pos(0)) & ", " & CStr(pos(1)) & ")"
    Erase accProp
    On Error Resume Next
#If Win64 Then
    Dim posXY As LongLong
    posXY = pos(1) * &H100000000^ Or CLngLng(pos(0))
    AccessibleObjectFromPoint posXY, acc, vnt
#Else
    AccessibleObjectFromPoint pos(0), pos(1), acc, vnt
#End If
    If Not acc Is Nothing Then
      accProp(0) = Replace(acc.accName, vbNullChar, "")
      accProp(1) = Replace(acc.accValue, vbNullChar, "")
      accProp(2) = Replace(acc.accDescription, vbNullChar, "")
      Set acc = Nothing
      msg = msg & ",Name=[" & accProp(0) & "],Value=[" & accProp(1) & "],Description=[" & accProp(2) & "]"
    End If
    On Error GoTo 0
    [Sheet1!A1].Value = msg
    DoEvents
  Loop
End Sub


ただ、相手が .NET Framework 製のライブラリということで、
上記の IAccessible からでは十分に情報を得られないかも知れません。
UI の操作を行うことが目的なら、IAccessible よりも UI Automation の方が
目的に合致しすいかと。UI Automation の場合、上位のオブジェクトから
And/Or の条件指定で子孫要素を探索できる機構がありますし、
Web 上にも、VBA / .NET いずれに対してもそれなりに情報があると思います。

参考までに、ソースコード付きの VBA サンプルが下記にあります。
https://qiita.com/fenblen_puyo/items/d6d51470a648b9862c07
編集キー/

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

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

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