首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Windows 7 Shell Library 開發實戰:建立與管理本機資料庫(上)

     編輯:關於.NET

Shell Library 概觀:重新定義使用者資料存取

Windows 7 引入了 Shell Library(Shell 程式庫) 的全新概念,徹底改變了使用者尋找與管理資料的方式。傳統版本中的「我的文件」、「圖片」、「音樂」等固有資料夾,如今統整為一個虛擬的「儲存庫」入口點。使用者不再受限於單一實體路徑,而是能將分散於多個磁碟、網路位置的資料夾納入同一個程式庫,系統自動為其建立索引,提供更快速的查詢與更豐富的中繼資料檢視。

核心優勢:使用者自主掌控資料結構

Shell Library 的設計初衷在於解決「資料散落在 PC 各處」的痛點。使用者可自行決定哪些資料夾屬於「文件庫」,哪些屬於「圖片庫」,實現邏輯上的集中管理。對開發者而言,Shell Library API 提供一致的介面,讓應用程式能共享使用者自訂的資料範圍,不再像早期 Windows Media Player 與 iTunes 各自維護不同的音樂庫那樣造成混亂。

支援網路資料夾,無縫跨裝置體驗

程式庫不僅限於本機路徑,同樣可包含網路資料夾。無論使用者在家中或辦公室,開啟檔案對話方塊時都能看到完整的程式庫視圖,大幅提升跨環境作業的連貫性。

Shell Library 架構示意圖

實驗目標:打造 SLUtil 命令列管理工具

本動手實驗將引導您開發 SLUtil,一個用於管理預設程式庫目錄的命令列工具。完成後您將掌握:

  • 建立、開啟、重命名、刪除程式庫
  • 新增/移除程式庫中的資料夾
  • 列舉與解析程式庫資料夾清單
  • 設定預設儲存資料夾、資料夾類型、圖示、導覽窗格釘選狀態
  • 呼叫「管理 UI」對話方塊

系統需求

  • Microsoft Visual Studio 2008 SP1
  • Windows 7
  • Windows 7 SDK

練習 1:建立 SLUtil 專案

  1. 開啟 Visual Studio 2008,選擇 C++ Win32 主控台應用程式,專案命名為 SLUtil,保持預設設定。
  2. 加入 CommandLineInterpreter.h 與 CommandLineInterpreter.cpp(位於 Starter 資料夾),利用 COMMAND 巨集註冊命令。
  3. 以 Starter 資料夾中的 stdafx.h 取代專案原有檔案,內含必要的 #include。
  4. 修改 targetver.h,將 _WIN32_WINNT 設為 0x0601 以支援 Windows 7 API。
  5. 在 SLUtil.cpp 的 #include "stdafx.h" 之後加入 #include "CommandLineInterpreter.h"。
  6. 修改主函式,初始化 COM 並呼叫命令列解譯器:
#include "stdafx.h"
#include "CommandLineInterpreter.h"

int _tmain(int argc, _TCHAR* argv[])
{
    // 初始化 COM
    CoInitialize(NULL);
    CCommandLineInterpreter::Execute(argc, argv);
    CoUninitialize();
    return 0;
}
  1. 編譯專案。在專案屬性 → 偵錯 → 命令引數中加入 ? 測試,執行應顯示說明訊息。
專案建立精靈 偵錯命令引數設定

練習 2:實作 Create 命令

程式化操作 Shell Library 需使用 IShellLibrary、IShellItem、IShellItem2、IShellItemArray 等介面,定義於 shobjidl.h。該標頭檔亦提供輔助函式,例如 SHCreateLibrary:

__inline HRESULT SHCreateLibrary(__in REFIID riid, __deref_out void **ppv)
{
    return CoCreateInstance(CLSID_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, riid, ppv);
}

在 SLUtil.cpp 加入建立程式庫的實作:

// 建立新的 Shell Library
void CreateLibrary(const CCommand &command, const vector<PCWSTR> &arguments)
{
    IShellLibrary *shellLibrary = NULL;
    IShellItem *savedTo = NULL;

    // 建立 Shell Library COM 物件
    HRESULT hr = SHCreateLibrary(IID_PPV_ARGS(&shellLibrary));
    if (FAILED(hr))
    {
        wcerr << L"Create: Can't create Shell Library COM object." << endl;
        exit(4);
    }

    // 儲存至使用者的 Libraries 資料夾,若同名自動加編號
    hr = shellLibrary->SaveInKnownFolder(FOLDERID_UsersLibraries, arguments[0],
        LSF_MAKEUNIQUENAME, &savedTo);
    if (FAILED(hr))
    {
        wcerr << L"Create: Can't create Shell Library." << endl;
        exit(5);
    }

    if (shellLibrary != NULL) shellLibrary->Release();
    if (savedTo != NULL) savedTo->Release();
}
COMMAND(L"Create", L"SLUtil Create LibraryName", L"Create a new library",
    L"SLUtil Create MyLib", 1, CreateLibrary);
  1. 編譯執行,命令引數改為 Create MyLib。
  2. 驗證:開啟檔案總管的「程式庫」節點,應可看到新建立的 MyLib.library-ms。
建立程式庫命令執行 檔案總管驗證結果

練習 3:實作 AddFolder 與 RemoveFolder 命令

對現有程式庫增減資料夾,需先重新開啟程式庫。為避免重複程式碼,先建立兩個輔助函式(僅處理使用者程式庫位置):

// 取得程式庫 COM 物件與完整路徑
HRESULT GetLibraryFromLibrariesFolder(PCWSTR libraryName, IShellLibrary **shellLibrary, bool openRead = true, PWSTR *libraryFullPath = NULL)
{
    wstring realLibraryName(libraryName);
    realLibraryName += L".library-ms";

    IShellItem2 *shellItem = NULL;
    HRESULT hr = SHCreateItemInKnownFolder(FOLDERID_UsersLibraries,
        KF_FLAG_DEFAULT_PATH | KF_FLAG_NO_ALIAS, realLibraryName.c_str(),
        IID_PPV_ARGS(&shellItem));
    if (FAILED(hr)) return hr;

    if (libraryFullPath != NULL)
        hr = shellItem->GetString(PKEY_ParsingPath, libraryFullPath);

    if (shellLibrary != NULL)
        hr = SHLoadLibraryFromItem(shellItem, openRead ? STGM_READ : STGM_READWRITE, IID_PPV_ARGS(shellLibrary));

    if (shellItem != NULL) shellItem->Release();
    return hr;
}

// 開啟現有程式庫
IShellLibrary *OpenLibrary(PCWSTR commandName, PCWSTR libraryName, bool openRead = true)
{
    IShellLibrary *shellLibrary = NULL;
    HRESULT hr = GetLibraryFromLibrariesFolder(libraryName, &shellLibrary, openRead);
    if (FAILED(hr))
    {
        wcerr << commandName << L": Can't load library." << endl;
        exit(4);
    }
    return shellLibrary;
}

接著實作新增/移除資料夾:

// 新增資料夾到程式庫
void AddFolder(const CCommand &command, const vector<PCWSTR> &arguments)
{
    IShellLibrary *shellLibrary = OpenLibrary(L"AddFolder", arguments[0], false);
    HRESULT hr = SHAddFolderPathToLibrary(shellLibrary, arguments[1]);
    if (FAILED(hr))
    {
        wcerr << L"AddFolder: Can't add folder to the library." << endl;
        exit(6);
    }
    shellLibrary->Commit(); // 送交變更
    if (shellLibrary != NULL) shellLibrary->Release();
}
COMMAND(L"AddFolder", L"SLUtil AddFolder LibraryName FolderPath",
    L"Add a folder to a library", L"SLUtil AddFolder Documents C:\\Docs", 2, AddFolder);

// 從程式庫移除資料夾
void RemoveFolder(const CCommand &command, const vector<PCWSTR> &arguments)
{
    IShellLibrary *shellLibrary = OpenLibrary(L"RemoveFolder", arguments[0], false);
    HRESULT hr = SHRemoveFolderPathFromLibrary(shellLibrary, arguments[1]);
    if (FAILED(hr))
    {
        wcerr << L"RemoveFolder: Can't remove folder from the library." << endl;
        exit(5);
    }
    shellLibrary->Commit();
    if (shellLibrary != NULL) shellLibrary->Release();
}
COMMAND(L"RemoveFolder", L"SLUtil RemoveFolder LibraryName FolderPath",
    L"Remove a folder from a library", L"SLUtil RemoveFolder Documents C:\\Docs", 2, RemoveFolder);

編譯執行後,即可使用 SLUtil AddFolder MyLib C:\Data 等指令動態管理程式庫內容。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved