C++ 在Win32 API中查看新的资源管理器窗口
我目前正在制作一个程序,使用win32 API将选项卡添加到Windows文件资源管理器中,因为我对目前任何这样做的程序(Clover、Groupy等)都不满意。 要做到这一点,我显然需要获取当前打开的所有资源管理器窗口,并让程序监视正在创建的新窗口 我目前的做法是在我的消息循环中调用C++ 在Win32 API中查看新的资源管理器窗口,c++,c,windows,winapi,C++,C,Windows,Winapi,我目前正在制作一个程序,使用win32 API将选项卡添加到Windows文件资源管理器中,因为我对目前任何这样做的程序(Clover、Groupy等)都不满意。 要做到这一点,我显然需要获取当前打开的所有资源管理器窗口,并让程序监视正在创建的新窗口 我目前的做法是在我的消息循环中调用EnumWindows,并将任何尚未连接的资源管理器窗口附加到程序的主窗口 while(GetMessage(&uMsg, NULL, 0, 0) > 0) { TranslateMessag
EnumWindows
,并将任何尚未连接的资源管理器窗口附加到程序的主窗口
while(GetMessage(&uMsg, NULL, 0, 0) > 0)
{
TranslateMessage(&uMsg);
DispatchMessage(&uMsg);
EnumWindows((WNDENUMPROC)findExplorerWindows, (LPARAM)mainWindow);
}
这显然不是最优的(新窗口仅在消息发送到我的程序时才会连接到我的程序,总的来说,它会让一切都慢下来,特别是当已经有很多打开的窗口时)我想知道是否有一种方法可以监视打开的窗口列表,以便在创建新窗口或诸如此类的事件时触发事件。下面是一些使用该界面的示例控制台代码(使用COM)。 首先它转储当前的资源管理器窗口(“视图”),然后它钩住伴随接口引发的事件
#包括
#包括
#包括
#包括
#包括
//处理DShellWindowsEvents的COM类
类Windows事件:公共IDispatch
{
//可怜人的COM对象…我们不在乎,我们基本上是一个静态的东西
STDMETHODIMP查询接口(refid-riid,void**ppvObject)
{
if(IsequalID(riid,IID_IUnknown))
{
*ppvObject=静态投影(此);
返回S_OK;
}
if(IsequalID(riid,IID_IDispatch))
{
*ppvObject=静态投影(此);
返回S_OK;
}
*ppvObject=NULL;
返回E_NOINTERFACE;
}
STDMETHODIMP_ULONG)AddRef(){return 1;}
STDMETHODIMP_ULONG)Release(){return 1;}
//这就是Shell所称的(顺便说一句,在同一UI线程上)
//只有两个事件“WindowRegistered”(打开)和“WindowReversed”(关闭)
STDMETHODIMP调用(DISPID DISPID成员、refid riid、LCID LCID、单词wFlags、DISPPARAMS*pDispParams、VARIANT*pVarResult、EXCEPINFO*pExcepInfo、UINT*puArgErr)
{
//第一个参数是窗口的注册cookie
int cookie=V_I4(&pDispParams->rgvarg[0]);
if(DISPID member==DISPID\u windowregisted)//需要exdispid.h
{
wprintf(L“窗口已注册,cookie:%u\n”,cookie);
}
else if(DISPID member==DISPID\u windowreversed)
{
wprintf(L“窗口已撤销,cookie:%u\n”,cookie);
}
//目前cookie并不是非常有用,它应该可以被FindWindowSW使用
c变量为空;
长hwnd;
CComPtr窗口;
HRESULT hr=Windows->FindWindowSW(&pDispParams->rgvarg[0],&empty,0,&hwnd,SWFO_COOKIEPASSED,&window);
//总是返回S_FALSE…它似乎不起作用
//所以,你必须再次要求所有的窗口。。。
返回S_OK;
}
//其余的都没有实现
STDMETHODIMP GetTypeInfoCount(UINT*pctinfo){返回E_NOTIMPL;}
STDMETHODIMP GetTypeInfo(UINT-iTInfo,LCID-LCID,ITypeInfo**ppTInfo){return E_NOTIMPL;}
STDMETHODIMP GetIDsOfNames(refid-riid,LPOLESTR*rgszNames,UINT-cNames,LCID-LCID,DISPID*rgDispId){return E_NOTIMPL;}
公众:
计算机窗口;
};
int main()
{
共初始化(空);
{
计算机窗口;
如果(成功(windows.CoCreateInstance(CLSID_ShellWindows)))
{
//转储当前窗口
长计数=0;
windows->get_Count(&Count);
用于(长i=0;iItem(CComVariant(i),&window)))
{
//去拿窗户把手
CComPtr应用程序;
如果(成功(窗口->查询接口(&app)))
{
HWND HWND=NULL;
app->get_-HWND((SHANDLE_PTR*)&HWND);
wprintf(L“HWND[%i]:%p\n”,i,HWND);
}
}
}
//现在等待windows打开
//获取事件的DShellWindowsEvents dispinterface
中央采购委员会;
如果(成功(windows.QueryInterface(&cpc)))
{
// https://docs.microsoft.com/en-us/windows/win32/shell/dshellwindowsevents
CComPtr cp;
如果(成功(cpc->FindConnectionPoint(DIID\u DShellWindowsEvents,&cp)))
{
窗口事件;
events.Windows=Windows;
DWORD cookie=0;
//钩事件
if(成功(cp->advice(&events,&cookie)))
{
//发送COM消息以确保事件到达
做
{
味精;
while(GetMessage(&msg,NULL,0,0))
{
翻译信息(&msg);
发送消息(&msg);
}
}虽然(正确);
//通常,如果有人向当前线程发送PostQuitMessage(0),我们应该到达这里
//但这是一个控制台示例。。。
//脱钩事件
cp->Unadvise(cookie);
}
}
}
}
}
coninitialize();
返回0;
}
下面是一些使用该接口的示例控制台代码(使用COM)。
首先它转储当前的资源管理器窗口(“视图”),然后它钩住伴随接口引发的事件
#包括
#包括
#包括
#包括
#包括
//处理DShellWindowsEvents的COM类
类Windows事件:公共IDispatch
{
//可怜人的COM对象…我们不在乎,我们基本上是一个静态的东西
STDMETHODIMP查询接口(refid-riid,void**ppvObject)
{
if(IsequalID(riid,IID_IUnknown))
{
*ppvObject=静态投影(此);
返回S_OK;
}
if(IsequalID(riid,IID_IDispatch))
{
*ppvObject=静态投影(此);
返回S_OK;
}
*ppvObject=NULL;
返回E_NOINTERFACE;
}
STDMETHODIMP_ULONG)AddRef(){return 1;}
STDMETHODIMP_ULONG)Release(){return 1;}
//这就是Shell所称的(顺便说一句,在同一UI线程上)
//只有两个事件“WindowRegistered”(打开)和“W”
#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;
}