今天被”Windows Shell外壳编程”搞残了.本来就是想在自己的应用程序中浏览文件,右键能够显示系统菜单.但是网上搜了一大堆资料都是讲”Shell扩展编程”的,差点没把我气死.后来在看雪找到了一个主题,见:http://bbs.pediy.com/showthread.php?p=573210
下载了一个”WTLExplorer”,哇塞!妈妈咪呀!这正是我所想要的,不过很可惜弹出的系统菜单不支持子菜单项的现实,于是又修改了一下终于可行了.
将ShellMgr.cpp文件中的DoContextMenu函数修改为:
BOOL CShellMgr::DoContextMenu(HWND hWnd, LPSHELLFOLDER lpsfParent, LPITEMIDLIST lpi, POINT point) {
	LPCONTEXTMENU spContextMenu;
	LPCONTEXTMENU pCtxMenuTemp = NULL;
	int menuType = 0;
	g_pIContext2 = NULL;
	g_pIContext3 = NULL;
	HRESULT hr = lpsfParent->GetUIObjectOf(hWnd, 1, (const struct _ITEMIDLIST**)&lpi, IID_IContextMenu, 0, (LPVOID*)&pCtxMenuTemp);
	if (FAILED(hr))
		return FALSE;
	if (pCtxMenuTemp->QueryInterface(IID_IContextMenu3, (void**)&spContextMenu) == NO_ERROR) {
		menuType = 3;
	} else if (pCtxMenuTemp->QueryInterface(IID_IContextMenu2, (void**)&spContextMenu) == NO_ERROR) {
		menuType = 2;
	} else if (pCtxMenuTemp->QueryInterface(IID_IContextMenu, (void**)&spContextMenu) == NO_ERROR) {
		menuType = 1;
	}
	HMENU hMenu = ::CreatePopupMenu();
	if (hMenu == NULL)
		return FALSE;
	// Get the context menu for the item.
	hr = spContextMenu->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_EXPLORE | CMF_NORMAL);
	if (FAILED(hr))
		return FALSE;
	// subclass window
	WNDPROC oldWndProc = NULL;
	if (menuType > 1) {
		// only subclass if it is IID_IContextMenu2 or IID_IContextMenu3
		oldWndProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG)HookWndProc);
		if (menuType == 2) {
			g_pIContext2 = (LPCONTEXTMENU2)spContextMenu;
		} else {
			g_pIContext3 = (LPCONTEXTMENU3)spContextMenu;
		}
	}
	int idCmd = ::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL);
	// unsubclass
	if (oldWndProc) {
		SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG)oldWndProc);
	}
	if (idCmd != 0) {
		USES_CONVERSION;
		// Execute the command that was selected.
		CMINVOKECOMMANDINFO cmi = { 0 };
		cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
		cmi.fMask = 0;
		cmi.hwnd = hWnd;
		cmi.lpVerb = T2CA(MAKEINTRESOURCE(idCmd - 1));
		cmi.lpParameters = NULL;
		cmi.lpDirectory = NULL;
		cmi.nShow = SW_SHOWNORMAL;
		cmi.dwHotKey = 0;
		cmi.hIcon = NULL;
		hr = spContextMenu->InvokeCommand(&cmi);
	}
	::DestroyMenu(hMenu);
	return TRUE;
}
再添加一个静态函数HookWndProc:
static LRESULT CALLBACK HookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	switch (message) {
	case WM_MENUCHAR: // only supported by IContextMenu3
		if (g_pIContext3) {
			LRESULT lResult = 0;
			g_pIContext3->HandleMenuMsg2(message, wParam, lParam, &lResult);
			return(lResult);
		}
		break;
	case WM_DRAWITEM:
	case WM_MEASUREITEM:
		if (wParam) {
			break; // if wParam != 0 then the message is not menu-related
		}
	case WM_INITMENUPOPUP:
		if (g_pIContext2) {
			g_pIContext2->HandleMenuMsg(message, wParam, lParam);
		} else {
			g_pIContext3->HandleMenuMsg(message, wParam, lParam);
		}
		return(message == WM_INITMENUPOPUP ? 0 : TRUE);
		break;
	default:
		break;
	}
	return ::CallWindowProc((WNDPROC)GetProp(hWnd, TEXT("oldWndProc")), hWnd, message, wParam, lParam);
}
这样就能显示系统菜单的子菜单项了,效果如图:

文档信息
- 本文作者:zhupite
- 本文链接:https://zhupite.com/program/WindowsShell%E5%A4%96%E5%A3%B3%E7%BC%96%E7%A8%8B%E5%88%9D%E6%8E%A2%E4%B9%8BWTLExplorer.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)