《Windows核心编程》---Windows Shell目录管理

Windows shell最重要的组成部件是explorer.exe,在使用Windows操作系统时,开始菜单、任务栏、资源管理器等都是explorer.exe提供的。

Windows shell编程接口的函数名一般是以SH开头的。一般Shell API都在shlobj.h头文件中声明,由Shell32.dll导出,链接时需要使用到Shell32.lib库。

Shell最重要的功能之一是进行文件浏览、查找、管理以及将文件和应用程序关联。Windows Shell中有很多特殊目录和文件,比如“我的文档”、“桌面”、“回收站”、“程序文件”(Program files)等。这些目录都是shell的特殊目录。

 

Shell对目录和文件的管理形式:

Shell有一种特殊的文件和目录管理方式,每个目录都有一个PIDLPointer of Item identifier list,项标识符表指针)值,这个值唯一标识一个文件夹。

有系统定义的特殊文件夹的CSIDLconstant special item ID list)是常数,如:

CSIDL_DESKTOP   //"桌面"文件夹

CSIDL_FAVORITES         //"收藏夹"

CSIDL_FONTS                 //字体文件夹

CSIDL_MYDOCUMENTS      //"我的文档"

CSIDL_MYMUSIC  //"我的音乐"

CSIDL_PROFILE     //"用户文件夹",一般是"C:/Document and Settings/username"

CSIDL_PROGRAMS       //"程序"文件夹,一般是"C:/Program Files"

CSIDL_RECENT      //"最近的文档"

CSIDL_STARTMENU     //"开始菜单"目录

CSIDL_SYSTEM                //"系统"目录

CSIDL_WINDOWS         //"Windows"目录

 

特殊目录的操作:

SHGetSpecialFolderPath函数用于通过文件夹的CSIDL来获得文件夹的路径:

BOOL SHGetSpecialFolderPath(

         HWND hwndOwner, //保留值

  __out  LPTSTR lpszPath,          //指向用于存放返回的文件夹路径的字符串缓冲区,

//大小至少为MAX_PATH个字符

  __in   int csidl,         //指定的CSIDL

  __in   BOOL fCreate //指定如果目标文件夹不存在是否创建一个新的

);

 

SHGetFolderLocation函数用于获取文件夹的路径,并保存在ITEMIDLIST结构中:

HRESULT SHGetFolderLocation(

  __in        HWND hwndOwner, //保留

  __in        int nFolder, //指定的CSIDL

  __in        HANDLE hToken, //代表一个特定用户的访问令牌,一般设为NULL

  __reserved  DWORD dwReserved, //保留

  __out       PIDLIST_ABSOLUTE *ppidl //IDL指针的地址(即PIDL的地址)该IDL指定相对于命名空间

                                     //根目录(桌面)的一个文件或目录的位置

//函数失败时该值设为NULL

//调用的程序应该使用ILFree函数来释放该资源

);

返回值:

成功时,返回S_OK

失败时,返回ERROR_FILE_NOT_FOUNDCSIDL值有效,但找不到目录);E_INVALIDARGCSIDL值无效)。

 

SHGetPathFromIDList函数用于将PIDL转换成路径:

BOOL SHGetPathFromIDList(

  __in   PCIDLIST_ABSOLUTE pidl, //IDL的地址,该IDL指定相对于命名空间根目录(桌面)

//一个文件或目录的位置

  __out  LPTSTR pszPath //用于接收文件系统路径的缓冲区地址,大小至少为MAX_PATH个字符

);

 

实例代码如下:

#include <windows.h>

#include <shlobj.h>

#include <stdio.h> //printf函数(包含在_tprintf中)

#include <tchar.h> //_tprintf函数

 

#pragma comment(lib, "Shell32.lib") //可有可无

 

int main()

{

    //获得"我的文档"的路径

    TCHAR szMyDocument[MAX_PATH];

    //获取特殊目录

    SHGetSpecialFolderPath(NULL, szMyDocument, CSIDL_PERSONAL, FALSE);

    //获取桌面的路径

    TCHAR szDesktop[MAX_PATH];

    LPITEMIDLIST pidl = NULL;

    LPMALLOC pMalloc = NULL;

    //分配

    SHGetMalloc(&pMalloc);

    //获取任意目录的路径

    SHGetFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, &pidl);

    SHGetPathFromIDList(pidl, szDesktop);

    //释放

    pMalloc->Free(pidl);

    pMalloc->Release();

    //显示结果

    _tprintf("My Document:/t%s/n", szMyDocument);

    _tprintf("Desktop:/t%s/n", szDesktop);

   

    system("pause");

    return 0;

}

 

上面代码使用两种方法来获得特殊文件夹路径,一种是直接使用SHGetSpecialFolderPath;另一种更为通用,使用SHGetFolderLocationPIDLCSIDL获得文件夹位置后,再使用SHGetPathFromIDList获得文件路径字符串。

 

绑定、遍历、属性获取:

通过Shell API可以编写更为一般的文件操作,如:

1)将IShellFolder接口绑定到目录对象上,以获取目录、子目录等相关信息;

2)获取IEnumIDList接口,用于遍历目录中包含的对象;

3)获取和显示文件和目录对象的相关属性。

 

SHGetDesktopFolder函数用于获取以IShellFolder接口形式返回的桌面文件夹:

HRESULT SHGetDesktopFolder(

  __out  IShellFolder **ppshf //ppshf指向返回的IShellFolder指针

);

返回值:

成功时,返回S_OK

失败时,返回HRESULT错误码。

 

IShellFolderWindows shell程序对目标进行管理的一个重要的接口。每一个目录对应一个实例化的IShellFolder接口。IShellFolder接口的成员包括EnumObjectsGetAttributesOfGetDisplayNameOf等。

 

IEnumIDList接口提供了一组标准方法,用于遍历PIDL,其成员包括CloneNextResetSkip等。

 

STRRET结构是很多IShellFolder接口成员返回的字符串形式:

typedef struct _STRRET {

  UINT uType; //指定返回的字符串的格式:

//STRRET_CSTR---cStr数组形式;

                   //STRRET_OFFSET---uOffset形式;

                   //STRRET_WSTR---pOleStr形式

  union {

    LPWSTR pOleStr; //存放返回的字符串的地址

    UINT   uOffset; //IDL开始的uOffset个字节处就是返回的字符串的位置

    CHAR   cStr[MAX_PATH]; //存放返回字符串的缓冲区

  } ;

} STRRET, *LPSTRRET;

 

代码实例,列举“回收站”中的文件和目录:

#include <windows.h>

#include <shlobj.h>

#include <stdio.h>

#include <tchar.h>

 

//#pragma comment(lib, "Shell32.lib")

 

int main()

{

         TCHAR pszPath[MAX_PATH];

         //IShellFolder接口

         IShellFolder *pisf = NULL;

         IShellFolder *pisfRecBin = NULL;

         //获得Shell命名空间根目录,即桌面

         SHGetDesktopFolder(&pisfRecBin);

         IEnumIDList *peidl = NULL;        //对象遍历接口

         LPITEMIDLIST pidlBin = NULL;

         LPITEMIDLIST idlCurrent = NULL;

        

         LPMALLOC pMalloc = NULL;

         //分配

         SHGetMalloc(&pMalloc);

         //回收站位置

         SHGetFolderLocation(NULL, CSIDL_BITBUCKET, NULL, 0, &pidlBin);

         //绑定回收站对象

         pisfRecBin->BindToObject(pidlBin, NULL, IID_IShellFolder, (void**)&pisf);

         //列举回收站对象,得到IEnumIDList接口,包括SHCONTF_FOLDERS

         //SHCONTF_NONFOLDERS、¡SHCONTF_INCLUDEHIDDEN类型对象

         pisf->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS |

                   SHCONTF_INCLUDEHIDDEN, &peidl);

 

         STRRET strret;

         ULONG uFetched;

         HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

         _tprintf("/nFiles In Recycle Bin:/n");

         while(1)

         {

                   //遍历IEnumIDList对象,idlCurrent为当前对象

                   if (peidl->Next(1, &idlCurrent, &uFetched) == S_FALSE)

                   {

                            break;

                   }

                   //获取回收站当前对象当前的路径

                   SHGetPathFromIDList(idlCurrent, pszPath);

                   //DisplayName,删除前的路径

                   pisf->GetDisplayNameOf(idlCurrent, SHGDN_NORMAL, &strret);

                   //显示,_tprintf可能会造成字符串编码不正确

                   //wprintf(L"/t%s/n", strret.pOleStr);---->wprint显示不了中文

                 WriteConsoleW(hOutput, L"/t", 1, NULL, NULL);

                 WriteConsoleW(hOutput, strret.pOleStr, lstrlenW(strret.pOleStr), NULL, NULL);

                 WriteConsoleW(hOutput, L"/n", 1, NULL, NULL);

         }

 

         //释放资源

         pMalloc->Free(pidlBin);

         pMalloc->Free(strret.pOleStr);

         pMalloc->Release();

         peidl->Release();

         pisf->Release();

    

    system("pause");

    return 0;

}

在显示结果时,由于STRRET strret保存的是UNICODE编码的字符串,在使用输出函数进行结果输出时,需要注意字符编码。

 

浏览文件夹对话框:

代码如下:

#include <windows.h>

#include <shlobj.h>

/************************************************************************/

/* 功能:弹出"浏览文件夹"对话框,并获取用户选择的文件夹目录             */

/* 参数:hwnd--父窗口句柄                                                                   */

/************************************************************************/

DWORD Browse(HWND hwnd)

{

         //用于保存路径

         TCHAR szRoot[MAX_PATH];

         TCHAR szChoose[MAX_PATH];

         TCHAR szDisplayName[MAX_PATH];

         //相关变量

         LPITEMIDLIST pidlRoot = NULL;

         LPITEMIDLIST pidlSelected = NULL;

         BROWSEINFO bi = {0};

         LPMALLOC pMalloc = NULL;

         //"浏览文件夹"的根路径,开发人员可根据情况选择,比如只浏览"我的文档"

         SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 0, &pidlRoot);

         SHGetPathFromIDList(pidlRoot, szRoot);

 

         //填充BROWSEINFO结构

         bi.hwndOwner = hwnd;

         bi.pidlRoot = pidlRoot;

         bi.pszDisplayName = szDisplayName;

         bi.lpszTitle = "Choose a target";

         bi.ulFlags = 0;

         bi.lpfn = NULL;

         bi.lParam = 0;

 

         //弹出对话框

         pidlSelected = SHBrowseForFolder(&bi);

         //DisplayName

         MessageBox(NULL, szDisplayName, "Display Name:", MB_OK);

         //选择的文件夹

         SHGetPathFromIDList(pidlSelected, szChoose);

         MessageBox(NULL, szChoose, "Choose:", MB_OK);

         //释放

         ILFree(pidlRoot);

         return 0;

}

 

 

/************************************************************************/

/* 程序入口函数                                                        */

/************************************************************************/

int WINAPI WinMain(HINSTANCE hInstance,

                            HINSTANCE hPrevInstance,

                            LPSTR lpCmdLine,

                            int nShowCmd )

{

         return Browse(NULL);

}

你可能感兴趣的:(《Windows核心编程》---Windows Shell目录管理)