本文介绍了注意 Win32 API 中的新资源管理器窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在制作一个使用 win32 API 向 Windows 文件浏览器添加选项卡的程序,因为我对当前执行此操作的任何程序(Clover、Groupy 等)都不满意.为此,我显然需要获取当前打开的所有资源管理器窗口,并使程序监视正在创建的新窗口.

I'm currently making a program to add tabs to the Windows file explorer using the win32 API since I'm not satisfied by any of the programs that currently do that (Clover, Groupy to name a few).To do that I obviously need to get all explorer windows that are currently opened and to make the program watch for new windows being created.

我目前的做法是在我的消息循环中调用 EnumWindows,并将任何尚未附加的资源管理器窗口附加到我程序的主窗口.

The way I currently do it is by calling EnumWindows in my messages loop, and attaching to my program's main window any explorer window that isn't attached yet.

while(GetMessage(&uMsg, NULL, 0, 0) > 0)
{
    TranslateMessage(&uMsg);
    DispatchMessage(&uMsg);
    EnumWindows((WNDENUMPROC)findExplorerWindows, (LPARAM)mainWindow);
}

这显然不是最优的(只有在向我的程序发送消息时,新窗口才会附加到我的程序,总体而言它会减慢一切,特别是当已经有很多打开的窗口时)而且我想要了解是否有一种方法可以在创建新窗口或类似任何内容时监视打开的窗口列表以触发事件.

This is obviously not optimal (new windows only get attached to my program when a message is sent to my program, and overall it slows everything down quite a bit especially when there's already a lot of opened windows) and I'd like to know if there is a way to watch the opened windows list to fire an event whenever a new window is created or anything of that sort.

推荐答案

这里是一些使用 IShellWindows 界面.首先它转储当前的资源管理器窗口(视图"),然后它挂钩由配套接口引发的事件 DShellWindowsEvents

Here is some sample Console code (uses COM) that uses the IShellWindows interface.First it dumps the current explorer windows ("views"), then it hooks events raised by the companion interface DShellWindowsEvents

#include <atlbase.h>
#include <atlcom.h>
#include <shobjidl_core.h>
#include <shlobj_core.h>
#include <exdispid.h>


// a COM class that handles DShellWindowsEvents
class WindowsEvents : public IDispatch
{
  // poor man's COM object... we don't care, we're basically a static thing here
  STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject)
  {
    if (IsEqualIID(riid, IID_IUnknown))
    {
      *ppvObject = static_cast<IUnknown*>(this);
      return S_OK;
    }

    if (IsEqualIID(riid, IID_IDispatch))
    {
      *ppvObject = static_cast<IDispatch*>(this);
      return S_OK;
    }

    *ppvObject = NULL;
    return E_NOINTERFACE;
  }
  STDMETHODIMP_(ULONG) AddRef() { return 1; }
  STDMETHODIMP_(ULONG) Release() { return 1; }

  // this is what's called by the Shell (BTW, on the same UI thread)
  // there are only two events "WindowRegistered" (opened) and "WindowRevoked" (closed)
  STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
  {
    // first parameter is window's registration cookie
    int cookie = V_I4(&pDispParams->rgvarg[0]);
    if (dispIdMember == DISPID_WINDOWREGISTERED) // needs exdispid.h
    {
      wprintf(L"Window registered, cookie:%u\n", cookie);
    }
    else if (dispIdMember == DISPID_WINDOWREVOKED)
    {
      wprintf(L"Window revoked, cookie:%u\n", cookie);
    }

    // currently the cookie is not super useful, it's supposed to be usable by FindWindowSW
    CComVariant empty;
    long hwnd;
    CComPtr<IDispatch> window;
    HRESULT hr = Windows->FindWindowSW(&pDispParams->rgvarg[0], &empty, 0, &hwnd, SWFO_COOKIEPASSED, &window);
    // always returns S_FALSE... it does not seem to work
    // so, you'll have to ask for all windows again...
    return S_OK;
  }

  // the rest is left not implemented
  STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; }
  STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }
  STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { return E_NOTIMPL; }

public:
  CComPtr<IShellWindows> Windows;
};

int main()
{
  CoInitialize(NULL);
  {
    CComPtr<IShellWindows> windows;
    if (SUCCEEDED(windows.CoCreateInstance(CLSID_ShellWindows)))
    {
      // dump current windows
      long count = 0;
      windows->get_Count(&count);
      for (long i = 0; i < count; i++)
      {
        CComPtr<IDispatch> window;
        if (SUCCEEDED(windows->Item(CComVariant(i), &window)))
        {
          // get the window handle
          CComPtr<IWebBrowserApp> app;
          if (SUCCEEDED(window->QueryInterface(&app)))
          {
            HWND hwnd = NULL;
            app->get_HWND((SHANDLE_PTR*)&hwnd);
            wprintf(L"HWND[%i]:%p\n", i, hwnd);
          }
        }
      }

      // now wait for windows to open
      // get the DShellWindowsEvents dispinterface for events
      CComPtr<IConnectionPointContainer> cpc;
      if (SUCCEEDED(windows.QueryInterface(&cpc)))
      {
        // https://docs.microsoft.com/en-us/windows/win32/shell/dshellwindowsevents
        CComPtr<IConnectionPoint> cp;
        if (SUCCEEDED(cpc->FindConnectionPoint(DIID_DShellWindowsEvents, &cp)))
        {
          WindowsEvents events;
          events.Windows = windows;
          DWORD cookie = 0;

          // hook events
          if (SUCCEEDED(cp->Advise(&events, &cookie)))
          {
            // pump COM messages to make sure events arrive
            do
            {
              MSG msg;
              while (GetMessage(&msg, NULL, 0, 0))
              {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
              }
            } while (TRUE);

            // normally we should get here if someone sends a PostQuitMessage(0) to the current thread
            // but this is a console sample...

            // unhook events
            cp->Unadvise(cookie);
          }
        }
      }
    }
  }
  CoUninitialize();
  return 0;
}

这篇关于注意 Win32 API 中的新资源管理器窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 16:22