C++ 获取桌面(Desktop)选中项

835 阅读1分钟

代码思路来源于开源项目 QuickLook,并做了简化.

开始

在VS2017 下创建C++控制台项目,在预编译头文件添加适当的include

#ifndef PCH_H
#define PCH_H

// TODO: 添加要在此处预编译的标头
#include<atlcomcli.h>
#include<Exdisp.h>
#include<Shobjidl.h>
#include<shlguid.h>
#include<Shlobj.h>
#include<Shellapi.h>
#include<Psapi.h>
#include<AppModel.h>
#include<string>
#endif //PCH_H

// 以上为QuickLook所添加的头文件.

创建函数定义

void GetSelectedInternernal(CComQIPtr<IWebBrowserApp> pwba);
void ObtainFirstItem(CComPtr<IDataObject> dao);
void getSelectedFromDesktop();

main 函数

int main()
{
	for (;;)
	{
		getSelectedFromDesktop();
		Sleep(1000);
	}
}
// 考虑到测试用途直接来个无限循环+Sleep

getSelectedFromDesktop

void getSelectedFromDesktop() {
    // 初始化
	CoInitialize(nullptr);
	CComPtr<IShellWindows> psw;
	CComQIPtr<IWebBrowserApp> pwba;
	// 获取 IShellWindows 实例
	if (FAILED(psw.CoCreateInstance(CLSID_ShellWindows)))
		return;
	VARIANT pvarLoc;
	VariantInit(&pvarLoc);
	long phwnd;
	// 获取 IWebBrowserApp 实例
	if (FAILED(psw->FindWindowSW(&pvarLoc, &pvarLoc, SWC_DESKTOP, &phwnd, SWFO_NEEDDISPATCH, reinterpret_cast<IDispatch**>(
		&pwba))))
		return;
	GetSelectedInternernal(pwba);
}

GetSelectedInternernal

// 层层递进取得最终的IShellView,并取出选中项(SVGIO_SELECTION)
void GetSelectedInternernal(CComQIPtr<IWebBrowserApp> pwba) {
	CComQIPtr<IServiceProvider> psp;
	if (FAILED(pwba->QueryInterface(IID_IServiceProvider, reinterpret_cast<void**>(&psp)))) {
		return;
	}
	CComPtr<IShellBrowser> psb;
	if (FAILED(psp->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, reinterpret_cast<LPVOID*>(&psb)))) {
		return;
	}
	CComPtr<IShellView> psv;
	if (FAILED(psb->QueryActiveShellView(&psv))) {
		return;
	}
	CComPtr<IDataObject> dao;
	if (FAILED(psv->GetItemObject(SVGIO_SELECTION, IID_IDataObject, reinterpret_cast<void**>(&dao)))) {
		return;
	}
	ObtainFirstItem(dao);
}
// 最终提取文件地址
void ObtainFirstItem(CComPtr<IDataObject> dao) {
	FORMATETC formatetc;
	STGMEDIUM medium = { sizeof medium };
	formatetc.cfFormat = CF_HDROP;
	formatetc.ptd = nullptr;
	formatetc.dwAspect = DVASPECT_CONTENT;
	formatetc.lindex = -1;
	formatetc.tymed = TYMED_HGLOBAL;
	medium.tymed = TYMED_HGLOBAL;
	if (FAILED(dao->GetData(&formatetc, &medium)))
		return;
        // 获取选中数量
	int n = DragQueryFile(HDROP(medium.hGlobal), 0xFFFFFFFF, nullptr, 0);
	if (n < 1)
		return;
	WCHAR buffer[260] = { '\0' };
        // 选择第一个
	DragQueryFile(HDROP(medium.hGlobal), 0, buffer, MAX_PATH - 1);
	// 输出
	std::wcout << buffer << std::endl;
}

输出结果