gpt4 book ai didi

winapi - 保留 pidl (ITEMIDLIST)

转载 作者:行者123 更新时间:2023-12-02 08:33:19 24 4
gpt4 key购买 nike

我想在 session 之间保留 pidls ,以便我的应用程序可以记住用户的文件夹选择,无论它们位于命名空间中的任何位置,即使它们不是文件系统文件夹。

我有一种感觉,执行此操作的方法是写出 ITEMIDLIST 本身的二进制内容,但我无法确定这一点,因为这些内容应该是不透明的,并由提供商决定。我不知道重新启动后,甚至在另一个进程中,该数据是否有效。据我所知,它可能包含指针。

保存并稍后重建 pidl 的正确方法是什么?

更新:

Jerry Coffin has suggested 一对函数似乎完全符合我的要求。然而,还有一个问题。

正如 Joel Spolsky points out 和 Raymond Chen seems to imply 所说,保存 ITEMIDLIST 的二进制内容确实是持久保存 pidl 的正确方法,从中可以推断 ILSaveToStreamILLoadFromStream 是执行此操作的辅助函数。

但是,我找不到证明这一点的文档。由于这个项目是用 C# 语言编写的,因此我希望避免为 IL... 函数互操作 IStream,并且如果可能的话,我自己保留二进制数据。有人能确认这是正确的吗?

解决方案说明:

查看 ILSaveToStreamILLoadFromStream 的文档,我发现这些函数直到 shell 5.0 版本(Windows 2000)才存在。那么在 Win2K 之前这是如何实现的呢?经过一些测试后,我得出的结论是,正如我所怀疑的和 Joel Spolsky 所假设的那样,写出原始 ITEMIDLIST 是正确的方法。

C# 中的简单实现如下:

unsafe{
byte* start = (byte*)pidl.ToPointer();
byte* ptr = start;
ushort* length;

do{
length = (ushort*)ptr;
ptr += *length;
}while(*length != 0);

byte[] rtn = new byte[ptr + 2 - start];
Marshal.Copy(pidl, rtn, 0, rtn.Length);
return rtn;
}

当然,这可以在没有指针的情况下使用Marshal.ReadInt16来完成:

int offset = 0;
int length;

do{
length = Marshal.ReadInt16(pidl, offset);
offset += length;
}while(length != 0);

byte[] rtn = new byte[offset + 2];
Marshal.Copy(pidl, rtn, 0, rtn.Length);
return rtn;

它只花费了几个时钟周期,但它仍然需要完全信任,因此除了远离看起来像“scaaaary”的指针之外,它并没有真正带来什么好处。

重建 pidl 甚至更容易,因为数据的总长度已经知道,甚至不需要任何指针:

byte[] itemidlist = ReadPidl();
IntPtr pidl = Marshal.AllocCoTaskMem(itemidlist.Length);
Marshal.Copy(itemidlist, 0, pidl, itemidlist.Length);

以这种方式保留和重建 pidls 在我的所有跨进程测试中都有效,在有限的情况下,甚至跨机器。我还没有测试过重新启动,因为我不愿意关闭所有内容并重新启动我的机器,但考虑到明显的跨机器兼容性,我对这个解决方案充满信心。

我接受 Joel Spolsky 的答案作为解决方案,但确实想向 future 的路人提出警告:Joel 谈到写出一个 SHITEMID 结构,但这并不是故事的全部。 ITEMIDLIST(这是 pidl 所指向的)实际上是这些可变长度 SHITEMID 结构的空终止列表,并且必须保留整个列表。这就是上面的代码执行循环来确定总长度的原因。它在此列表中从一个元素跳转到另一个元素,读取每个元素的长度以找出到下一个元素的偏移量。只有读取到长度为零的元素后,才能知道整个列表的长度。

最佳答案

根据雷蒙德陈 you can persist a pidl -- 或者,更具体地说,一个 SHITEMID结构,只需写出项目的长度,然后写出字节。

请注意,此结构是典型的 Windows 可变长度结构,其中有一个 cb(“字节数”)元素指定该结构的长度(以字节为单位),后跟其余数据。也就是说,要写结构体,就需要写cb字节。要读取它,您需要分配cb字节的内存并设置cb字段。

请注意不要使用 sizeof(SHITEMID),因为它的声明方式假定 abID 字段只有一个字节,因此不够大。

关于winapi - 保留 pidl (ITEMIDLIST),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1774508/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com