《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)