如何从 InternetExplorer 对象获取 HWND

问题描述

我正在尝试获取 Windows 资源管理器窗口的当前文件夹位置。 使用此代码段,我可以迭代所有窗口并获取它们的位置。 但是,我需要将它们与它们的窗口句柄进行匹配,以便我可以根据文件夹位置操作窗口样式、位置、父级、标题等。

或者,是否可以从 HWND 获取 InternetExplorer 对象?

public void doStuff()
{
    var t = Type.GetTypeFromProgID("Shell.Application");
    var o = Activator.CreateInstance(t) as Shell32.Shell;

    try
    {
        var ws = o.Application.Windows();

        for (int i = 0; i < ws.Count; i++)
        {
            var ie = ws.Item(i);

            if (ie == null)
                continue;

            var path = System.IO.Path.GetFileName((string)ie.FullName);

            if (path.ToLower() != "explorer.exe")
                continue;

            // Gets the folder that it is showing
            temp = ie.LocationURL.ToString();
            temp = new Uri(temp).LocalPath;

            // How can I get the window handle?
            // ie.hwnd returns the top most window handle
            // So if the explorer window is embedded,it returns the wrong window handle
        }
    }
    catch (Exception x)
    {
        Console.log(x.Message);
    }
    finally
    {
        if (o != null)
            Marshal.FinalReleaseComObject(o);
    }
}

解决方法

编辑:

不知道是什么让你的代码花了这么长时间。在 PowerShell 中,检索 HWND-FolderPath 关联需要 90 毫秒,而不是 15 秒!我希望它在编译代码中更快:

PS C:\> $shell.windows() | select HWND,@{ N = 'Path'  ; E = { $_.Document.Folder.Self.Path }}

   HWND Path
   ---- ----
1180948 C:\Users\keith\Documents
 198040 C:\Users\keith\Pictures
 328592 C:\Windows
 721672 C:\Users\keith\Videos
 198538 C:\Users\keith\DummyDesktop


PS C:\> Measure-Command -Expression  {$shell.windows() | select HWND,@{ N = 'Path'  ; E = { $_.Document.Folder.Self.Path }}}


Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 90
Ticks             : 904963
TotalDays         : 1.04741087962963E-06
TotalHours        : 2.51378611111111E-05
TotalMinutes      : 0.00150827166666667
TotalSeconds      : 0.0904963
TotalMilliseconds : 90.4963

我的回答中的分步方法是为了理解。假设之前创建了 Shell 对象,您只需要上面的一行。



我刚刚通过 PowerShell 中的 Shell.Application COM 对象使用文件资源管理器窗口,因此您必须进行一些代码转换,但对象、属性和方法应该是一样的。

Shell 对象的 Windows 方法返回一个 Shellwindows 对象,该对象“代表属于 Shell 的打开窗口的集合”。这包含 Internet Explorer文件资源管理器(包括控制面板)窗口:

PS C:\>>$Shell = New-Object -ComObject shell.application
PS C:\> $shell.windows() |
>>   Format-Table -AutoSize -Wrap -Property Name,TYpe,LocationName,LocationURL -GroupBy FullName


   FullName: C:\Program Files (x86)\Internet Explorer\IEXPLORE.EXE

Name              Type          LocationName LocationURL
----              ----          ------------ -----------
Internet Explorer HTML Document Google       https://www.google.com/?gws_rd=ssl#spf=1627718454134


   FullName: C:\WINDOWS\explorer.exe

Name          Type LocationName  LocationURL
----          ---- ------------  -----------
File Explorer      Documents     file:///C:/Users/keith/Documents
File Explorer      Control Panel
File Explorer      Libraries
File Explorer      Quick access
File Explorer      Network

但所有窗口确实都是 InternetExplorer 对象。

PS C:\>>$Shell.Windows() | Get-Member


   TypeName: System.__ComObject#{d30c1661-cdaf-11d0-8a3e-00c04fc9e26e}

Name                 MemberType Definition
----                 ---------- ----------
ClientToWindow       Method     void ClientToWindow (int,int)
ExecWB               Method     void ExecWB (OLECMDID,OLECMDEXECOPT,Variant,Variant)
GetProperty          Method     Variant GetProperty (string)
GoBack               Method     void GoBack ()
GoForward            Method     void GoForward ()
GoHome               Method     void GoHome ()
GoSearch             Method     void GoSearch ()
Navigate             Method     void Navigate (string,Variant)
Navigate2            Method     void Navigate2 (Variant,Variant)
PutProperty          Method     void PutProperty (string,Variant)
QueryStatusWB        Method     OLECMDF QueryStatusWB (OLECMDID)
Quit                 Method     void Quit ()
Refresh              Method     void Refresh ()
Refresh2             Method     void Refresh2 (Variant)
ShowBrowserBar       Method     void ShowBrowserBar (Variant,Variant)
Stop                 Method     void Stop ()
AddressBar           Property   bool AddressBar () {get} {set}
Application          Property   IDispatch Application () {get}
Busy                 Property   bool Busy () {get}
Container            Property   IDispatch Container () {get}
Document             Property   IDispatch Document () {get}
FullName             Property   string FullName () {get}
FullScreen           Property   bool FullScreen () {get} {set}
Height               Property   int Height () {get} {set}
HWND                 Property   int HWND () {get}
Left                 Property   int Left () {get} {set}
LocationName         Property   string LocationName () {get}
LocationURL          Property   string LocationURL () {get}
MenuBar              Property   bool MenuBar () {get} {set}
Name                 Property   string Name () {get}
Offline              Property   bool Offline () {get} {set}
Parent               Property   IDispatch Parent () {get}
Path                 Property   string Path () {get}
ReadyState           Property   tagREADYSTATE ReadyState () {get}
RegisterAsBrowser    Property   bool RegisterAsBrowser () {get} {set}
RegisterAsDropTarget Property   bool RegisterAsDropTarget () {get} {set}
Resizable            Property   bool Resizable () {get} {set}
Silent               Property   bool Silent () {get} {set}
StatusBar            Property   bool StatusBar () {get} {set}
StatusText           Property   string StatusText () {get} {set}
TheaterMode          Property   bool TheaterMode () {get} {set}
ToolBar              Property   int ToolBar () {get} {set}
Top                  Property   int Top () {get} {set}
TopLevelContainer    Property   bool TopLevelContainer () {get}
Type                 Property   string Type () {get}
Visible              Property   bool Visible () {get} {set}
Width                Property   int Width () {get} {set}

TypeMame 的 GUID 表明它本质上是 IWebBrowser2 接口的包装器。

这是您接下来要访问的容易被忽视的 Document 属性。该链接揭示了为什么当您处于 Explorer/Shell 框架的 mnid 中时,这很容易被忽略。它公开了以下方法和属性:

PS C:\>>$FolderWIndows[0].Document | Get-Member


   TypeName: System.__ComObject#{29ec8e6c-46d3-411f-baaa-611a6c9cac66}

Name               MemberType Definition
----               ---------- ----------
FilterView         Method     void FilterView (string)
PopupItemMenu      Method     string PopupItemMenu (FolderItem,Variant)
SelectedItems      Method     FolderItems SelectedItems ()
SelectItem         Method     void SelectItem (Variant,int)
SelectItemRelative Method     void SelectItemRelative (int)
Application        Property   IDispatch Application () {get}
CurrentViewMode    Property   uint CurrentViewMode () {get} {set}
FocusedItem        Property   FolderItem FocusedItem () {get}
Folder             Property   Folder Folder () {get}
FolderFlags        Property   uint FolderFlags () {get} {set}
GroupBy            Property   string GroupBy () {get} {set}
IconSize           Property   int IconSize () {get} {set}
Parent             Property   IDispatch Parent () {get}
Script             Property   IDispatch Script () {get}
SortColumns        Property   string SortColumns () {get} {set}
ViewOptions        Property   int ViewOptions () {get}

但它的 Folder 属性返回窗口中显示的文件夹的 Folder 对象。 Folder 对象及其关联的 FolderItem 对象公开了与 Shell 命名空间中的项关联的属性和方法。 FolderItem 通过 SelfFolder 属性检索:

PS C:\>>$FolderWIndows.Document.Folder | Get-Member


   TypeName: System.__ComObject#{a7ae5f64-c4d7-4d7f-9307-4d24ee54b841}

Name                       MemberType Definition
----                       ---------- ----------
CopyHere                   Method     void CopyHere (Variant,Variant)
DismissedWebViewBarricade  Method     void DismissedWebViewBarricade ()
GetDetailsOf               Method     string GetDetailsOf (Variant,int)
Items                      Method     FolderItems Items ()
MoveHere                   Method     void MoveHere (Variant,Variant)
NewFolder                  Method     void NewFolder (string,Variant)
ParseName                  Method     FolderItem ParseName (string)
Synchronize                Method     void Synchronize ()
Application                Property   IDispatch Application () {get}
HaveToShowWebViewBarricade Property   bool HaveToShowWebViewBarricade () {get}
OfflineStatus              Property   int OfflineStatus () {get}
Parent                     Property   IDispatch Parent () {get}
ParentFolder               Property   Folder ParentFolder () {get}
Self                       Property   FolderItem Self () {get}
ShowWebViewBarricade       Property   bool ShowWebViewBarricade () {get} {set}
Title                      Property   string Title () {get}


PS C:\>>$FolderWIndows.Document.Folder.Self | Get-Member


   TypeName: System.__ComObject#{edc817aa-92b8-11d1-b075-00c04fc33aa5}

Name             MemberType Definition
----             ---------- ----------
ExtendedProperty Method     Variant ExtendedProperty (string)
InvokeVerb       Method     void InvokeVerb (Variant)
InvokeVerbEx     Method     void InvokeVerbEx (Variant,Variant)
Verbs            Method     FolderItemVerbs Verbs ()
Application      Property   IDispatch Application () {get}
GetFolder        Property   IDispatch GetFolder () {get}
GetLink          Property   IDispatch GetLink () {get}
IsBrowsable      Property   bool IsBrowsable () {get}
IsFileSystem     Property   bool IsFileSystem () {get}
IsFolder         Property   bool IsFolder () {get}
IsLink           Property   bool IsLink () {get}
ModifyDate       Property   Date ModifyDate () {get} {set}
Name             Property   string Name () {get} {set}
Parent           Property   IDispatch Parent () {get}
Path             Property   string Path () {get}
Size             Property   int Size () {get}
Type             Property   string Type () {get}

这是您想要的 FolderItem 的 Path 属性。

PS C:\>>$FolderWIndows | select HWND,>>                              @{ N = 'Title' ; E = { $_.Document.Folder.Title }},>>                              @{ N = 'Path'  ; E = { $_.Document.Folder.Self.Path }}

   HWND Title         Path
   ---- -----         ----
3080380 Documents     C:\Users\keith\Documents
  68614 Control Panel ::{26EE0668-A00A-44D7-9371-BEB064C98683}
 853746 Libraries     ::{031E4825-7B94-4DC3-B131-E946B44C8DD5}
1245532 Quick access  ::{679F85CB-0220-4080-B29B-5540CC05AAB6}
 199810 Network       ::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}

对于文件资源管理器和Shell命名空间,FolderItem的路径可能不明确。您可以通过递归评估 ParentFolder 对象来确定命名空间路径,直到您到达没有父级的 shell 命名空间的根桌面。

Function Get-NSPath ( $oFolder )
{
    If     (( $oParent = $oFolder.ParentFolder ).ParentFolder )
    {
           (( Get-NSPath $oParent ),$oFolder.Title ) -join '\'
    }
    ElseIf ( $oParent )
    {
           $oFolder.Title       # Desktop/NavPane Item
    }
}   # If oFolder was the virtual Desktop,Namespace path is null.

从多个位置打开 DOcumentes 文件夹后:

$FolderWindows = $shell.Windows() | Where FullName -match 'explorer.exe$'
PS C:\>>$FolderWIndows | select HWND,>>                              @{ N = 'Title'     ; E = { $_.Document.Folder.Title }},>>                              @{ N = 'Path'      ; E = { $_.Document.Folder.Self.Path }},>>                              @{ N = 'NameSpace' ; E = { Get-NSPath $_.Document.Folder }}

   HWND Title     Path                     NameSpace
   ---- -----     ----                     ---------
 265366 Documents C:\Users\keith\Documents This PC\Documents
 331000 Documents C:\Users\keith\Documents Keith Miller\Documents
2950776 Documents C:\Users\keith\Documents This PC\Windows (C:)\Users\keith\Documents
 396606 Documents C:\Users\keith\Documents Libraries\Documents\Documents