⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 faq62.htm

📁 C++builder学习资料C++builder
💻 HTM
📖 第 1 页 / 共 2 页
字号:


<HTML>

<HEAD>

   <TITLE>Allow the user to browse for a folder</TITLE>

   <META NAME="Author" CONTENT="Harold Howe">

</HEAD>

<BODY BGCOLOR="WHITE">



<CENTER>

<TABLE  BORDER=0 CELLPADDING=0 CELLSPACING=0 WIDTH="640">



<TR>

<TD>







<H3>

Allow the user to browse for a folder

</H3>

<BR>

<H3>Answer:</H3>

<P>

There are two ways to allow the user to browse for a folder. First, there's the hard way,

using the API function <TT>SHBrowseForFolder</TT>. Then there's the easy way, using the

VCL's <TT>SelectFolder</TT> function. <TT>SelectFolder</TT> is documented in the BCB

help system. This function works nicely, but unfortunately, it displays a form that uses

the old Win 3.1 icons for folders and drives. <TT>SHBrowseForFolder</TT> shows a more

contemporary dialog that contains the newer icons that are part of Windows 95, Windows 98,

and Windows NT4. This FAQ explains how to utilize the <TT>SHBrowseForFolder</TT> function

in a C++Builder project. Figure 1 shows the dialog box that pops up when you call <TT>SHBrowseForFolder</TT>.

</P>



<IMG SRC="images/browse.gif" BORDER=0 ALIGN="BOTTOM">  <BR>

<H4>Figure 1. The <TT>SHBrowseForFolder</TT> dialog</H4>

<P>

<TT>SHBrowseForFolder</TT> is part of the shell interface API. The prototype for the

function is located in <TT>SHLOBJ.H</TT>. Like most API functions,

<TT>SHBrowseForFolder</TT> takes a large, inexplicable structure as an argument.

The structure's type name is <TT>BROWSEINFO</TT>. You fill in the members of this

structure to control how the browse dialog will behave. After the user closes the dialog,

<TT>SHBrowseForFolder</TT> returns a pointer to an ID list (<TT>PIDL</TT>) that indicates

what folder was selected.

</P>

<P>

One confusing aspect of <TT>SHBrowseForFolder</TT> is that it doesn't return the directory

path to the folder that the user selected. One might presume that the <TT>BROWSEINFO</TT>

structure would contain a string for the directory path. Of course, this would

have made way too much sense, so Microsoft decided to implement an elaborate mechanism

that requires you to work for that directory string. As mentioned earlier,

<TT>SHBrowseForFolder</TT> returns a PIDL, which is a relatively worthless object. The

API contains a function called <TT>SHGetPathFromIDList</TT> that can convert a PIDL into

a directory path string.

</P>

<P>

The code segment below explains how to use <TT>SHBrowseForFolder</TT>.

</P>

<pre>

<b>void</b> <b>__fastcall</b> TForm1<b>:</b><b>:</b>Button1Click<b>(</b>TObject <b>*</b>Sender<b>)</b>

<b>{</b>

    BROWSEINFO    info<b>;</b>

    <b>char</b>          szDir<b>[</b>MAX_PATH<b>]</b><b>;</b>

    <b>char</b>          szDisplayName<b>[</b>MAX_PATH<b>]</b><b>;</b>

    LPITEMIDLIST  pidl<b>;</b>

    LPMALLOC      pShellMalloc<b>;</b>



    <font color="navy">// SHBrowseForFolder returns a PIDL. The memory for the PIDL is</font>

    <font color="navy">// allocated by the shell. Eventually, we will need to free this</font>

    <font color="navy">// memory, so we need to get a pointer to the shell malloc COM</font>

    <font color="navy">// object that will free the PIDL later on.</font>

    <b>if</b><b>(</b>SHGetMalloc<b>(</b><b>&</b>pShellMalloc<b>)</b> <b>==</b> NO_ERROR<b>)</b>

    <b>{</b>

        <font color="navy">// if we were able to get the shell malloc object,</font>

        <font color="navy">// then proceed by initializing the BROWSEINFO stuct</font>

        memset<b>(</b><b>&</b>info<b>,</b> <font color="blue">0x00</font><b>,</b><b>sizeof</b><b>(</b>info<b>)</b><b>)</b><b>;</b>

        info<b>.</b>hwndOwner <b>=</b> Handle<b>;</b>                 <font color="navy">// Owner window</font>

        info<b>.</b>pidlRoot  <b>=</b> <font color="blue">0</font><b>;</b>                      <font color="navy">// root folder</font>

        info<b>.</b>pszDisplayName <b>=</b> szDisplayName<b>;</b>     <font color="navy">// return display name</font>

        info<b>.</b>lpszTitle <b>=</b> <font color="blue">"Browse Title"</font><b>;</b>         <font color="navy">// label caption</font>

        info<b>.</b>ulFlags   <b>=</b> BIF_RETURNONLYFSDIRS<b>;</b>   <font color="navy">// config flags</font>

        info<b>.</b>lpfn <b>=</b> <font color="blue">0</font><b>;</b>                           <font color="navy">// callback function</font>



        <font color="navy">// execute the browsing dialog</font>

        pidl <b>=</b> SHBrowseForFolder<b>(</b><b>&</b>info<b>)</b><b>;</b>



        <font color="navy">// pidl will be null if they cancel the browse dialog.</font>

        <font color="navy">// pidl will be not null when they select a folder</font>

        <b>if</b><b>(</b>pidl<b>)</b>

        <b>{</b>

            <font color="navy">// try to convert the pidl to a display string</font>

            <font color="navy">// return is true if success</font>

            <b>if</b><b>(</b>SHGetPathFromIDList<b>(</b>pidl<b>,</b> szDir<b>)</b><b>)</b>

            <b>{</b>

                <font color="navy">// set one caption to the directory path</font>

                Label1<b>-></b>Caption <b>=</b> szDir<b>;</b>

            <b>}</b>



            <font color="navy">// set another caption based on the display name</font>

            Label2<b>-></b>Caption <b>=</b> info<b>.</b>pszDisplayName<b>;</b>



            <font color="navy">// use the shell malloc com object to free the pidl.</font>

            <font color="navy">// then call Relasee to signal that we don't need</font>

            <font color="navy">// the shell malloc object anymore</font>

            pShellMalloc<b>-></b>Free<b>(</b>pidl<b>)</b><b>;</b>

        <b>}</b>

        pShellMalloc<b>-></b>Release<b>(</b><b>)</b><b>;</b>

    <b>}</b>

<b>}</b>

</pre>

<H3>Understanding the purpose of <TT>SHGetMalloc</TT></H3>

<P>

<TT>SHBrowseForFolder</TT> returns a <TT>PIDL</TT> object. The <TT>PIDL</TT> is allocated by the shell's task

allocator. When you're done using the <TT>PIDL</TT>, it must be released by the task allocator. In

order to properly free the <TT>PIDL</TT> object, you must obtain a reference to the shell's task

allocator by calling the <TT>SHGetMalloc</TT> function. You can then use the task allocator

to deallocate the <TT>PIDL</TT>.

</P>

<P>

<TT>SHGetMalloc</TT> returns a pointer to an <TT>IMalloc</TT> COM object. The <TT>IMalloc</TT> COM interface

is documented in the OLE Reference MS help file that comes with C++Builder. If you're not

up to speed with COM (like...who is), then think of the <TT>IMalloc</TT> COM object as just another

C++ object that has methods that you can call. The method that we need for this FAQ is the

<TT>Free</TT> method. <TT>Free</TT> will release the <TT>PIDL</TT> object. When you're finished using the

task alloctor, call the <TT>Release</TT> method of the <TT>IMalloc</TT> object. The pseudo-code below depicts the

relationship between the COM methods and regular C++ code that we are more familiar with.

</P>

<PRE>

<B>COM code</B>                           <B>C++ psuedo-equivalent</B>

LPMALLOC pShellMalloc;             // think of pShellMalloc as an object that

SHGetMalloc(&pShellMalloc);        // handles new and delete for OS shell tasks



LPITEMIDLIST  pidl;                Tpidl *pidl;

pidl = SHBrowseForFolder(...);     pidl = new Tpidl();



pShellMalloc-&gt;Free(pidl);          delete pidl;



pShellMalloc-&gt;Release();

</PRE>

<H3>The <TT>BROWSEINFO</TT> structure</H3>

<P>

The <TT>BROWSEINFO</TT> structure allows you to control the appearance and behavior

of the <TT>SHBrowseForFolder</TT> dialog. Each <TT>BROWSEINFO</TT> structure is described

below.

</P>

<pre>

<b>typedef</b> <b>struct</b> <b>{</b>

    HWND          hwndOwner<b>;</b>

    LPCITEMIDLIST pidlRoot<b>;</b>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -