📄 cb199910dc_f.asp.htm
字号:
style='mso-bidi-font-style:normal'>SHGetDesktopFolder</i> method is used to get
a pointer to this interface. Initially, this pointer is bound to the Desktop
folder, which is, in fact, the root folder of the shell. All other folders are
referenced relative to this root folder. Several methods of the <i
style='mso-bidi-font-style:normal'>IShellFolder</i> interface will be used
throughout our implementation. (The reader is referred to <i>OLE
Programmer's Reference</i>, available as online help with C++Builder, for a complete description of each
of these methods.) The ones used will be described as needed. For now, think of
the <i>IShellFolder</i> interface as a
simple class with several member functions used to manipulate shell folders.
None of these objects are real classes; they're C++ structures, where each
"method" is a virtual function. </p>
<p class=BodyText> </p>
<p class=BodyText> Other
interfaces of interest include <i>IEnumIDList</i>,
<i>IContextMenu</i>, and <i
style='mso-bidi-font-style:normal'>IContextMenu2</i>. As the name implies, the <i
style='mso-bidi-font-style:normal'>IEnumIDList</i> interface is used to
enumerate items in a given folder. The advantage is that this interface can be
used with virtual folders, as well as standard file folders. Similarly, the <i
style='mso-bidi-font-style:normal'>IContextMenu</i> and <i>IContextMenu2</i> interfaces are used to handle an object's context
menu. Each of these interfaces will return a pointer of a specific type. For
example, the <i>SHGetMalloc</i> function
returns a long pointer to the <i>IMalloc</i>
interface (LPMALLOC). Similarly, the LPSHELLFOLDER is a pointer to the <i
style='mso-bidi-font-style:normal'>IShellFolder</i> interface. </p>
<p class=BodyText> </p>
<p class=BodyText> There
are several data types that are commonly used when working with the shell
namespace. The one of primary concern is the ITEMIDLIST (item identifier list)
and its corresponding pointer, LPITEMIDLIST. This pointer is abbreviated as
PIDL (pronounced "piddle"). A PIDL is nothing more than a pointer to an item
identifier list. As you may have guessed, an item identifier list (ID list) is
nothing more than a list of IDs (of the type SHITEMID). Each SHITEMID uniquely
identifies an object in that object's parent folder. A list of these IDs
identifies an object within the shell namespace. </p>
<p class=BodyText> </p>
<p class=BodyText> While
item identifiers are used by the shell, they are never actually seen by the
user. It would be quite difficult to identify a list of files based solely on
their corresponding item ID. Instead, the shell uses display names for each
file object. Keep in mind that the term <i>file object</i> refers to any item
in the shell, including printers and Control Panel applications. </p>
<p class=BodyText> </p>
<p class=BodyText> Like
paths, PIDLs come in two flavors: relative and absolute. Direct descendants of
the Desktop, such as My Computer and Network Neighborhood, have absolute PIDLs;
they only contain one SHITEMID (see the <i>EnumDeskVB</i>
example project at <a href="javascript:if(confirm('http://www.mvps.org/btmtz/ \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address. \n\nDo you want to open it from the server?'))window.location='http://www.mvps.org/btmtz/'" tppabs="http://www.mvps.org/btmtz/">http://www.mvps.org/btmtz/</a>).
Although in reality they're relative to the Desktop folder, they're called
absolute because the Desktop folder is the root folder, and their parent folder
is the Desktop. The Control Panel's PIDL, on the other hand, is not absolute because
its parent folder is My Computer. Similarly, a file object in the Control Panel
has a PIDL relative to the Control Panel. Because the Desktop folder is also
the root folder, its PIDL only contains one SHITEMID of size zero. </p>
<p class=BodyText> </p>
<p class=BodyText> Working
with PIDLs isn't always straightforward. Although there are several standard
functions and methods that can be used to parse or concatenate strings, there
are none for working with PIDLs. (That statement isn't entirely correct; there
are many undocumented functions exported from shell32.dll that are designed to
work with PIDLs. We'll discuss the undocumented features in a later section.)
For now, we need to construct some functions that will make working with PIDLs
easier. <a href="#ListingOne">Listing One</a>
shows helper functions that make it easier to use PIDLs. </p>
<p class=BodyText> </p>
<p class=Subheads>Using the
Shell Namespace to Fill the ListView</p>
<p class=BodyText> Now that
we have the necessary tools for manipulating PIDLs, let's proceed with the
actual enumeration. At this point, we have yet to write any component-specific
code. As before, we start with a blank form containing a single <i
style='mso-bidi-font-style:normal'>TListView</i>. The code in <a
href="#ListingTwo">Listing Two</a>
demonstrates the use of the shell namespace to fill the ListView. Note that if
successful, it's very easy to adapt this code into a component by simply
cutting and pasting the entire function. Furthermore, it's much easier to test
the function before placing it into a component. </p>
<p class=BodyText> </p>
<p class=BodyText> Note how
we used each of the described interfaces to perform a specific task. This is
one of the features of COM: Each interface is designed to accomplish a set of
tasks pertaining to the scope of objects that the particular interface
supports. </p>
<p class=BodyText> </p>
<p class=BodyText> Let's
briefly examine how the <i>FillListEx</i>
method works. The function takes two parameters: a pointer to the shell folder,
and a PIDL for the folder to enumerate. Within the function, we first use the <i
style='mso-bidi-font-style:normal'>SHGetMalloc</i> function to get a pointer to
the <i>IMalloc</i> interface. The only role
of this interface is to free the memory allocated by the various shell
functions. Next, we call the <i>IShellFolder::EnumObjects</i>
method to perform the actual enumeration. This function returns a pointer to
the <i>IEnumIDList</i> interface, which is
then used to perform the actual enumeration. The <i>IEnumIDList::Next</i>
method iterates through all IDs in the folder. This method returns a PIDL to
each object, which is then passed into the <i>SHGetFileInfo</i>
function to retrieve useful information, such as its display name and system
image list icon index. Passing the SHGFI_PIDL flag to the <i>SHGetFileInfo</i> function, we can pass a PIDL as the <i
style='mso-bidi-font-style:normal'>pszPath</i> parameter where a path is
usually specified. Because this PIDL must be absolute, we use the <i
style='mso-bidi-font-style:normal'>MergeIDLists</i> helper function. </p>
<p class=BodyText> </p>
<p class=BodyText> We'll
eventually implement the Details (vsReport) view, so now is a good time to add
this functionality. Although this feature isn't high on our priority list, it's
a good idea to implement it now while the process is fresh in our minds.
Explorer's Details view adds three additional columns to the list: Size, Type,
and Modified. The Type field is simple to add because this information can be
returned by the <i>SHGetItemInfo</i> call by
including the SHGFI_TYPENAME flag. The other two fields, Size and Modified, are
usually returned by a call to <i>FindFirstFile</i>/<i
style='mso-bidi-font-style:normal'>FindNextFile</i> in the WIN32_FIND_DATA
structure. However, using the <i>SHGetDataFromIDList</i>
function, we can retrieve the same information from a PIDL. </p>
<p class=BodyText> </p>
<p class=Subheads>Conclusion</p>
<p class=BodyText> This
article demonstrated the first part of creating an Explorer-style ListView component,
starting with the tedious design stages. Several COM interfaces and use of the
shell namespace to fill in the ListView control of our component were also
discussed. </p>
<p class=BodyText> </p>
<p class=BodyText> In the
next installation of this two-part series, we'll do some coding and implementation
of the Explorer-style component. We'll discuss various issues, including
relieving the bottleneck mentioned in this article, sorting the list of files,
adding extra functionality, adding the context menu, automatic launching,
getting notification, and other design-time considerations. </p>
<p class=BodyText> </p>
<p class=BodyText> <i>The code referenced in this article is<b>
</b>available for <a href="download/cb199910dc_f.zip" tppabs="http://www.cbuilderzine.com/features/1999/10/cb199910dc_f/cb199910dc_d.asp">download</a>. </i></p>
<p class=BodyText> </p>
<p class=Biotext>Damon
Chandler has been programming for over 15 years, and enjoys every facet of the
art. Mostly self-taught, Damon followed a common path to C++ programming -
GW-BASIC, Pascal, then C++. It was the combination of the VCL and C++ that got
him hooked on C++Builder. An engineer by trade and a programmer at heart, Damon
is very pleased to see the two technologies finally merge. Damon is currently
working in the Visual Communications Lab at Cornell University, where his
research primarily centers around wavelet image compression. C++Builder is the
tool of choice, and the RAD theme has helped create new interfaces for often
obscure tasks. </p>
<p class=BodyText> </p>
<p class=Subheads><a name=ListingOne></a>Begin Listing One - Helper functions</p>
<p class=Code><span class=Code><i><span Class=CodeBlue>/**********************************************************************</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>* Shell
Namespace Helper Functions: Working
with PIDLS</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue> **********************************************************************/</span></i></span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>// =====================================================================</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>// Function: GetItemCount()</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>// Synopsis: Returns the number of item identifiers in a PIDL</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>// Parameters: LPITEMIDLIST pidl -- PIDL to enumerate</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>//
=====================================================================</span></i></span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><b>unsigned</b>
<b>int</b> GetItemCount(LPITEMIDLIST pidl) </span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code><b> unsigned</b> <b>int</b> nCount = 0; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <b> unsigned</b>
<b>short</b> nLen = pidl->mkid.cb; </span></p>
<p class=Code><span class=Code> <b> while</b>
(nLen != 0) </span></p>
<p class=Code><span class=Code> { </span></p>
<p class=Code><span class=Code> pidl = GetNextItem(pidl); </span></p>
<p class=Code><span class=Code> nLen = pidl->mkid.cb; </span></p>
<p class=Code><span class=Code> nCount++;</span></p>
<p class=Code><span class=Code> } </span></p>
<p class=Code><span class=Code> <b> return</b>
nCount; </span></p>
<p class=Code><span class=Code>}</span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>// ---------------------------------------------------------------------------</span></i></span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>//
=====================================================================</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>// Function: GetNextItem()</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>// Synopsis: Returns a pointer to the next item identifier in a PIDL</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>// Parameters: LPITEMIDLIST pidl -- PIDL containing
item to point to</span></i></span></p>
<p class=Code><span class=Code><i><span Class=CodeBlue>//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -