给程序内部菜单增加指定的explorer菜单

Tips

为了将explorer的右键菜单项的某个菜单增加到我们程序内部的菜单,我们需要做以下几件事情:

  1. 获得指定文件的IShellFolder
  2. 获得指定文件的IContextMenu
  3. 创建菜单A,并且把IContextMenu的内容填充到菜单A
  4. 查询菜单A,找到我们想要的菜单项
  5. 取出我们想要的菜单项的内容,填充到我们想要真正弹出的菜单B
  6. 弹出菜单B
  7. 用IContextMenu响应用户对菜单的选择

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
CComPtr<IShellFolder> GetParentFolder(LPCWSTR szFolder)
{
CComPtr<IShellFolder> pDesktop;
SHGetDesktopFolder(&pDesktop);
if (NULL == pDesktop)
{
return NULL;
}

ULONG pchEaten = 0;
LPITEMIDLIST pidl = NULL;
DWORD dwAttributes = 0;
HRESULT hr = pDesktop->ParseDisplayName(NULL, NULL, (LPTSTR)szFolder, NULL, &pidl, NULL);
if (S_OK != hr)
{
return NULL;
}

CComPtr<IShellFolder> pParentFolder = NULL;
hr = pDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (void**)&pParentFolder);
if (S_OK != hr)
{
CoTaskMemFree(pidl);
return NULL;
}

CoTaskMemFree(pidl);

return pParentFolder;
}

std::wstring GetDirectory(LPCWSTR szFile)
{
WCHAR szDrive[_MAX_DRIVE];
WCHAR szDir[_MAX_DIR];
WCHAR szFName[_MAX_FNAME];
WCHAR szExt[_MAX_EXT];
_wsplitpath_s(szFile, szDrive, szDir, szFName, szExt);

std::wstring strResult = szDrive;
strResult += szDir;
return strResult;
}

std::wstring GetFileNameWithExt(LPCWSTR szFile)
{
WCHAR szDrive[_MAX_DRIVE];
WCHAR szDir[_MAX_DIR];
WCHAR szFName[_MAX_FNAME];
WCHAR szExt[_MAX_EXT];
_wsplitpath_s(szFile, szDrive, szDir, szFName, szExt);

std::wstring strResult = szFName;
strResult += szExt;
return strResult;
}
void qtmenutest::ShowContextMenu(const QPoint &pos)
{
m_pContextMenu.Release();
QMenu contextMenu(tr("Context menu"), this);

std::wstring strFilePath = L"d:\\1.jpg";
CComPtr<IShellFolder> pParentFolder = GetParentFolder(GetDirectory(strFilePath.c_str()).c_str());
if (NULL == pParentFolder)
{
return;
}

std::wstring strFile = GetFileNameWithExt(strFilePath.c_str());
ULONG pchEaten = 0;
LPITEMIDLIST pidl = NULL;
DWORD dwAttributes = 0;
HRESULT hr = pParentFolder->ParseDisplayName(WId(), NULL, (LPWSTR)strFile.c_str(), &pchEaten, &pidl, &dwAttributes);
if (S_OK != hr)
{
return;
}


UINT refReversed = 0;
hr = pParentFolder->GetUIObjectOf(WId(), 1, (LPCITEMIDLIST *)&pidl, IID_IContextMenu, &refReversed, (void **)&m_pContextMenu);
if (S_OK != hr)
{
CoTaskMemFree(pidl);
return;
}

HMENU hMenu = CreatePopupMenu();
if (hMenu == NULL) {
CoTaskMemFree(pidl);
return;
}

m_pContextMenu->QueryContextMenu(hMenu, 0, 100, 200, CMF_EXPLORE | CMF_NORMAL);
int nMenuCount = GetMenuItemCount(hMenu);
HMENU hSubMenu = NULL;
WCHAR szMenuText[MAX_PATH];
for (int i = 0; i < nMenuCount; i++) {
GetMenuStringW(hMenu, i, szMenuText, MAX_PATH, MF_BYPOSITION);
if (wcsstr(szMenuText, L"some_ui_text")) {
hSubMenu = GetSubMenu(hMenu, i);
break;
}
}

QMenu *subMenu = contextMenu.addMenu(QString::fromWCharArray(szMenuText));
int nSubMenuCount = GetMenuItemCount(hSubMenu);
for (int i = 0; i < nSubMenuCount; i++) {
GetMenuStringW(hSubMenu, i, szMenuText, MAX_PATH, MF_BYPOSITION);
int nCmdId = GetMenuItemID(hSubMenu, i);
QAction *curAct = subMenu->addAction(QString::fromWCharArray(szMenuText));
if (curAct) {
curAct->setData(nCmdId);
}
}

QAction *selAct = contextMenu.exec(mapToGlobal(pos));
if (selAct) {
int nSelId = selAct->data().toInt();
if (nSelId) {
CMINVOKECOMMANDINFO info = {0};
info.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
info.lpVerb = MAKEINTRESOURCEA(nSelId - 100);
m_pContextMenu->InvokeCommand(&info);
}
}

DestroyMenu(hMenu);
CoTaskMemFree(pidl);
return;
}

Post Directory

Article directory