ライブラリ

IEモードのEdgeからIEを取得するプログラム

サンプルブックはこちら↓(解凍パスワード:123)
EdgeIEmode【Pass:123】.zip
(2022/5/27 16:15 微調整  ※関数名を微調整、参照設定3を追記)

弁士さんに感謝(=人=)
 

Option Explicit
Option Private Module
'【参照設定1】Microsoft Internet Controls
'【参照設定2】Microsoft HTML Object Library
'【参照設定3】Microsoft Scripting Runtime?

Private EnumWindowDic       As Scripting.Dictionary
Private EnumChildDocHandle  As LongPtr
Private Declare PtrSafe Function EnumWindows Lib "user32" (ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long
Private Declare PtrSafe Function EnumChildWindows Lib "user32" (ByVal hWndParent As LongPtr, ByVal lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long
Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hWnd As LongPtr, ByVal lpClassname As String, ByVal nNameLength As Long) As Long

Private Declare PtrSafe Function CLSIDFromString Lib "ole32" (ByVal pString As LongPtr, ByRef pCLSID As Currency) As Long
Private Declare PtrSafe Function RegisterWindowMessageW Lib "user32" (ByVal lpString As LongPtr) As Long

Private Enum SMTO
    Normal = 0
    BLOCK = 1
    ABORTIFHUNG = 2
    NOTIMEOUTIFNOTHUNG = 8
End Enum
Private Declare PtrSafe Function SendMessageTimeoutW Lib "user32" (ByVal hWnd As LongPtr, ByVal MSG As Long, ByVal wParam As LongPtr, ByRef lParam As LongPtr, ByVal fuFlags As SMTO, ByVal uTimeout As Long, ByRef lpdwResult As Long) As LongPtr
Private Declare PtrSafe Function ObjectFromLresult Lib "oleacc" (ByVal lResult As Long, ByRef riid As Currency, ByVal wParam As LongPtr, ppvObject As Any) As Long

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type
Private Declare PtrSafe Function IIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, ByVal lpiid As LongPtr) As Long
Private Declare PtrSafe Function IUnknown_QueryService Lib "shlwapi.dll" (ByVal punk As IUnknown, ByVal guidService As LongPtr, ByVal riid As LongPtr, ByVal ppvOut As LongPtr) As Long

Private Function prSample()
    
    '全てのIEの辞書を取得
    Dim Dic_IE  As Scripting.Dictionary
    Set Dic_IE = fIE_Dic_ALL
    If Dic_IE.Count = 0 Then Exit Function
    
    Dim Key As Variant
    For Each Key In Dic_IE.Keys
        
        'Key=IEのウィンドウハンドル
        Dim hIE As LongPtr
        hIE = Key
        
        'IEオブジェクトを辞書から取り出す
        Dim IE  As InternetExplorer
        Set IE = Dic_IE.Item(Key)
        
'        Call IE.Navigate2("https://okwave.jp/qa/q8825108.html")
        
    Next
    
End Function

Private Function prEdge_Start(URL As String)
    
    '指定URLでEdgeを起動させる
    Dim WSH As Object
    WSH = CreateObject("WScript.Shell")
    Call WSH.Run("msedge.exe" & " " & URL & " " & "-new-window")
    
End Function

Public Function fIE_Dic_ALL() As Scripting.Dictionary
    
    '旧IEの辞書を作成
    Dim Dic_IE As Scripting.Dictionary
    Set Dic_IE = prIE_Dic_Old
    
    'IEモードのEdgeのウィンドウハンドルを辞書で取得
    Dim Dic_Edge As Scripting.Dictionary
    Set Dic_Edge = prIE_Dic_IEmodeEdge
    If Dic_Edge.Count > 0 Then
        
        '表示されてるEdgeのウィンドウのハンドルを回し
        Dim Key As Variant
        For Each Key In Dic_Edge.Keys
            
            Dim hEdge   As LongPtr
            hEdge = Key
            
            'IEのドキュメントのハンドルを取得
            Dim hIEDoc  As LongPtr
            hIEDoc = Dic_Edge.Item(Key)
            
            'ハンドルからDocumentを取得
            Dim Doc As HTMLDocument
            Set Doc = prIE_Handle_to_Doc(hIEDoc)
            If Doc Is Nothing = False Then
               
               'DocumentからIEを取得
                Dim IE  As InternetExplorer
                Set IE = prIE_from_Doc(Doc)
                If IE Is Nothing = False Then
                    Set Dic_IE.Item(CStr(IE.hWnd)) = IE
                End If
                
            End If
            
        Next
        
    End If
    
    Set fIE_Dic_ALL = Dic_IE
    
End Function

Private Function prIE_Dic_Old(Optional Visible As Boolean = True) As Scripting.Dictionary
    
    Dim Dic As Scripting.Dictionary
    Set Dic = New Scripting.Dictionary
    
    'IE,Explorer系のコレクションオブジェクトを生成
    '※生成時にコレクション済
    Dim Shell   As ShellWindows
    Set Shell = New ShellWindows
    
    '※権限の異なるIE等が起動されていると、ForEachだとデバッグ発生となるのでForIで対応
    Dim i   As Long
    For i = 1 To Shell.Count
        
        Dim Win As WebBrowser
        Set Win = Nothing
        On Error Resume Next
        Set Win = Shell.Item(i)
        On Error GoTo 0
        If Win Is Nothing = False Then
            
            With Win
                
                'IEの場合、指定の表示状態だったら、辞書に格納
                Dim Name    As String
                On Error Resume Next
                Name = Replace(.FullName, .Path, "")
                On Error GoTo 0
                If LCase(Name) = LCase("iexplore.exe") Then
                    If .Visible = Visible Then
                        Set Dic.Item(CStr(.hWnd)) = Win 'Key:ウィンドウハンドル, Item:IE
                    End If
                End If
                
            End With
            
        End If
        
    Next
    
    Set prIE_Dic_Old = Dic
    
End Function

Private Function prIE_Dic_IEmodeEdge() As Scripting.Dictionary
    
    '辞書を初期化
    Set EnumWindowDic = New Scripting.Dictionary
    
    'トップレベルのウィンドウハンドル全てに対して「EnumWindowProc」を実行させる
    Call EnumWindows(AddressOf prWindowEnumProc, 1)
    
    '[EnumWindowDic]に溜まった情報を、新規辞書に移し替えて返す
    Dim Dic As Scripting.Dictionary
    Set Dic = New Scripting.Dictionary
    Dim Key As Variant
    For Each Key In EnumWindowDic.Keys
        Dic.Item(Key) = EnumWindowDic.Item(Key)
    Next
    Set prIE_Dic_IEmodeEdge = Dic
    
    Set EnumWindowDic = Nothing '解放
    
End Function

Private Function prWindowEnumProc(ByVal hWnd As LongPtr, ByVal lParam As LongPtr) As Boolean
    
    'トップレベルのウィンドウハンドルのクラス名を取得
    Dim ClassName   As String
    ClassName = prWindowClassName(hWnd)
    
    'ウィンドウのクラスが、ブラウザの場合
    '※通常のEdgeの構成は [Chrome_RenderWidgetHostHWND][Chrome_RenderWidgetHostHWND] の2段階のみ
    Select Case ClassName
    Case "Chrome_WidgetWin_1", "Chrome_WidgetWin_2" '2:最小化時,別タブがアクティブ時
        
        'IEモードのドキュメントのハンドルが取得できたら辞書に貯めておく
        Dim hIEDoc  As LongPtr
        hIEDoc = prIE_DocumentHandle(hWnd)
        If hIEDoc <> 0 Then
            EnumWindowDic.Item(CStr(hWnd)) = CStr(hIEDoc)
        End If
        
    End Select
    
    prWindowEnumProc = True
    
End Function

Private Function prIE_DocumentHandle(hWnd As LongPtr) As LongPtr
    
    'クリア
    EnumChildDocHandle = 0
    
    '子ウィンドウハンドル全てに対して「EnumChildWindowProc」を実行させる
    Call EnumChildWindows(hWnd, AddressOf prWindowEnumChildProc, 1)
    
    prIE_DocumentHandle = EnumChildDocHandle
    
End Function

Private Function prWindowEnumChildProc(ByVal hWnd As LongPtr, ByVal lParam As LongPtr) As Boolean
    
    '子ウィンドウのクラス名を取得
    Dim ClassName   As String
    ClassName = prWindowClassName(hWnd)
    
    'ウィンドウのクラスが、IEモードの場合、格納しておく
    If ClassName = "Internet Explorer_Server" Then
        EnumChildDocHandle = hWnd
    End If
    
    prWindowEnumChildProc = True
    
End Function

Private Function prWindowClassName(hWnd As LongPtr) As String
    
    Dim Class As String
    Class = String$(255, 0)
    
    Dim Cnt As Long
    Cnt = GetClassName(hWnd, Class, Len(Class))
    If Cnt = 0 Then Exit Function
    
    prWindowClassName = Left$(Class, InStr(1, Class, vbNullChar) - 1)
    
End Function

Private Function prIE_Handle_to_Doc(ByVal hWnd_InternetExplorer_Server As LongPtr, _
                                    Optional ByVal uTimeout As Long = 1000, _
                                    Optional ByVal documentVersion As Integer = 1) As HTMLDocument
' Internet Explorer_Server ウィンドウのハンドルから HTMLDocument オブジェクトを取得する
'
' 第 1 引数: InternetExplorer_Server のウィンドウハンドル
' 第 2 引数: 省略可能(タイムアウト時間)
' 第 3 引数: 省略可能(1:IHTMLDocument~8:IHTMLDocument8)
    
    Dim DocVer  As Long
    DocVer = documentVersion
    If documentVersion <= 0 Then
        DocVer = 1
    ElseIf documentVersion >= 8 Then
        DocVer = 8
    End If
    
    Dim Dic_Doc As Scripting.Dictionary
    Set Dic_Doc = New Scripting.Dictionary
    Dic_Doc.Item(Dic_Doc.Count) = "" '★既定値★
    Dic_Doc.Item(Dic_Doc.Count) = "{626FC520-A41E-11cf-A731-00A0C9082637}"
    Dic_Doc.Item(Dic_Doc.Count) = "{332c4425-26cb-11d0-b483-00c04fd90119}"
    Dic_Doc.Item(Dic_Doc.Count) = "{3050f485-98b5-11cf-bb82-00aa00bdce0b}"
    Dic_Doc.Item(Dic_Doc.Count) = "{3050f69a-98b5-11cf-bb82-00aa00bdce0b}"
    Dic_Doc.Item(Dic_Doc.Count) = "{3050f80c-98b5-11cf-bb82-00aa00bdce0b}"
    Dic_Doc.Item(Dic_Doc.Count) = "{30510417-98b5-11cf-bb82-00aa00bdce0b}"
    Dic_Doc.Item(Dic_Doc.Count) = "{305104b8-98b5-11cf-bb82-00aa00bdce0b}"
    Dic_Doc.Item(Dic_Doc.Count) = "{305107d0-98b5-11cf-bb82-00aa00bdce0b}"
    
    Dim IID_IHTMLDocumentX As String
    IID_IHTMLDocumentX = Dic_Doc.Item(DocVer - 1)
    
    Dim InterfaceId(1) As Currency
    Call CLSIDFromString(StrPtr(IID_IHTMLDocumentX), InterfaceId(0))
    
    Dim lngMsg As Long
    lngMsg = RegisterWindowMessageW(StrPtr("WM_HTML_GETOBJECT"))
    If lngMsg = 0 Then Exit Function
    
    Dim lpdwResult As Long
    Dim hRet    As LongPtr
    hRet = SendMessageTimeoutW(hWnd_InternetExplorer_Server, lngMsg, 0, 0, SMTO.ABORTIFHUNG, uTimeout, lpdwResult)
    If hRet = 0 Then Exit Function
    
    Dim Obj As Object
    Dim hResult As Long
    hResult = ObjectFromLresult(lpdwResult, InterfaceId(0), 0, Obj)
    If hResult <> 0 Then Exit Function
    If Obj Is Nothing Then Exit Function
    
    Set prIE_Handle_to_Doc = Obj
    
End Function

Private Function prIE_from_Doc(Doc As HTMLDocument) As InternetExplorer
    
    'IE,DocumentのIIDを取得
    Const IKey_IWebBrowserApp   As String = "{0002DF05-0000-0000-C000-000000000046}"
    Const IKey_IWebBrowser2     As String = "{D30C1661-CDAF-11D0-8A3E-00C04FC9E26E}"
    Dim IID_IWebBrowserApp  As GUID
    Dim IID_IWebBrowser2    As GUID
    Dim Ret As Long
    Ret = IIDFromString(StrPtr(IKey_IWebBrowserApp), VarPtr(IID_IWebBrowserApp))
    Ret = IIDFromString(StrPtr(IKey_IWebBrowser2), VarPtr(IID_IWebBrowser2))
    
    'IHTMLWindow2を基に、IEオブジェクトを取得
'    IUnknown_QueryService
'    引数1:IHTMLWindow2         サービスをサポートするCOMオブジェクトのIUnknownインスタンスへのポインター
'    引数2:IID_IWebBrowserApp   サービスのユニークな識別子(SID)
'    引数3:IID_IWebBrowser2     目的のサービスインターフェイスのIID
'    引数4:(Ref)IEオブジェクト
    Dim IE  As InternetExplorer 'APIのByRef戻り値
    Ret = IUnknown_QueryService(Doc.parentWindow, VarPtr(IID_IWebBrowserApp), VarPtr(IID_IWebBrowser2), VarPtr(IE))
    If IE Is Nothing Then Exit Function
    If Ret <> 0 Then Exit Function
    
    '成功したらIEを返す
    Set prIE_from_Doc = IE
    
End Function

IE   2022/05/27   shono

この記事へのコメント

コメントを送る

 
※ メールは公開されません
Loading...
 画像の文字を入力してください