📄 cb200006dc_f.asp.htm
字号:
<p class=BodyText> </p>
<p class=BodyText> We
provide support for context menus in our class via the <i>DoShowContextMenu</i>, <i>WMContextMenu</i>,
and <i>WMContextMenu2</i> member functions,
as shown in <a href="#ListingSeven">Listing Seven</a>.
The former handles the details we've just discussed. The <i>WMContextMenu</i> member function is simply a message handler for the
WM_CONTEXTMENU message. The <i>WMContextMenu2</i>
member function handles the popup menu and owner-drawn messages that are sent
through the use of the <i>IContextMenu2</i>
interface. Specifically, the member function handles the WM_DRAWITEM,
WM_MEASUREITEM, and WM_INITMENUPOPUP messages. The actual task of rendering the
owner-drawn menu items is delegated to the <i>IContextMenu2</i>
interface itself, via the <i>IContextMenu2:: HandleMenuMsg</i> member function. </p>
<p class=BodyText> </p>
<p class=BodyText> To help
fortify the techniques of using the <i>IContextMenu</i>
and <i>IContextMenu2</i> interfaces, refer
to the DemoContextMenu sample project (also included with the downloadable
source code). In this project, the task of displaying an item's context menu is
isolated from the rest of the <i>TExpListView</i>
implementation. </p>
<p class=BodyText> </p>
<p class=Subheads>Launching
an Item's Associated Application</p>
<p class=BodyText> Since
we've associated a <i>TListShellInfo</i>
instance with each <i>TListItem</i> object,
we have access to the absolute and relative PIDLs of each shell object within
our list view. Accordingly, to launch an item's associated application, we can
simply use the <i>ShellExecuteEx</i> API
function with the SEE_MASK_INVOKEIDLIST flag. Use of this flag simply instructs
the function that the <i>SHELLEXECUTEINFO:: lpIDList </i>data member contains
the fully qualified PIDL of the item we wish to execute. Support for this
functionality is provided in our class via the <i>DoLaunchItem</i> and <i>LaunchItem</i>
member functions. The former simply calls the latter, which uses the <i
style='mso-bidi-font-style:normal'>ShellExecuteEx</i> function. These member
functions are shown in <a href="#ListingEight">Listing Eight</a>.</p>
<p class=BodyText> </p>
<p class=BodyText> Notice
from the implementation of the <i>LaunchItem</i>
member function that we provide special handling for the situation when the
shell item is a shortcut. In such a case, we cannot simply assign the item's
absolute PIDL to the <i>lpIDList</i> data
member, because the PIDL refers to the link object itself, not the object to
which the shortcut refers. Instead, we use the <i>GetLinkPIDL</i> function (from the "pidlhelp" library) to de-reference
the link object, then assign this result to the <i>lpIDList</i> data member. </p>
<p class=BodyText> </p>
<p class=Subheads>Receiving
Notification of Changes</p>
<p class=BodyText> While we
now have a robust means of filling our list view and managing the items that it
contains, we still need a method of receiving notification of changes to any of
the objects that are represented. For file system objects, we can simply use
the <i>FindFirstChangeNotification</i> and <i
style='mso-bidi-font-style:normal'>FindNextChangeNotification</i> API
functions, in conjunction with the <i>WaitForMultipleObjects</i>
API function. This latter function will literally wait for notification (from
the file system) of a change event. The "waiting" process is typically handled
in a separate thread to allow the main thread to continue processing messages.
To this end, we can simply create a <i>TThread</i>
descendant class, and place the <i>WaitForMultipleObjects</i>
function call in the <i>Execute</i> member
function. For a detailed discussion of this process, including the specifics of
the <i>TThread</i> descendant class, refer
to the sample project <span Class=CodeBlue><a
href="javascript:if(confirm('http://bcbcaq.freeservers.com/Project_Monitor.html \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://bcbcaq.freeservers.com/Project_Monitor.html'" tppabs="http://bcbcaq.freeservers.com/Project_Monitor.html">http://bcbcaq.freeservers.com/Project_Monitor.html</a>.</span><i></i></p>
<p class=BodyText> </p>
<p class=BodyText> Unfortunately,
the aforementioned technique will not work for virtual folders; the <i
style='mso-bidi-font-style:normal'>FindFirstChangeNotification</i> function requires
a file system path. In fact, there's no documented means by which we can
monitor the contents of a virtual folder without some type of polling
technique. As it turns out, there is an undocumented alternative, via the <i
style='mso-bidi-font-style:normal'>SHChangeNotifyRegister</i> function, exported
from SHELL32.DLL with an ordinal value of two. While the use of this function
is open to interpretation, Bluck and Holderness have prepared a comprehensive
treatment in the article found at <span Class=CodeBlue><a
href="javascript:if(confirm('http://www.delphizine.com/features/1999/03/di199903kb_f/di199903kb_f.asp \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.delphizine.com/features/1999/03/di199903kb_f/di199903kb_f.asp'" tppabs="http://www.delphizine.com/features/1999/03/di199903kb_f/di199903kb_f.asp">http://www.delphizine.com/features/1999/03/di199903kb_f/di199903kb_f.asp</a>.</span></p>
<p class=BodyText> </p>
<p class=Subheads>Design-time
Considerations</p>
<p class=BodyText> Now that
the run-time functionality is in place, let's consider some design-time issues.
We have one published property, <i>Folder</i>, that needs a property editor.
Instead of requiring the user to type in an absolute path just to change
directories, let us display a simple "Browse for Folder" dialog box, as
depicted in Figure 4. By using the <i>SHBrowseForFolder</i>
API function, we can obtain an absolute PIDL for the chosen folder. Moreover,
this will allow easy selection of virtual folders. </p>
<p class=BodyText> </p>
<p class=Captions><img width=333 height=214
src="images/cb200006dc_f_image006.jpg" tppabs="http://www.cbuilderzine.com/features/2000/06/cb200006dc_f/cb200006dc_f_image006.jpg" align=left hspace=12><b>Figure 4:</b> The Folder property editor. </p>
<p class=BodyText> </p>
<p class=BodyText> For the
property editor, we create a <i>TStringProperty</i>
descendant class, <i>TPathEditor</i>, and
implement three inherited member functions: <i>Edit</i>, <i>GetValue</i>, and <i>GetAttributes</i>.
<i>GetAttributes</i> is used to indicate what property attributes to display in
the Object Inspector. In this case, we return the <i>paDialog</i> and <i>paReadOnly</i>
attributes. </p>
<p class=BodyText> </p>
<p class=BodyText> Within
the <i>GetValue</i> member function, we
return the string we want displayed in the Object Inspector's edit control
field for the <i>Folder</i> property. Because most virtual folders will yield
an empty string for the <i>Folder</i> property, we implement the <i
style='mso-bidi-font-style:normal'>GetValue</i> member function to return the
virtual folder's corresponding display name. This latter task is accomplished
by the <i>DisplayNameFromPIDL</i> utility
function. </p>
<p class=BodyText> </p>
<p class=BodyText> The <i
style='mso-bidi-font-style:normal'>Edit</i> member is executed when the user
clicks the ellipsis button that appears next to the Folder field (as a result
of the <i>paDialog</i> attribute). It is
from within this function that we call the <i>SHBrowseForFolder</i>
API function, then assign the returned PIDL to the <i>PIDL</i> property of our
component. <a href="#ListingNine">Listing Nine</a>
provides the implementation of the <i>TPathEditor</i>
class. </p>
<p class=BodyText> </p>
<p class=BodyText> Notice
that we use a few additional PIDL-related utility functions in the
implementation of our <i>TPathEditor</i>
class. For example, we use the <i>CSIDLFromPIDL</i>
utility function to retrieve a special folder constant identifier (the CSIDL_<i>XXX</i>
values) from a PIDL. This conversion is necessary because we cannot rely on the
display name of a virtual folder to yield its PIDL. Put another way, the "My
Computer" object may be renamed "Jim Bob's Computer" on the end user's system.
If we were to stream "My Computer" to the .dfm file on the development machine,
the component will fail to return a PIDL from this display name on the end
user's machine if there is no object with that particular display name. The
only consistent references that we have are the CSIDL definitions. That is,
CSIDL_DRIVES (the CSIDL constant for "My Computer") will work on any machine
regardless of changes to the display name of the "My Computer" object. </p>
<p class=BodyText> </p>
<p class=Subheads>Conclusion</p>
<p class=BodyText> Creating
an Explorer-style list view control is by no means a weekend task. In fact,
there are many more aspects yet to be "explored." One major feature that has
been conveniently overlooked is drag-and-drop support. Like much of the implementation
presented throughout this article, this requires the use of several additional
COM interfaces. Other features, such as adding a background image, require less
effort. While additional testing needs to be done before our component is
deemed completely robust, the underlying principles are nonetheless sound. For
example, a similar approach can be used to create an Explorer-style tree view
control or an Explorer-style combo box. </p>
<p class=BodyText> </p>
<p class=BodyText> <i>The code referenced in this article is<b>
</b>available for <a href="download/cb200006dc_f.zip" tppabs="http://www.cbuilderzine.com/features/2000/06/cb200006dc_f/cb200006dc_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 - The <i>TListShellInfo</i>
class</p>
<p class=Code><span class=Code><b>class</b>
PACKAGE TListShellInfo : <b>public</b>
TObject</span></p>
<p class=Code><span class=Code>{</span></p>
<p class=Code><span class=Code><b>private</b>:</span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Path property. </span></i></span></p>
<p class=Code><span class=Code> AnsiString <b>__fastcall</b> GetPath()<b>const</b></span></p>
<p class=Code><span class=Code> { <b>return</b>
PathFromPIDL(m_FlpidlFQ); }</span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// AbsolutePIDL and RelativePIDL properties. </span></i></span></p>
<p class=Code><span class=Code> LPITEMIDLIST m_FlpidlFQ; </span></p>
<p class=Code><span class=Code> LPITEMIDLIST m_FlpidlRel; </span></p>
<p class=Code><span class=Code> </span></p>
<p class=Code><span class=Code> <i> <span Class=CodeBlue>// Attributes properties. </span></i></span></p>
<p class=Code><span class=Code> <b> bool</b>
m_FIsVirtual; </span></p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -