代码之家  ›  专栏  ›  技术社区  ›  P Daddy

保留pidl(itemidlist)

  •  6
  • P Daddy  · 技术社区  · 16 年前

    我想坚持下去 pidl 在会话之间,这样我的应用程序就可以记住用户在命名空间中的文件夹选择,即使它们不是文件系统文件夹。

    我觉得这样做的方法是写出 ITEMIDLIST 但我不能肯定这一点,因为这些内容应该是不透明的,由提供者决定。我不知道在重启之后,甚至在另一个进程中,这些数据是否有效。据我所知,它可以包含指针。

    什么是保持和稍后重建PIDL的正确方法?

    更新:

    杰里棺材 has suggested 一对函数,似乎完全按照我的要求执行。然而,还有一个问题。

    作为Joel Spolsky points out Raymond Chen seems to imply 保存的二进制内容 项目清单 确实是坚持PIDL的正确方法,从中可以推断 ILSaveToStream 和 ILLoadFromStream 就是这样做的助手函数。

    但是,我找不到证明这一点的文档。由于这个项目是在C中的,所以我希望避免必须互操作 IStream 对于 IL... 函数,并在可能的情况下自己保存二进制数据。有人能确认这是正确的吗?

    解决方案说明:

    查看文档 ILSaveToStream 和 ILLoadFromStream ,我看到这些函数直到5.0版的shell(Windows2000)才存在。那么在win2k之前这是怎么做到的呢?经过一些测试,我得出结论,正如我怀疑的和乔尔·斯波斯基假设的那样,写出原始的 项目清单 是前进的道路。

    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在我的所有测试中都可以跨流程工作,在有限的场景中甚至跨流程工作。 机器 .我还没有在重新启动时进行测试,因为我不愿意关闭所有东西并重新启动我的机器,但是考虑到明显的跨机器兼容性,我对这个解决方案充满信心。

    我接受乔尔·斯波斯基的回答作为解决方案,但我确实想提醒未来的路人:乔尔说要写一个 SHITEMID 结构,但这不是全部。安 项目清单 (这就是pidl指向的)实际上是这些变量长度的以空结尾的列表 希特米德 结构和整个列表必须持久化。这就是上面的代码执行循环以确定总长度的原因。它在这个列表中从一个元素跳到另一个元素,读取每个元素的长度以找出到下一个元素的偏移量。只有在读取元素长度为零之后,才知道整个列表的长度。

    3 回复  |  直到 8 年前
        1
  •  4
  •   sven    16 年前

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

    注意,这个结构是一个典型的Windows可变长度结构,它有一个cb(“count of bytes”)元素,指定结构的长度(以字节为单位),后跟其余的数据。换句话说,要编写结构,需要编写cb字节。要读取它,需要分配内存的cb字节并设置cb字段。

    注意不要使用sizeof(shitemid),因为声明它的方式只假设abid字段有一个字节,这样就不够大了。

        2
  •  1
  •   Jerry Coffin    16 年前

    ilsavetostream和illoadfromstream(可能还有illoadfromstreamex)。但是有一个警告:illoadFromStream和illoadFromStreamEx是不赞成使用的,如果微软已经说过要替换它们的话,我不知道。

        3
  •  1
  •   Sheng Jiang 蒋晟    8 年前

    PIDLS内部没有标准。毕竟,pidl只用于定位项目。只要pidl生成器和解析器(Windows资源管理器或第三方shell命名空间扩展)识别出pidl(或可预见地失败),explorer.exe就会高兴。没有人说PIDL必须能够在机器重新启动或用户桌面上持久。

    在一种情况下,您可以做一个有根据的猜测,如果pidl是持久的跨机器重启是检查sfgao_canlink属性。通过声明此属性,pidl解析器声明您可以拖动文件夹中的项目以创建包含项目pidl的桌面快捷方式。解析程序必须在pidl中处理持久性和向后兼容性,否则双击快捷方式将使资源管理器进程崩溃。有缺陷的编程发生了,所以不要想当然地认为这是理所当然的。

    在过去黑暗的日子里,pidl被保存在字节数组中,或者当需要通过COM对象时,作为安全的字节数组以变量形式传递。