Следите за новым проводником windows в Win32 API - PullRequest
0 голосов
/ 29 января 2020

В настоящее время я создаю программу для добавления вкладок в файловый менеджер Windows с использованием win32 API, поскольку меня не устраивает ни одна из программ, которые в настоящее время делают это (Clover, Groupy и многие другие). Для этого мне, очевидно, нужно получить все открытые в настоящее время проводники windows и заставить программу наблюдать за созданием новых windows.

В настоящее время я делаю это, вызывая EnumWindows в мои сообщения oop и присоединение к главному окну моей программы любого окна обозревателя, которое еще не прикреплено.

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

Это явно не оптимально (новые windows присоединяются к моей программе только тогда, когда сообщение отправлено в мою программу, и в целом все немного замедляется, особенно когда уже открыто много windows), и я хотел бы знать, есть ли способ просмотреть открытый список windows, чтобы запускать событие всякий раз, когда создается новое окно или что-либо в этом роде.

1 Ответ

2 голосов
/ 29 января 2020

Вот пример кода консоли (использует COM), который использует интерфейс IShell Windows. Сначала он сбрасывает текущий проводник windows («представления»), затем перехватывает события, вызванные сопутствующим интерфейсом 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...