程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 如何實現快捷方式中的查找目標功能

如何實現快捷方式中的查找目標功能

編輯:關於VC++

最近寫一個開發輔助工具,在這個過程要做一個類似文件快捷方式中查找目 標的功能,先查MSDN98,大家不要見笑,我現在一直都用它,沒有相應的API, 後又. Net 2003中的MSDN,找到了可以實現該功能的API, SHOpenFolderAndSelectItems()函數,它的原型如下:

(具體用法參考 MSDN)“Opens a Microsoft® Windows® Explorer window with specified items in a particular folder selected.”

HRESULTSHOpenFolderAndSelectItems(
   LPCITEMIDLISTpidlFolder,
  UINTcidl,
   LPCITEMIDLIST*apidl,
  DWORDdwFlags
);

但是,它需 要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的測試。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved