发布网友 发布时间:2024-10-22 07:45
共1个回答
热心网友 时间:2024-11-02 07:02
有时,我们可能需要将PIDL(进程标识符列表)分解为单独的ID列表,但通常没有公开的函数直接提供这项功能。微软鼓励开发者自己实现这个功能。幸运的是,还有未公开的函数能够简化这一过程。要确定PIDL中所有标识符的尺寸,可以使用`ILGetSize`函数。若想遍历PIDL中的每一个项目标识符,`ILGetNext`函数可以实现这一目标,它会返回指向列表中下一个项目标识符的指针。如果PIDL为空或已指向列表的最后项,函数会返回空值。要返回列表中最后项的项目标识符,可以使用未公开的`ILFindLastID`函数。
对于更专业的查找操作,可以使用`ILFindChild`函数,它接受一个父PIDL和一个子PIDL作为参数,返回指向子PIDL独特部分的指针。例如,如果父PIDL是目录 'C:\DIR' 的PIDL,而子PIDL是”C:\DIR\FILE.TXT“的PIDL,它将返回指向代表FILE.TXT的子PIDL的指针。如果给定的子PIDL不是父PIDL的子对象,函数将返回空值。这些函数的索引值分别为152、153、16和24。
复制和合并PIDL的功能可以通过`ILClone`和`ILCloneFirst`函数实现。给定一个已有的PIDL,`ILClone`函数可以分配并返回一个新的PIDL的克隆。而`ILCloneFirst`可以从源PIDL中生成仅包含第一个项目标识符的PIDL。若要获取最后一个项目标识符的拷贝,可以组合使用`ILFindLastID`和`ILCloneFirst`函数调用。对于PIDL的其他部分,需要不断调用`ILGetNext`和`ILCloneFirst`函数。
合并两个PIDL的操作可以通过`ILCombine`函数完成,它接受两个PIDL作为参数,创建包含两个源列表的新PIDL。如果需要将一个单独的项目标识符与PIDL合并,可以使用`ILAppendID`函数。它允许将一个`TItemID`记录添加到一个已有的PIDL的开头或结尾。然而,与`ILCombine`不同,原始的PIDL在操作后会被销毁。`ILAppendID`函数中的PIDL参数甚至可以为`nil`。
在Windows NT中,为PIDL分配内存需要使用外壳内存分配器。系统中有两个未公开的函数提供了不同的内存分配和释放方法,分别是`ILGlobalClone`和`ILGlobalFree`函数(索引值分别为20和156)。这些函数使用缺省进程的堆(由`GetProcessHeap`获取),堆的分配在某些方面比外壳分配器更高效,而外壳在内部使用全局分配函数可以提高效率。
为了删除整个PIDL,只需使用`ILFree`函数即可。如果要从列表的末尾删除最后一个项目标识符,可以使用`ILRemoveLastID`函数。值得注意的是,它并不真正释放内存,只是重置了列表的最后位置。这是唯一一个删除相关操作的函数。若想从PIDL的开始删除一个项目标识符,只能使用`ILGetNext`和`ILClone`来生成一个从原始PIDL的第二个ID开始的拷贝,然后使用`ILFree`删除源PIDL。
深入命名空间的遍历可以通过桌面作为根节点开始。获得桌面对象的`IShellFolder`接口是实现这一操作的关键步骤。下面的代码演示了如何获取桌面接口:
p
var
Desktop: IShellFolder;
Begin
OleCheck(SHGetDesktopFolder(Desktop));
...
`IShellFolder`接口可以用来枚举外壳中的内容、设置或获取外壳对象的名称、查询它们的属性并通过界面元素进行交互。下面是一个使用`IShellFolder`接口的示例:
p
type
TItemListArray = array of PItemIDList;
...
function GetShellItems(Folder: IShellFolder): TItemListArray;
Const
SHCONTF_ALL = SHCONTF_FOLDERSorSHCONTF_NONFOLDERSor
SHCONTF_INCLUDEHIDDEN;
Var
EnumList: IEnumIDList;
NewItem: PItemIDList;
Dummy: Cardinal;
I: Integer;
Begin
Result := nil;
I := 0;
if Folder.EnumObjects(0, SHCONTF_ALL, EnumList) = S_OK then
while EnumList.Next(1, NewItem, Dummy) = S_OK do
begin
Inc(I);
SetLength(Result, I);
Result[I - 1] := NewItem;
end;
end;
要获取相对PIDL的字符串表达,可以使用`GetShellObjectName`函数。通过将这些代码集成起来,可以编写一个过程来输出指定深度的外壳命名空间的层次关系:
p
procere EnumShellNamespace(Strings: TStrings; Depth: Integer; Folder: IShellFolder = nil);
procere AddObjectName(Folder: IShellFolder; ItemList: PItemIDList; Level: Integer);
对于Delphi来说,由于其提供了非常友好的对象框架,可以封装`IShellFolder`的功能,实现一个`TShellNode`类。`TShellNode`被设计为基类,可以从它继承更加有用的类,一些属性和方法是`protected`的,需要在继承类中声明为`public`。衍生类不应该重新定义`constructors`过程,但可以重载`Initialize`方法。
`TShellNode`类的扩展类可以添加系统图像列表索引属性、查找能力等等,这完全取决于你的想象。除了桌面外,微软还定义了一组CoClasses对象,它们都暴露了`IShellFolder`接口,我们也可以从它们出发来遍历命名空间。`TShellNode`类的示例衍生类可以添加图像索引和`Strings`属性。
举例来说,使用下面的代码来创建一个简单的打印机选择组合列表框:
p
EnumShellNamespace(ComboBox.Items, 1, CreateCOMObject(CLSID_Printers) as IShellFolder);
在例子程序中,`TShellNode`类衍生了一个`TShellTreeNode`类,添加了图像索引和`Strings`属性。`ImageIndex`属性对应于系统图像列表中的节点的图像索引,`Strings`属性保存着节点的绝对PIDL列表中每一项的显示名称。程序允许我们在绝对和相对PIDL察看模式间切换。示意图展示了程序中显示的外壳对象树。
例子程序的主要目的是演示如何进行PIDL的操作。在`GetItemListStrings`过程中,展示了如何使用`ILClone`、`ILFindChild`、`ILFree`、`ILGetCount`、`ILIsRoot`和`ILRemoveLastID`等例程。`ILClone`和`ILFindChild`用于复制和查找PIDL中的元素,`ILFree`用于释放内存,`ILGetCount`用于获取PIDL中的项目数量,`ILIsRoot`用于检查是否为根节点,而`ILRemoveLastID`用于删除PIDL的最后一个元素。这些功能共同提供了一种在Delphi应用程序中操作外壳命名空间的强大方法。
扩展资料