新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → 实现快捷方式中的查找目标功能 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 3528 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 实现快捷方式中的查找目标功能 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 实现快捷方式中的查找目标功能


      最近写一个开发辅助工具,在这个过程要做一个类似文件快捷方式中查找目标的功能,先查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();
    }


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/2/7 9:03:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/11/23 0:28:55

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    62.012ms