文章收藏-FAQ 位置:电脑学习网

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

    最近写一个开发辅助工具,在这个过程要做一个类似文件快捷方式中查找目标的功能,先查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 下编译后的代码,通过 Windows98,2k,XP 的测试。

     [文章来源:“十万个为什么”电脑学习网]
     [网络地址:http://why100000.com]
     [版权声明:除本站部分特别声明禁止转载的专稿外,其他的文章可以自由转载,但请务必注明出处和原始作者。本站文章版权归文章原作者所有。如果本站转载的文章有版权问题请联系本站,我们会尽快予以更正。]
 

【字体:[大] [中] [小] 【加入收藏】 【发表评论】 【关闭本窗口】

Copyright © “十万个为什么”电脑学习网 2000-2007 陕ICP备06007929号
站务联系:MSN & Email:zhangking2008@gmail.com  QQ:9365822