-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patharticle-12.html
175 lines (120 loc) · 16.2 KB
/
article-12.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
---
article: 12
title: "How to add a program to the Explorer Send To menu"
summary: "A look at adding an entry to Explorer's Send To menu and handling files sent to an application using the menu."
meta-title: "Use Delphi Pascal to add a program to the Windows Explorer Send To menu | How to"
meta-desc: "An article that explains how to use Delphi Pascal to programmatically add an item to Windows Explorer's \"Send To\" menu."
index: true
redirect_from:
- /articles/12
---
<section id="intro">
<h2>Why do it</h2>
<p>If you are writing a general purpose file-related program it can be useful to add it to the Windows Explorer "Send To" menu. For example I place Windows Notepad on the "Send To" menu so I can easily view any file in the text editor:</p>
<div id="figure-1" class="frame">
<div>
<img class="scale center-block" src="{{ site.data.core.articles-images-base-url}}/12.gif" alt="Screen shot of an example of 'Send To' menu" title="Figure 1" width="337" height="221">
</div>
<div class="caption">Figure 1: Example of a 'Send-To' menu</div>
</div>
</section>
<section id="method">
<h2>How it's done</h2>
<p>There are two stages achieving our goal:</p>
<ol>
<li>Ensuring our program can receive files sent from the "Send To" menu.</li>
<li>Creating an entry for our program in the "Send To" menu.</li>
</ol>
<p>Although you can create a special handler for the "Send To" menu, we will take the simple approach of simply storing a shortcut to our program in the menu.</p>
<h3>Receiving files from the "Send To" menu</h3>
<p>This is very simple. If the user selects one or more files, right clicks and selects <em>Send To | Our program</em>, Windows will simply start our program and pass the name(s) of the selected file(s) on the command line. So, to read the files sent from the "Send To" menu, we simply need to check our command line parameters.</p>
<p>We can do this in our application's <var>FormCreate</var> event handler as follows:</p>
<div class="frame">
<div class="code-pascal">
<pre class="line"><span class="linenum"> 1</span><span class="kwd">procedure</span><span class="space"> </span><span class="ident">TForm1</span><span class="sym">.</span><span class="ident">FormCreate</span><span class="sym">(</span><span class="ident">Sender</span><span class="sym">:</span><span class="space"> </span><span class="ident">TObject</span><span class="sym">)</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 2</span><span class="kwd">var</span></pre>
<pre class="line"><span class="linenum"> 3</span><span class="space"> </span><span class="ident">I</span><span class="sym">:</span><span class="space"> </span><span class="ident">Integer</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 4</span><span class="kwd">begin</span></pre>
<pre class="line"><span class="linenum"> 5</span><span class="space"> </span><span class="kwd">for</span><span class="space"> </span><span class="ident">I</span><span class="space"> </span><span class="sym">:=</span><span class="space"> </span><span class="num">1</span><span class="space"> </span><span class="kwd">to</span><span class="space"> </span><span class="ident">ParamCount</span><span class="space"> </span><span class="kwd">do</span></pre>
<pre class="line"><span class="linenum"> 6</span><span class="space"> </span><span class="ident">ProcessFile</span><span class="sym">(</span><span class="ident">ParamStr</span><span class="sym">(</span><span class="ident">I</span><span class="sym">)</span><span class="sym">)</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 7</span><span class="kwd">end</span><span class="sym">;</span></pre>
</div>
<div class="caption">Listing 1</div>
</div>
<p>where <var>ProcessFile</var> processes a given file in an application defined way. (In the <a href="#demo">demo program</a> that accompanies this article we simply display the file names in a memo control).</p>
<p>That's all there is to handling the files. Now let's look at how we create the "Send To" menu entry.</p>
<h3>Creating the "Send To" menu item</h3>
<p>Windows stores the contents of a user's "Send To" menu in a special folder. We will need to add a shortcut to our program in that folder.</p>
<p>We must first find the path to the "Send To" folder. Each user has their own copy of this folder. We find its location by using the <var>SHGetSpecialFolderLocation</var> and <var>SHGetPathFromIDList</var> API calls (defined in the <var>ShlObj</var> unit) as follows:</p>
<div class="frame">
<div class="code-pascal">
<pre class="line"><span class="linenum"> 1</span><span class="kwd">function</span><span class="space"> </span><span class="ident">GetSendToFolder</span><span class="sym">:</span><span class="space"> </span><span class="kwd">string</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 2</span><span class="kwd">var</span></pre>
<pre class="line"><span class="linenum"> 3</span><span class="space"> </span><span class="ident">pidl</span><span class="sym">:</span><span class="space"> </span><span class="ident">PItemIDList</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 4</span><span class="space"> </span><span class="ident">PPath</span><span class="sym">:</span><span class="space"> </span><span class="kwd">array</span><span class="sym">[</span><span class="num">0</span><span class="sym">..</span><span class="ident">MAX_PATH</span><span class="sym">]</span><span class="space"> </span><span class="kwd">of</span><span class="space"> </span><span class="ident">AnsiChar</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 5</span><span class="kwd">begin</span></pre>
<pre class="line"><span class="linenum"> 6</span><span class="space"> </span><span class="ident">Result</span><span class="space"> </span><span class="sym">:=</span><span class="space"> </span><span class="str">''</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 7</span><span class="space"> </span><span class="kwd">if</span><span class="space"> </span><span class="ident">SHGetSpecialFolderLocation</span><span class="sym">(</span><span class="num">0</span><span class="sym">,</span><span class="space"> </span><span class="ident">CSIDL_SENDTO</span><span class="sym">,</span><span class="space"> </span><span class="ident">pidl</span><span class="sym">)</span><span class="space"> </span><span class="sym">=</span><span class="space"> </span><span class="ident">NOERROR</span><span class="space"> </span><span class="kwd">then</span></pre>
<pre class="line"><span class="linenum"> 8</span><span class="space"> </span><span class="kwd">begin</span></pre>
<pre class="line"><span class="linenum"> 9</span><span class="space"> </span><span class="kwd">try</span></pre>
<pre class="line"><span class="linenum"> 10</span><span class="space"> </span><span class="kwd">if</span><span class="space"> </span><span class="ident">SHGetPathFromIDList</span><span class="sym">(</span><span class="ident">pidl</span><span class="sym">,</span><span class="space"> </span><span class="ident">PPath</span><span class="sym">)</span><span class="space"> </span><span class="kwd">then</span></pre>
<pre class="line"><span class="linenum"> 11</span><span class="space"> </span><span class="ident">Result</span><span class="space"> </span><span class="sym">:=</span><span class="space"> </span><span class="ident">PPath</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 12</span><span class="space"> </span><span class="kwd">finally</span></pre>
<pre class="line"><span class="linenum"> 13</span><span class="space"> </span><span class="ident">CoTaskMemFree</span><span class="sym">(</span><span class="ident">pidl</span><span class="sym">)</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 14</span><span class="space"> </span><span class="kwd">end</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 15</span><span class="space"> </span><span class="kwd">end</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 16</span><span class="kwd">end</span><span class="sym">;</span></pre>
</div>
<div class="caption">Listing 2</div>
</div>
<p>We first use <var>SHGetSpecialFolderLocation</var> to get a PIDL representing the required folder. We pass <var>CSIDL_SENDTO</var> to the function to get the PIDL for the current user's "Send To" folder. If we succeed in getting the PIDL we then get the path to the folder by passing the PIDL to <var>SHGetPathFromIDList</var> and returning a string representation of the PChar buffer we passed to the function. Windows allocated memory for the PIDL using its task allocator. It is our responsibility to free the PIDL, using the <var>CoTaskMemFree</var> function (defined in the <var>ActiveX</var> unit).</p>
<p>Having found the path to the user's "Send To" folder we can now create a shortcut to our application in the folder. We may choose to do this in a set up program or by making this an option in our application. Whatever our choice, here is the code we use:</p>
<div class="frame">
<div class="code-pascal">
<pre class="line"><span class="linenum"> 1</span><span class="comment">// ...</span></pre>
<pre class="line"><span class="linenum"> 2</span><span class="ident">CreateShellLink</span><span class="sym">(</span></pre>
<pre class="line"><span class="linenum"> 3</span><span class="space"> </span><span class="ident">GetSendToFolder</span><span class="space"> </span><span class="sym">+</span><span class="space"> </span><span class="str">'\'</span><span class="space"> </span><span class="sym">+</span><span class="space"> </span><span class="str">'My SendTo Item.lnk'</span><span class="sym">,</span></pre>
<pre class="line"><span class="linenum"> 4</span><span class="space"> </span><span class="ident">ParamStr</span><span class="sym">(</span><span class="num">0</span><span class="sym">)</span><span class="sym">,</span></pre>
<pre class="line"><span class="linenum"> 5</span><span class="space"> </span><span class="str">'My SendTo Sample Program'</span><span class="sym">,</span></pre>
<pre class="line"><span class="linenum"> 6</span><span class="space"> </span><span class="ident">ExtractFileDir</span><span class="sym">(</span><span class="ident">ParamStr</span><span class="sym">(</span><span class="num">0</span><span class="sym">)</span><span class="sym">)</span><span class="sym">,</span></pre>
<pre class="line"><span class="linenum"> 7</span><span class="space"> </span><span class="str">''</span><span class="sym">,</span></pre>
<pre class="line"><span class="linenum"> 8</span><span class="space"> </span><span class="str">''</span><span class="sym">,</span></pre>
<pre class="line"><span class="linenum"> 9</span><span class="space"> </span><span class="sym">-</span><span class="num">1</span></pre>
<pre class="line"><span class="linenum"> 10</span><span class="sym">)</span><span class="sym">;</span></pre>
<pre class="line"><span class="linenum"> 11</span><span class="comment">// ...</span></pre>
</div>
<div class="caption">Listing 3</div>
</div>
<p>We are making use of the <var>CreateShellLink</var> function from the DelphiDabbler <a href="https://github.com/delphidabbler/code-snippets/tree/master/csdb">Code Snippets Database</a> to create the shortcut to our program. The parameters passed to <var>CreateShellLink</var> are:</p>
<ol class="wide">
<li>The first parameter to <var>CreateShellLink</var> is the full path to the shortcut file – here we use the name of the "Send To" folder, as returned by <var>GetSendToFolder</var>, followed by the name of the shortcut file. Note that the "Send To" menu displays the name of this file, stripped of it's extension, so give the file a descriptive name.</li>
<li>The second parameter is the name of the file referenced by the shortcut – our program in this case. <var>ParamStr(0)</var> stores the name of the program.</li>
<li>The third parameter is a description of the shortcut (this is <em>not</em> displayed in the "Send To" menu).</li>
<li>The fourth parameter is our program's working directory. This may be omitted if not required.</li>
<li>The fifth parameter stores any command line that is to be passed to the program. We do not use this parameter here. Remember that the "Send To" menu also passes file names on the command line.</li>
<li>The sixth parameter is not used here: when provided it specifies the file containing the shortcut's icon. Since we don't specify a file, the icon is assumed to be in the program file.</li>
<li>The final parameter also related to the shortcut's icon. Specifying <samp>-1</samp> indicates that the program's default icon should be used.</li>
</ol>
<p> Since this article is not about how to create shell links, we will not go into detail of how this routine works or review its source code here. (The source code <em>is</em> included in the accompanying <a href="#demo">demo program</a>.)</p>
<h3>That's all folks</h3>
<p>We have now covered the basics of adding an item to the "Send To" menu and in handling files "sent" to our program from the menu. The code presented can be used as a basis for implementing "Send To" menu support in your programs.</p>
</section>
<section id="demo">
<h2>Demo program</h2>
<p>A demo program to accompany this article can be found in the <code><a href="https://github.com/delphidabbler/article-demos">delphidabbler/article-demos</a></code> Git repository on GitHub.</p>
<p>You can view the code in the <code><a href="https://github.com/delphidabbler/article-demos/tree/master/article-12">article-12</a></code> sub-directory. Alternatively download a zip file containing all the demos by going to the repository's landing page and clicking the <em>Clone or download</em> button and selecting <em>Download ZIP</em>.</p>
<p>See the demo's <a href="https://github.com/delphidabbler/article-demos/blob/master/article-12/README.md">README.md</a> file for details.</p>
<div class="callout callout-info">
<p><span class="fa fa-code fa-x-pad-right fa-2x fa-pull-left fa-border text-muted"></span>This source code is merely a proof of concept and is intended only to illustrate this article. It is not designed for use in its current form in finished applications. The code is provided on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.</p>
<p>The demo is open source. See the demo's <a href="https://github.com/delphidabbler/article-demos/blob/master/article-12/LICENSE.md">LICENSE.md</a> file for licensing details.</p>
</div>
</section>
<section id="feedback">
<h2>Feedback</h2>
<p>I hope you found this article useful.</p>
<p>If you have any observations, comments, or have found any errors there are two places you can report them.</p>
<ol class="wide">
<li>For anything to do with the article content, <em>but not the downloadable demo code</em>, please use this website's <a href="https://github.com/delphidabbler/delphidabbler.github.io/issues">Issues page</a> on GitHub. Make sure you mention that the issue relates to "article #12".</li>
<li>For bugs in the demo code see the <code>article-demo</code> project's <code><a href="https://github.com/delphidabbler/article-demos/blob/master/README.md#bug-reports">README.md</a></code> file for details of how to report them.</li>
</ol>
</section>