AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VC编程

用VC6.0实现快捷方式中的查找目标功能

51自学网 2015-08-30 http://www.wanshiok.com
  最近写一个开发辅助工具,在这个过程要做一个类似文件快捷方式中查找目标的功能,先查MSDN98,大家不要见笑,我现在一直都用它,没有相应的API,后又. Net 2003中的MSDN,找到了可以实现该功能的API,SHOpenFolderAndSelectItems()函数,它的原型如下:

  (具体用法参考MSDN)“Opens a Microsoft® Windows® Explorer window with specified items in a particular folder selected.”
HRESULT SHOpenFolderAndSelectItems(    LPCITEMIDLIST pidlFolder,    UINT cidl,    LPCITEMIDLIST *apidl,    DWORD dwFlags);

  但是,它需要Windows XP及上,若在Win2000或Win98如何实现它呢?于是我就上网搜索,几经周折最终搜到的一篇文章,但它只是利用工具通过反汇编Windows API函数得到的代码,可能可以实现与快捷方式相同的对话框(我没有试过),但其代码可读性非常差,我只能参考一下大概的流程,他提到一个非常重要的一点,那就是使用一个未公开的API函数SHGetIDispatchForFolder,它可帮助我打开文件夹。好不多说了,下面是关键的部分:

  查找目标功能,分为两个步骤,首先打开或找到目标文件所在的文件夹,其次在打开的文件夹中选中相应的项目(即文件)。在说这个步骤之前,先认识一下,下面两个结构

typedef struct _SHITEMID {     USHORT cb;     BYTE   abID[1]; } SHITEMID, * LPSHITEMID; typedef const SHITEMID  * LPCSHITEMID; typedef struct _ITEMIDLIST {    SHITEMID mkid;} ITEMIDLIST, * LPITEMIDLIST; typedef const ITEMIDLIST * LPCITEMIDLIST; 

  这两个结构的数据保存的是项目定义符列表(仅是字面翻译),这个结构所表示的文件夹及文件除了正常的,还包括一些特殊的文件夹及文件(如目录,我的电脑等),SHGetIDispatchForFolder函数正是用它的做为参数,可以打开一些特殊的文件夹。SHGetIDispatchForFolder函数的原型是 :
      HRESULT (WINAPI*gpfSHGetIDispatchForFolder)(ITEMIDLIST* pidl, IWebBrowserApp** ppIWebBrowserApp); 
  通常快捷方式给我的ITEMIDLIST是包含文件名的,若直接调用上面的函数,它将直接会打开出目标文件,而不是打开文件夹。下面是区分文件及文件夹的代码:
 pIdlFile = pidl;       /// 找出目标文件中文件名的偏移量 while (cb = pIdlFile->mkid.cb)  {  pidl2 = pIdlFile;  pIdlFile = (ITEMIDLIST*)((BYTE*)pIdlFile + cb); } cb = pidl2->mkid.cb; pidl2->mkid.cb = 0;

  下面是打开文件夹及选中文件的代码,相信大家不难理解。



/// 打开目标文件所在的文件夹 if (SUCCEEDED(GetShellFolderViewDual(pidl, &pIShellFolderViewDual)))  { pidl2->mkid.cb = cb; // 0 Deselect the item.  // 1 Select the item.  // 3 Put the item in edit mode.  // 4 Deselect all but the specified item.  // 8 Ensure the item is displayed in the view.  // 0x10 Give the item the focus.  COleVariant bszFile(pidl2); if(pIShellFolderViewDual != NULL) { /// 选中相应的选项 pIShellFolderViewDual->SelectItem(bszFile, 0x1d); pIShellFolderViewDual->Release(); } return TRUE; }
  源代码中包含了一个DEMO。下面是完整的函数,可以直接调用FindTarget(CString str)参数为文件名,若是快捷方式则会自动指向其目标。若代码中已做过COM的初始化工作,请删除CoInitialize(NULL);及CoUninitialize();语句。
HRESULT GetShellFolderViewDual(ITEMIDLIST* pidl, IShellFolderViewDual** ppIShellFolderViewDual){ IWebBrowserApp* pIWebBrowserApp; IDispatch* pDoc; HWND hWnd; HRESULT hr; HINSTANCE ghSHDOCVW; HRESULT (WINAPI*gpfSHGetIDispatchForFolder)(ITEMIDLIST* pidl, IWebBrowserApp** ppIWebBrowserApp); *ppIShellFolderViewDual = NULL; ghSHDOCVW = LoadLibrary(_T("SHDOCVW.DLL")); if (ghSHDOCVW == NULL)  return FALSE; pIWebBrowserApp=NULL; gpfSHGetIDispatchForFolder =   (HRESULT (WINAPI*)(ITEMIDLIST*, IWebBrowserApp**)) GetProcAddress(ghSHDOCVW, "SHGetIDispatchForFolder"); if (gpfSHGetIDispatchForFolder == NULL)  return FALSE; /// 调用未公开的API函数 SHGetIDispatchForFolder if (SUCCEEDED(gpfSHGetIDispatchForFolder(pidl, &pIWebBrowserApp)))  {  if (SUCCEEDED(pIWebBrowserApp->get_HWND((long*)&hWnd)))   {   SetForegroundWindow(hWnd);   ShowWindow(hWnd, SW_SHOWNORMAL);  }  if (SUCCEEDED(hr = pIWebBrowserApp->get_Document(&pDoc)))  {   pDoc->QueryInterface(IID_IShellFolderViewDual, (void**) ppIShellFolderViewDual);   pDoc->Release();  }  pIWebBrowserApp->Release(); } FreeLibrary(ghSHDOCVW); return TRUE;}BOOL XZSHOpenFolderAndSelectItems(ITEMIDLIST *pidlFolder){ ITEMIDLIST *pidl, *pidl2; ITEMIDLIST* pIdlFile; USHORT cb; IShellFolderViewDual* pIShellFolderViewDual; HRESULT (WINAPI *gpfSHOpenFolderAndSelectItems)
(LPCITEMIDLIST *pidlFolder, UINT cidl, LPCITEMIDLIST *apidl, DWORD dwFlags); HINSTANCE ghShell32;/// 只有WinXp及以上及系统才支持SHOpenFolderAndSelectItems() API/// 那其它系统该怎么实现这个功能呢?只能采用其它的方法来处理/// 首先用XP跟踪到SHOpenFolderAndSelectItems()API中,看它是如何处理的,再用同样的方法去实现/// 其它系统的这个功能使用工具 VC6 .net 2003 MSDN Ollydbg v1.10中文版 ghShell32 = LoadLibrary(_T("Shell32.DLL")); if (ghShell32 == NULL) return FALSE; gpfSHOpenFolderAndSelectItems =          (HRESULT (WINAPI*)(LPCITEMIDLIST*, UINT, LPCITEMIDLIST*, DWORD))
GetProcAddress(ghShell32, "SHOpenFolderAndSelectItems"); if (gpfSHOpenFolderAndSelectItems != NULL) { /// 可以获得SHOpenFolderAndSelectItems()函数的API地址 if (SUCCEEDED(gpfSHOpenFolderAndSelectItems((LPCITEMIDLIST*)pidlFolder,0,(LPCITEMIDLIST*)NULL,0))) { ///直接调用系统的功能 FreeLibrary(ghShell32); return TRUE; } FreeLibrary(ghShell32); return FALSE; } FreeLibrary(ghShell32); /// 当操作系统不支持SHOpenFolderAndSelectItems()函数的API时的处理, /// 自已动手写一个与系统功能相同的代码 pidl = pidlFolder; pIdlFile = pidl; /// 找出目标文件中文件名的偏移量 while (cb = pIdlFile->mkid.cb) { pidl2 = pIdlFile; pIdlFile = (ITEMIDLIST*)((BYTE*)pIdlFile + cb); } cb = pidl2->mkid.cb; pidl2->mkid.cb = 0; /// 打开目标文件所在的文件夹 if (SUCCEEDED(GetShellFolderViewDual(pidl, &pIShellFolderViewDual))) { pidl2->mkid.cb = cb; // 0 Deselect the item. // 1 Select the item. // 3 Put the item in edit mode. // 4 Deselect all but the specified item. // 8 Ensure the item is displayed in the view. // 0x10 Give the item the focus. COleVariant bszFile(pidl2); if(pIShellFolderViewDual != NULL) { /// 选中相应的选项 pIShellFolderViewDual->SelectItem(bszFile, 0x1d); pIShellFolderViewDual->Release(); } return TRUE; } return FALSE;}void FindTarget(CString str){ HRESULT hres; IShellLink *psl; ITEMIDLIST *pidl; IPersistFile *ppf; CoInitialize(NULL); // Get a pointer to the IShellLink interface. hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); if (SUCCEEDED(hres)) { // 设置目标文件 psl->SetPath(str); /// 获得目标文件的ITEMIDLIST psl->GetIDList(&pidl); // Get a pointer to the IPersistFile interface. hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); if (SUCCEEDED(hres)) { WCHAR wsz[MAX_PATH]; #ifdef _UNICODE wcscpy(wsz, str);#else // Ensure that the string is Unicode. MultiByteToWideChar(CP_ACP, 0, str, -1, wsz, MAX_PATH); #endif // Load the shortcut. hres = ppf->Load(wsz, STGM_READ); if (SUCCEEDED(hres)) { /// 获得快捷方式的ITEMIDLIST psl->GetIDList(&pidl); }m ppf->Release(); } /// 打开文件夹并选中项目 XZSHOpenFolderAndSelectItems(pidl); psl->Release(); } CoUninitialize();}

  在VC6下编译后的代码,通过98,2k,XP的测试。

 

 

 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
上一篇:摆脱DLL"地狱"的困扰之获取进程信息  下一篇:在VC++中实现自动连续播放多媒体文件