我想在 session 之间坚持使用pidl,以便我的应用程序可以记住用户的文件夹选择,无论他们在命名空间中位于什么位置,即使它们不是文件系统文件夹也是如此。
我感觉这样做的方法是写出ITEMIDLIST
本身的二进制内容,但是我不能确定这一点,因为这些内容应该是不透明的,并且取决于提供者。我不知道重启后,甚至在另一个过程中,此数据是否有效。就我所知,它可能包含指针。
坚持并随后重建pidl的正确方法是什么?
更新:
杰里·科芬(Jerry Coffin)has suggested似乎完全符合我的要求的一对函数。但是,仍然有一个问题。
正如Joel Spolsky points out一样,Raymond Chen seems to imply保存ITEMIDLIST
的二进制内容的确是持久保存pidl的正确方法,从中可以推断出ILSaveToStream
和ILLoadFromStream
是执行此操作的辅助函数。
但是,我找不到能证明这一点的文档。由于该项目使用C#,因此我希望避免为IStream
函数互操作一个IL...
,并且在可能的情况下自己保留二进制数据。有人可以确认这是正确的吗?
解决方案说明:
查看ILSaveToStream和ILLoadFromStream的文档,我发现这些功能甚至在 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;
它仅花费几个时钟周期,但仍需要完全信任,因此,除了远离看起来像斯卡雅的指针之外,它实际上并没有买多少东西。重建pidl更加容易,因为数据的总长度是已知的,并且甚至不需要任何指针:
byte[] itemidlist = ReadPidl();
IntPtr pidl = Marshal.AllocCoTaskMem(itemidlist.Length);
Marshal.Copy(itemidlist, 0, pidl, itemidlist.Length);
以这种方式持久化和重建pidl在我的所有测试中都可以跨进程,并且在有限的场景中甚至可以跨机器进行。我还没有进行过重新启动的测试,因为我不愿意关闭所有内容并重新启动计算机,但是鉴于明显的跨计算机兼容性,我对该解决方案充满信心。我接受Joel Spolsky的回答作为解决方案,但确实想警告 future 的路人:Joel谈论写出
SHITEMID
结构,但这不是全部。 ITEMIDLIST
(即pidl指向的)实际上是这些可变长度SHITEMID
结构的以空终止的列表,并且整个列表必须保留。这就是为什么上面的代码执行循环以确定总长度的原因。它在此列表中从一个元素跳到另一个元素,读取每个元素的长度以找出到下一个元素的偏移量。只有在读取元素长度为零之后,才知道整个列表的长度。 最佳答案
根据雷蒙德·陈(Raymond Chen)的you can persist a pidl-或更具体地说,是SHITEMID结构,只需先写出项目的长度,然后写出字节。
请注意,此结构是典型的Windows可变长度结构,带有cb(“字节数”)元素,以字节为单位指定结构的长度,其后是其余数据。换句话说,要写入结构,您需要写入cb字节。要读取它,您需要分配cb内存字节并设置cb字段。
注意不要使用sizeof(SHITEMID),因为它的声明方式仅假定abID字段为一个字节,因此不够大。
关于winapi - 坚持使用pidl(ITEMIDLIST),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1774508/