我在CSDN提问题一直没人回复,一下午时间自己终于解决了问题

http://bbs.csdn.net/topics/391916381

现将过程录下

先说需求,我想实现的功能是 在程序中对文件调用百度网盘/qq的接口,发送给好友或上传到网盘,实现思路是右键菜单

现在我已经实现了在我的窗口中能够调出系统的右键菜单,并实现接口。
思路是 IShellFolder->ParseDisplayName 得到 文件到PIDL,IShellFolder->GetUIObjectOf() 得到IContextMenu 接口。
然后IContextMenu->QueryContextMenu() 得到菜单,再弹出菜单后,根据返回值调用 IContextMenu->InvokeCommand() 实现对文件的命令。

现在问题来了。
1. 在资源管理器中右键是有百度云盘的,但是在自己的窗口中没有。
2. 如何不弹出菜单,直接调用命令
3. 有可能右键菜单没有,但是QQShellExt YunShellExt 的COM接口还是存在的,有没有可能跳过ShellFolder->GetUiObjectOf 直接得到与云盘或QQ相关的 IContextMenu 或单独初始化一个。也就是有没有可能直接调用 QQShellExt 或 YunShellExt 的接口?

下面是我测试右键菜单的相关代码:

ShellContextMenu.h

 #pragma once
class CShellContextMenu
{
public:
CShellContextMenu();
~CShellContextMenu(); public: bool ShowContextMenu(const CStringArray& files, HWND hWnd, LPPOINT pt); IShellFolder* GetDesktopFolder();
IShellFolder* GetParentFolder(LPCTSTR szFolder); CString GetDirectory(LPCTSTR szFile);
CString GetFileNameWithExt(LPCTSTR szFile); bool GetPidls(const CStringArray& files); private:
IContextMenu* GetContextMenuInterfaces(IShellFolder* pShellFolder, CArray<LPCITEMIDLIST>& idls);
bool InvokeCmd(IContextMenu* pContext, LPCTSTR szCmd, LPCTSTR szFolder);
bool InvokeCmd(IContextMenu* pContext, int nCmdSelection, LPCTSTR szFolder, LPPOINT pt);
bool ShowContextMenu(HWND hWnd, LPPOINT pt); void ReleaseIdls();
void ReleaseAll(); private:
CArray<LPCITEMIDLIST> m_idls; IShellFolder* m_pDesktopFolder;
IShellFolder* m_pParentFolder;
IContextMenu* m_pContextMenu;
IContextMenu2* m_pContextMenu2;
IContextMenu3* m_pContextMenu3; CString m_strParentFolder;
};

ShellContextMenu.cpp

 #include "stdafx.h"
#include "ShellContextMenu.h" CShellContextMenu::CShellContextMenu()
{
m_pDesktopFolder = nullptr;
m_pParentFolder = nullptr; m_pContextMenu = nullptr;
m_pContextMenu2 = nullptr;
m_pContextMenu3 = nullptr;
} CShellContextMenu::~CShellContextMenu()
{
ReleaseAll();
} bool CShellContextMenu::ShowContextMenu(const CStringArray& files, HWND hWnd, LPPOINT pt)
{
ReleaseAll(); if (!GetPidls(files))
{
return false;
} return ShowContextMenu(hWnd, pt);
} IShellFolder* CShellContextMenu::GetDesktopFolder()
{
// 获取桌面指针
if (nullptr == m_pDesktopFolder)
{
if (S_OK != SHGetDesktopFolder(&m_pDesktopFolder))
{
return nullptr;
}
} return m_pDesktopFolder;
} IShellFolder* CShellContextMenu::GetParentFolder(LPCTSTR szFolder)
{
if (nullptr == m_pParentFolder)
{
auto pDesktop = GetDesktopFolder();
if (nullptr == pDesktop)
{
return nullptr;
} ULONG pchEaten = ;
LPITEMIDLIST pidl = nullptr;
DWORD dwAttributes = ;
auto hr = pDesktop->ParseDisplayName(nullptr, nullptr, (LPTSTR)szFolder, nullptr, &pidl, nullptr);
if (S_OK != hr)
{
return nullptr;
} STRRET sRetName;
hr = pDesktop->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &sRetName);
if (S_OK != hr)
{
CoTaskMemFree(pidl);
return nullptr;
} hr = StrRetToBuf(&sRetName, pidl, m_strParentFolder.GetBuffer(_MAX_PATH), _MAX_PATH);
m_strParentFolder.ReleaseBuffer();
if (S_OK != hr)
{
CoTaskMemFree(pidl);
return nullptr;
} IShellFolder* pParentFolder = nullptr;
hr = pDesktop->BindToObject(pidl, nullptr, IID_IShellFolder, (void**)&pParentFolder);
if (S_OK != hr)
{
CoTaskMemFree(pidl);
return nullptr;
} CoTaskMemFree(pidl); m_pParentFolder = pParentFolder; } return m_pParentFolder;
} CString CShellContextMenu::GetDirectory(LPCTSTR szFile)
{
TCHAR szDrive[_MAX_DRIVE];
TCHAR szDir[_MAX_DIR];
TCHAR szFName[_MAX_FNAME];
TCHAR szExt[_MAX_EXT];
_tsplitpath_s(szFile, szDrive, szDir, szFName, szExt); CString strResult = szDrive;
strResult += szDir;
return strResult;
} CString CShellContextMenu::GetFileNameWithExt(LPCTSTR szFile)
{
TCHAR szDrive[_MAX_DRIVE];
TCHAR szDir[_MAX_DIR];
TCHAR szFName[_MAX_FNAME];
TCHAR szExt[_MAX_EXT];
_tsplitpath_s(szFile, szDrive, szDir, szFName, szExt); CString strResult = szFName;
strResult += szExt;
return strResult;
} bool CShellContextMenu::GetPidls(const CStringArray& files)
{
ReleaseIdls(); if (files.IsEmpty())
{
return false;
} auto pParentFolder = GetParentFolder(GetDirectory(files[]));
if (nullptr == pParentFolder)
{
return false;
} for (int i = ; i < files.GetSize(); i++)
{
CString strFile = GetFileNameWithExt(files[i]); ULONG pchEaten = ;
LPITEMIDLIST pidl = nullptr;
DWORD dwAttributes = ;
auto hr = pParentFolder->ParseDisplayName(nullptr, nullptr, (LPTSTR)(LPCTSTR)strFile, &pchEaten, &pidl, &dwAttributes);
if (S_OK != hr)
{
continue;
} m_idls.Add(pidl); } return !m_idls.IsEmpty(); } IContextMenu* CShellContextMenu::GetContextMenuInterfaces(IShellFolder* pShellFolder, CArray<LPCITEMIDLIST>& idls)
{
IContextMenu* pResult = nullptr;
UINT refReversed = ;
auto hr = pShellFolder->GetUIObjectOf(nullptr, idls.GetSize(), idls.GetData(), IID_IContextMenu, &refReversed, (void**)&pResult);
if (S_OK != hr)
{
return nullptr;
} return pResult;
} bool CShellContextMenu::InvokeCmd(IContextMenu* pContext, LPCTSTR szCmd, LPCTSTR szFolder)
{
CMINVOKECOMMANDINFOEX info;
info.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
info.lpVerbW = szCmd;
info.lpDirectoryW = szFolder;
info.fMask = CMIC_MASK_UNICODE; return S_OK == pContext->InvokeCommand((CMINVOKECOMMANDINFO*)&info); } /// <summary>
/// 调用命令
/// </summary>
/// <param name="pContext"></param>
/// <param name="nCmdSelection"></param>
/// <param name="szFolder"></param>
/// <returns></returns>
bool CShellContextMenu::InvokeCmd(IContextMenu* pContext, int nCmdSelection, LPCTSTR szFolder, LPPOINT pt)
{
try
{
USES_CONVERSION;
CMINVOKECOMMANDINFOEX invoke;
memset(&invoke, , sizeof(CMINVOKECOMMANDINFOEX));
invoke.cbSize = sizeof(CMINVOKECOMMANDINFOEX);
invoke.lpVerb = (LPCSTR)(nCmdSelection - CDM_FIRST);
invoke.lpDirectory = CT2CA(szFolder);
invoke.lpVerbW = (LPCTSTR)(nCmdSelection - CDM_FIRST);
invoke.lpDirectoryW = szFolder;
invoke.fMask = CMIC_MASK_UNICODE;
// invoke.ptInvoke.x = pt->x;
// invoke.ptInvoke.y = pt->y;
invoke.nShow = SW_SHOWNORMAL; auto hr = pContext->InvokeCommand((CMINVOKECOMMANDINFO*)&invoke);
return S_OK == hr; }
catch (...)
{
return false;
}
} bool CShellContextMenu::ShowContextMenu(HWND hWnd, LPPOINT pt)
{
if (m_idls.IsEmpty())
{
ReleaseAll();
return false;
} m_pContextMenu = GetContextMenuInterfaces(m_pParentFolder, m_idls);
if (nullptr == m_pContextMenu)
{
ReleaseAll();
return false;
} auto hMenu = ::CreatePopupMenu();
auto hr = m_pContextMenu->QueryContextMenu(hMenu, , CDM_FIRST, CDM_LAST, CMF_EXPLORE | CMF_NORMAL);
if (HRESULT_SEVERITY(hr) != SEVERITY_SUCCESS)
{
ReleaseAll();
return false;
} m_pContextMenu->QueryInterface(IID_IContextMenu2, (void**)&m_pContextMenu2);
m_pContextMenu->QueryInterface(IID_IContextMenu3, (void**)&m_pContextMenu3); auto nSel = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, pt->x, pt->y, hWnd, nullptr);
if ( == nSel)
{
auto error = ::GetLastError(); CString str;
::FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
str.GetBuffer(),
, NULL); str.ReleaseBuffer();
}
DestroyMenu(hMenu); // CString strCmd;
// hr = m_pContextMenu->GetCommandString(nSel, GCS_VALIDATE | GCS_VERB | GCS_UNICODE, nullptr, (char*)strCmd.GetBuffer(1024), 1024);
// strCmd.ReleaseBuffer();
//
// CString strHelpr;
// hr = m_pContextMenu->GetCommandString(nSel,GCS_VALIDATE | GCS_HELPTEXT | GCS_UNICODE, nullptr, (char*)strHelpr.GetBuffer(1024), 1024);
// strHelpr.ReleaseBuffer();
// if (S_OK == hr)
// {
// InvokeCmd(m_pContextMenu, strCmd, m_strParentFolder);
// } if (nSel > )
{
InvokeCmd(m_pContextMenu, nSel, m_strParentFolder, pt);
} ReleaseAll();
return true;
} void CShellContextMenu::ReleaseIdls()
{
for (int i = ; i < m_idls.GetSize(); i++)
{
if (nullptr != m_idls[i])
{
CoTaskMemFree((void*)m_idls[i]);
}
} m_idls.RemoveAll();
} void CShellContextMenu::ReleaseAll()
{
ReleaseIdls(); #define _ReleaseComPtr(p) \
if (nullptr != (p)){(p)->Release(); (p) = nullptr;} _ReleaseComPtr(m_pContextMenu3);
_ReleaseComPtr(m_pContextMenu2);
_ReleaseComPtr(m_pContextMenu);
_ReleaseComPtr(m_pParentFolder);
_ReleaseComPtr(m_pDesktopFolder); #undef _ReleaseComPtr
}

call

void CTestContextMenuCppDlg::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CShellContextMenu cxMenu; CStringArray ar;
ar.Add(_T("D:\\a.txt")); ClientToScreen(&point);
cxMenu.ShowContextMenu(ar, GetSafeHwnd(), &point); CDialogEx::OnRButtonUp(nFlags, point);
}

想要实现的形式:

    CStringArray ar;
ar.Add(_T("D:\\a.txt"));
QQExt ext;
ext.发给好友(ar);// 调用右键菜单 发给好友

然后,我开始一边研究一边等待CSDN上能有人帮我解决这个问题。

更新1:

以上代码其实完全从 http://www.jackspace.cn/html/0528745226.html 抄来的,说是国外人写的,原文没找到。

更新2:

又找到这篇文章
http://bcbjournal.org/articles/vol4/0006/Using_the_shell_context_menu.htm

说系统菜单中的以下动作可以直接调用
Verb
openas
cut
copy
paste
link
delete
properties
Explore
find
COMPRESS
UNCOMPRESS

更新3:

#define CLSID_QQ_EXT "{53D2405C-48AB-4C8A-8F59-CE0610F13BBC}"

    ::CoInitialize(nullptr);

    CLSID clsid;
CLSIDFromString(_T(CLSID_QQ_EXT), &clsid); IContextMenu* pContextMenu = nullptr;
auto hr = CoCreateInstance(clsid, nullptr, CLSCTX_ALL, IID_IContextMenu, (void**)&pContextMenu);
if (S_OK != hr)
{
return false;
} HMENU hMenu = CreatePopupMenu();
hr = pContextMenu->QueryContextMenu(hMenu, , CDM_FIRST, CDM_LAST, CMF_EXPLORE);
if (HRESULT_SEVERITY(hr) != SEVERITY_SUCCESS)
{
return false;
} auto nSel = ::TrackPopupMenuEx(hMenu, TPM_RETURNCMD, pt->x, pt->y, hWnd, nullptr);

这段代码可以跑得通,并且弹出一个空菜单,所以问题就是怎么给 QQExt一个文件,或者pidl

更新4:

    m_pContextMenu = GetContextMenuInterfaces(m_pParentFolder, m_idls);
if (nullptr == m_pContextMenu)
{
ReleaseAll();
return false;
} auto pContextMenu = m_pContextMenu; auto hr = m_pContextMenu->QueryInterface(IID_IContextMenu2, (void**)&m_pContextMenu2);
if (S_OK == hr)
{
pContextMenu = m_pContextMenu2;
} hr = pContextMenu->QueryInterface(IID_IContextMenu3, (void**)&m_pContextMenu3);
if (S_OK == hr)
{
pContextMenu = m_pContextMenu3;
} auto hMenu = ::CreatePopupMenu();
hr = pContextMenu->QueryContextMenu(hMenu, , CDM_FIRST, CDM_LAST, CMF_EXPLORE | CMF_NORMAL | CMF_ASYNCVERBSTATE);
if (HRESULT_SEVERITY(hr) != SEVERITY_SUCCESS)
{
ReleaseAll();
return false;
} auto nSel = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, pt->x, pt->y, hWnd, nullptr);
if ( == nSel)
{
auto error = ::GetLastError(); CString str;
::FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
str.GetBuffer(),
, NULL); str.ReleaseBuffer();
}
DestroyMenu(hMenu); CString strCmd;
hr = m_pContextMenu->GetCommandString(nSel - CDM_FIRST, GCS_VALIDATE | GCS_VERB | GCS_UNICODE, nullptr, (char*)strCmd.GetBuffer(), );
strCmd.ReleaseBuffer(); CString strHelpr;
hr = m_pContextMenu->GetCommandString(nSel - CDM_FIRST,GCS_VALIDATE | GCS_HELPTEXT | GCS_UNICODE, nullptr, (char*)strHelpr.GetBuffer(), );
strHelpr.ReleaseBuffer();
// if (S_OK == hr)
// {
// InvokeCmd(m_pContextMenu, strCmd, m_strParentFolder);
// }
//
if (nSel > )
{
InvokeCmd(pContextMenu, nSel, m_strParentFolder, pt);
}

此至,这条路完全跑通,明天开始整理相关代码,并测试这段代码对百度网盘的适应情况。

在CSDN盯了一下午,没有任何回复,沮丧。最后还是自己解决 。

静默调用ShellContextMenu 实现QQ文件共享的更多相关文章

  1. 腾讯QQAndroid API调用实例(QQ分享无需登录)

    腾讯QQAndroid API调用实例(QQ分享无需登录)   主要分为两个步骤: 配置Androidmanifest.xml 修改activity里边代码 具体修改如下:   1.Activity代 ...

  2. 2019-5-21-C#-命令行如何静默调用-del-删除文件

    title author date CreateTime categories C# 命令行如何静默调用 del 删除文件 lindexi 2019-05-21 11:32:28 +0800 2019 ...

  3. FileZilla命令行实现文件上传以及CreateProcess实现静默调用

    应用需求:         用户在选择渲染作业时面临两种情况:一是选择用户远程存储上的文件:二是选择本地文件系统中的文件进行渲染.由于渲染任务是在远程主机上进行的,实际进行渲染时源文件也是在ftp目录 ...

  4. C#调用Mail发送QQ邮件

    需要用到: 1.System.Net.Mail; 2.QQ邮箱的POP3/SMTP服务码 QQ邮箱的POP3/SMTP服务码获取方法: 1.打开qq邮箱: 2.进入设置页面-->账户:(往下翻) ...

  5. C# 命令行如何静默调用 del 删除文件

    如果在 C# 命令行调用 del 删除文件,很多时候会提示是否需要删除,本文告诉大家如何调用命令行的时候静默删除 在C# 命令行 调用 del 删除文件的时候,会提示是否删除,通过在命令行加上 \Q ...

  6. 调用腾讯QQ启动

    http://wpa.qq.com/msgrd?v=3&uin=88888888&site=qq&menu=yes

  7. net core调用MimeKit发送QQ邮件

    一.在QQ邮箱内申请授权码,具体参考请官方文档 二.具体代码 public void TestSendMailDemo() { MimeMessage message = new MimeMessag ...

  8. html扩展调用qq聊天窗口

    需要在官方给qq开通客服功能,使用相应的html代码,别人才能通过链接调用到该qq 官方生成调用链接 over!over!over!

  9. C# 软件绑定QQ群类开源放出

    周天闲来无事写个公共类,可以添加到你们自己项目中限制必须加入你QQ群才可以使用. 代码简单,高手勿喷,有哪里不合理的请回帖让大家学习学习. using System; using System.Tex ...

随机推荐

  1. jQuery+zTree

    0 zTree简介 树形控件的使用是应用开发过程中必不可少的.zTree 是一个依靠 jQuery 实现的多功能 “树插件”.优异的性能.灵活的配置.多种功能的组合是 zTree 最大优点. 0.0 ...

  2. Mysql only_full_group_by 引起的错误

    SQLSTATE[]: Syntax error or access violation: Expression # of SELECT list is not in GROUP BY clause ...

  3. [译]C语言实现一个简易的Hash table(6)

    上一章中,我们实现了Hash表中的插入.搜索和删除接口,我们在初始化hash表时固定了大小为53,为了方便扩展,本章将介绍如何修改hash表的大小. 设置Hash表大小 现在,我们的hash表是固定大 ...

  4. STM32使用FatFs

    1.定义一些变量在我们代码开始的部分,先定义一些变量供我们使用.这里选择几个来解析一下.第一个FIL file;这个变量是文件的结构体变量,记录了我们打开的文件的信息.使用f_open等函数的时候都要 ...

  5. 【Mac】解决「无法将 chromedriver 移动到 /usr/bin 目录下」问题

    问题描述 在搭建 Selenium 库 + ChromeDriver 爬虫环境时,遇到了无法将 chromedriver 移动到 /usr/bin 目录下的问题,如下图: 一查原来是因为系统有一个 S ...

  6. 使用VS2015 编译 64位的boost库

    别人写的编译参考: 目标:使用VS2015 编译 64位的boost库. 一直以来都是在Win32环境下Build和使用boost,但现在基本上每天都在64位Win7下工作,所以很有必要把这几天的经验 ...

  7. python中Excel表操作

    python中关于excel表个的操作 使用 python中的xlwt和xlrd模块进行操作 # 2003之前:Excel:xls# 2003之后:Excel:xlsx# xlrd:读取的模块:xls ...

  8. 20155215 2016-2017-2 《Java程序设计》第6周学习总结

    20155215 2016-2017-2 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 stream:串流.抽象化输入/输出概念.将数据从来源取出,使用输入串流:将数据写入 ...

  9. 20155310 《JAVA程序设计》实验二(JAVA面向对象程序设计)实验报告

    20155310 <JAVA程序设计>实验二(JAVA面向对象程序设计)实验报告 实验内容 •初步掌握单元测试和TDD •理解并掌握面向对象三要素:封装.继承.多态 •初步掌握UML建模 ...

  10. 20145209 实验二 《Java面向对象程序设计》 实验报告

    20145209 实验二 <Java面向对象程序设计> 实验报告 实验内容 1.初步掌握单元测试和TDD. 2.理解并掌握面向对象三要素:封装.继承.多态. 3.初步掌握UML建模. 4. ...