最近有使用用 Windows Shell/COM 用得比较多,于是做点笔记。
以下使用两种方式拿 IShellDispatch 实例指针,有了 IShellDisaptch 这种具有反射功能的东东,威力就大了。
第 1 种是直接创建的,接口功能偏少;第 2 种是拿的当前活动桌面的,接口功能丰富(代码是从 NSIS 的 StdUtils.dll 中抠出来的);
我也不太懂,就直接贴代码了吧,应该是直接就能用的,推荐使用第 2 种。
源代码文件:Source.cpp。
// C/C++
#include <iostream>
// Windows SDK
#include <windows.h>
// Windows Shell
#include <shldisp.h>
#include <ExDisp.h>
#include <ShObjIdl.h>
#include <ShlGuid.h>
// ATL/COM
#include <atlbase.h>
IShellDispatch* GetShellDispatch_v1()
{
HRESULT hr;
CComPtr<IShellDispatch> spShellDisp;
hr = CoCreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC, IID_IShellDispatch, (void**)&spShellDisp);
return SUCCEEDED(hr) && spShellDisp ? spShellDisp.Detach() : nullptr;
}
IShellDispatch* GetShellDispatch_v2()
{
IShellDispatch* pShellDispatch = nullptr;
CComPtr<IShellWindows> spShellWindows;
if (SUCCEEDED(::CoCreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&spShellWindows)))) {
HWND hDesktop;
CComPtr<IDispatch> spDisp;
CComVariant varEmpty;
if (SUCCEEDED(spShellWindows->FindWindowSW(&varEmpty, &varEmpty, SWC_DESKTOP, (long*)&hDesktop, SWFO_NEEDDISPATCH, &spDisp))) {
if (hDesktop != nullptr && hDesktop != INVALID_HANDLE_VALUE) {
CComPtr<IShellBrowser> spShellBrowser;
if (SUCCEEDED(IUnknown_QueryService(spDisp, SID_STopLevelBrowser, IID_PPV_ARGS(&spShellBrowser)))) {
CComPtr<IShellView> spShellView;
if (SUCCEEDED(spShellBrowser->QueryActiveShellView(&spShellView))) {
CComPtr<IDispatch> spBackgroundDisp;
if (SUCCEEDED(spShellView->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&spBackgroundDisp)))) {
DWORD dwProcessId;
if (::GetWindowThreadProcessId(hDesktop, &dwProcessId) && dwProcessId) {
::AllowSetForegroundWindow(dwProcessId);
}
if (CComQIPtr<IShellFolderViewDual> spShellFolderViewDual = spBackgroundDisp) {
CComPtr<IDispatch> spDisp;
if (SUCCEEDED(spShellFolderViewDual->get_Application(&spDisp))) {
if (CComQIPtr<IShellDispatch> spShellDispatch = spDisp) {
pShellDispatch = spShellDispatch.Detach();
}
}
}
}
}
}
}
}
}
return pShellDispatch;
}
int main()
{
CoInitialize(nullptr);
IShellDispatch* pShellDispatch = nullptr;
// v1
pShellDispatch = GetShellDispatch_v1();
std::cout << pShellDispatch << std::endl;
pShellDispatch && pShellDispatch->Release();
// v2
pShellDispatch = GetShellDispatch_v2();
std::cout << pShellDispatch << std::endl;
pShellDispatch && pShellDispatch->Release();
CoUninitialize();
return 0;
}