ItemIDList结构(文件路径的转换)

本文介绍如何将文件路径转换为ItemIDList,以便在Windows应用程序中作为文件夹浏览窗口的根目录。通过使用SHGetDesktopFolder和ParseDisplayName等API,可以实现自定义浏览窗口的初始显示位置。

文章转载自网络


将文件路径转换至ItemIDList

通常我们会用SHBrowseForFolder接口来打开一个文件夹浏览窗口,代码一般如下:

BROWSEINFO bi = { 0 };
LPITEMIDLIST pItemIDList = SHBrowseForFolder( &bi );

这样就会打开一个浏览文件夹窗口,如下:

SHBrowseForFolder接口传入的参数为BROWSEINFO结构体指针,该结构体指针中有个ItemIDList指针成员pidlRoot,即为打开浏览文件夹窗口后显示的根目录,如果该形参为NULL,那么桌面将为根目录。

现在,我们打算将根目录置为任何我想显示的文件路径,该怎么做呢?那么我们就要将文件路径转换到对应的ItemIDList,然后赋值给pidlRoot。

首先我们要得到桌面的目录,代码如下:


LPSHELLFOLDER pDesktopFolder = NULL;
HRESULT hr = SHGetDesktopFolder( &pDesktopFolder );
if ( FAILED(hr) )
{
 return NULL;
}

然后通过调用ParseDisplayName接口就可以得到文件路径对应的ItemIDList了,由于ParseDisplayName的形参类型为LPOLESTR,所以我们需要先转化,代码如下:

OLECHAR strOleFilePath[MAX_PATH];
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, strFilePath.c_str(), -1, strOleFilePath, MAX_PATH );

然后,我们就可以调用ParseDisplayName去得到文件路径对应的ItemIDList了,代码如下:

LPITEMIDLIST pItemIDList = NULL;
hr = pDesktopFolder->ParseDisplayName( NULL, NULL, strOleFilePath, NULL, &pItemIDList, NULL );
pDesktopFolder->Release();
if ( FAILED(hr) )
{
 return NULL;
}

这样我们就得到了文件路径对应的ItemIDList,然后就可以以它为根目录显示了,代码如下:

BROWSEINFO bi = { 0 };
bi.pidlRoot = GetItemIDListFromFilePath( "F:\\NewtonSDK" ); // 返回NULL也没关系,以桌面为根

LPITEMIDLIST pItemIDList = SHBrowseForFolder( &bi );


好了,至此我们的任务就完成了,以上仅供大家参考,谢谢^-^!

附上完整代码:

LPITEMIDLIST GetItemIDListFromFilePath( const std::string &strFilePath )
{
 if ( strFilePath.empty() )
 {
  return NULL;
 }

 // 得到桌面的目录
 LPSHELLFOLDER pDesktopFolder = NULL;
 HRESULT hr = SHGetDesktopFolder( &pDesktopFolder );
 if ( FAILED(hr) )
 {
  return NULL;
 }

 // 将文件路径转换至OLECHAR格式
 OLECHAR strOleFilePath[MAX_PATH];
 MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, strFilePath.c_str(), -1, strOleFilePath, MAX_PATH );

 // 得到文件路径对应的ItemIDList
 LPITEMIDLIST pItemIDList = NULL;
 hr = pDesktopFolder->ParseDisplayName( NULL, NULL, strOleFilePath, NULL, &pItemIDList, NULL );
 pDesktopFolder->Release();
 if ( FAILED(hr) )
 {
  return NULL;
 }

 return pItemIDList;
}

调用Win32 API弹出目录选择对话框 01:30 BROWSEINFO使用 结构体配合 SHBrowseForFolder Win32 API 弹出标准的目录选择对话框。初始化BROWSEINFO结构体 02:01 创建 BROWSEINFO 结构体实例并填充成员:hwndOwner: 窗口句柄,由MFC框架自动绑定。root: 根目录,可填空表示使用默认根目录。pszDisplayName: 接收选中目录的显示名称。lpszTitle: 对话框标题,设为“选择目录”。ulFlags: 标志位,设为0表示使用默认行为。lpfn: 回调函数指针,此处不需要,设为NULL。lParam: 附加参数,无则设为0。SHBrowseForFolder(&bi) 弹出对话框,返回一个指向ITEMIDLIST的指针。调用 获取选中路径并进行有效性判断 04:37 SHGetPathFromIDList 函数将返回的ITEMIDLIST转换为实际路径字符串。使用 判断路径是否为空 05:06 使用 if (strcmp(path, "") == 0) 判断用户是否成功选择路径。若为空,则弹出消息框提示“选择成功”。否则提示“选择失败”。将选中路径显示在编辑框中 06:17 m_Dir定义控件变量 绑定到编辑框,类型为 CString。m_Dir.SetWindowText(path) 将路径写入编辑框。调用 运行验证:选择D盘目录后,路径成功显示在界面编辑框中。配置文件监控选项与启动按钮 07:07 添加一个多选框(Check Box),用于启用“文件名被改变”的监控。m_FileName添加变量 关联该复选框状态。添加“监控启动”按钮,用于触发监控线程的创建。创建独立线程执行堵塞式文件监控 08:39 因为文件监控API是堵塞函数,必须在新线程中运行以避免主界面卡死。CreateThread使用 创建新线程:参数均设为空或0。MonitorThreadProc指定线程函数名为 。__stdcall调用约定需正确设置为 。FindFirstChangeNotification 监控指定目录。线程函数中将调用 调用FindFirstChangeNotification监控文件变化 10:24 API参数设置 10:48 第一个参数:监控的目录路径,使用之前定义的全局变量 g_Path。第二个参数:是否递归监控子目录,设为 FALSE 表示仅监控指定目录。第三个参数:通知过滤条件,设为 $FILE\_NAME\_CHANGE$ 以监控文件重命名事件。hEvent调用API返回一个事件句柄 。循环等待文件变更事件 12:11 while (true)使用 死循环持续监控目录。WaitForSingleObject(hEvent, INFINITE) 等待事件触发,调用 INFINITE-1 值为 ,表示无限等待。WAIT_OBJECT_0 时表示有文件发生改变。当函数返回值为 通过自定义消息通知主对话框 13:18 为了在线程中通知主线程UI更新,需定义自定义消息:宏定义:#define WM_MYMSG (WM_USER + 1)。在线程中获取主窗口句柄,并通过 PostMessage(hWnd, WM_MYMSG, 0, 0) 发送消息。传递窗口句柄至线程函数 14:55 CreateThread在调用 时,通过第三个参数 lpParameter 传入主窗口句柄。(HWND)lpParameter 强制转换获取句柄。在线程函数内使用 处理自定义消息并更新日志显示 16:34 WM_MYMSG 消息。使用MFC类向导添加消息映射,处理 在消息处理函数中:m_Log获取日志控件变量 。判断当前日志内容是否为空:若为空,直接设置文本为“文件名改变了”。\r\n 和新记录“文件名改变了”。否则,在原有文本后追加换行符 m_Log.UpdateData(FALSE) 刷新控件显示。调用 重新激活监控以支持多次事件 16:07 每次事件触发后,需再次调用 FindNextChangeNotification(hEvent) 使事件句柄重新变为未触发状态,从而支持下一次监控。确保在循环中持续有效监听。功能测试与验证 19:51 编译运行程序,选择D盘目录并勾选“文件名改变”选项。点击“监控启动”按钮,开启后台线程。修改D盘下任意文件名,如改为“456”、“789AABASD”。观察界面日志编辑框实时显示“文件名改变了”信息,每改一次增加一行,验证功能正确实现。 写一个文件监控器代码,讲讲代码
最新发布
11-12
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值