Statistics
| Branch: | Revision:

root / trunk / Pithos.ShellExtensions / ShellExtLib.cs @ bb679ec8

History | View | Annotate | Download (33.4 kB)

1
#region
2
/* -----------------------------------------------------------------------
3
 * <copyright file="ShellExtLib.cs" company="GRNet">
4
 * 
5
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or
8
 * without modification, are permitted provided that the following
9
 * conditions are met:
10
 *
11
 *   1. Redistributions of source code must retain the above
12
 *      copyright notice, this list of conditions and the following
13
 *      disclaimer.
14
 *
15
 *   2. Redistributions in binary form must reproduce the above
16
 *      copyright notice, this list of conditions and the following
17
 *      disclaimer in the documentation and/or other materials
18
 *      provided with the distribution.
19
 *
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
 * POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 * The views and conclusions contained in the software and
35
 * documentation are those of the authors and should not be
36
 * interpreted as representing official policies, either expressed
37
 * or implied, of GRNET S.A.
38
 * </copyright>
39
 * -----------------------------------------------------------------------
40
 */
41
#endregion
42
using System;
43
using System.Diagnostics;
44
using System.Text;
45
using Microsoft.Win32;
46
using System.Runtime.InteropServices;
47
using System.Runtime.InteropServices.ComTypes;
48

    
49

    
50
namespace Pithos.ShellExtensions
51
{
52
    #region Shell Interfaces
53
    [Flags]
54
    public enum ISIOI
55
    {
56
        ISIOI_ICONFILE = 1,
57
        ISIOI_ICONINDEX = 2
58
    }
59

    
60
    [ComVisible(false)]
61
    [ComImport]
62
    [Guid("0C6C4200-C589-11D0-999A-00C04FD655E1")]
63
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
64
    public interface IShellIconOverlayIdentifier
65
    {
66

    
67
        [PreserveSig]
68
        int IsMemberOf(
69
            [MarshalAs(UnmanagedType.LPWStr)] string path,
70

    
71
            uint attributes);
72

    
73
        [PreserveSig]
74
        int GetOverlayInfo(
75
            IntPtr iconFileBuffer,
76
            int iconFileBufferSize,
77
            out int iconIndex,
78
            out uint flags);
79

    
80
        [PreserveSig]
81
        int GetPriority(
82
            out int priority);
83

    
84
    }
85

    
86

    
87

    
88
    [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
89
    [Guid("000214e8-0000-0000-c000-000000000046")]
90
    internal interface IShellExtInit
91
    {
92
        void Initialize(
93
            IntPtr /*LPCITEMIDLIST*/ pidlFolder,
94
            IntPtr /*LPDATAOBJECT*/ pDataObj,
95
            IntPtr /*HKEY*/ hKeyProgID);
96
    }
97

    
98

    
99
    [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
100
    [Guid("000214e4-0000-0000-c000-000000000046")]
101
    internal interface IContextMenu
102
    {
103
        [PreserveSig]
104
        int QueryContextMenu(
105
            IntPtr /*HMENU*/ hMenu,
106
            uint iMenu,
107
            uint idCmdFirst,
108
            uint idCmdLast,
109
            uint uFlags);
110

    
111
        void InvokeCommand(IntPtr pici);
112

    
113
        void GetCommandString(
114
            UIntPtr idCmd,
115
            uint uFlags,
116
            IntPtr pReserved,
117
            StringBuilder pszName,
118
            uint cchMax);
119
    }
120

    
121
    #endregion
122

    
123

    
124
    #region Shell Registration
125

    
126
    internal class ShellExtReg
127
    {
128
        private const string _approvedKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved";
129

    
130
        public static void RegisterIconOverlayIdentifier(Guid clsid,
131
            string friendlyName)
132
        {
133
            if (clsid == Guid.Empty)
134
            {
135
                throw new ArgumentException("clsid must not be empty");
136
            }
137
            if (string.IsNullOrEmpty(friendlyName))
138
            {
139
                throw new ArgumentException("friendlyName must not be null or empty");
140
            }
141

    
142
            // Create the key HKLM\SOFTWARE\TortoiseOverlays\<IconName>\Pithos={<CLSID>}.
143
            string keyName = string.Format(@"SOFTWARE\TortoiseOverlays\{0}",
144
                friendlyName);
145
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyName,true))
146
            {
147
                // Set the default value of the key.
148
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
149
                {
150
                    key.SetValue("Pithos", clsid.ToString("B"),RegistryValueKind.String);
151
                }
152
            }
153
        }
154

    
155
        internal static void UnregisterIconOverlayIdentifier(Guid clsid,
156
            string friendlyName)
157
        {
158
            if (clsid == null)
159
            {
160
                throw new ArgumentException("clsid must not be null");
161
            }
162
            if (string.IsNullOrEmpty(friendlyName))
163
            {
164
                throw new ArgumentException("friendlyName must not be null or empty");
165
            }
166

    
167

    
168
            string keyName = string.Format(@"SOFTWARE\TortoiseOverlays\{0}",
169
                friendlyName);
170
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyName, true))
171
            {
172
                // Set the default value of the key.
173
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
174
                {
175
                    key.DeleteValue("Pithos");
176
                }
177
            }
178
        }
179

    
180

    
181
        /// <summary>
182
        /// Register the context menu handler.
183
        /// </summary>
184
        /// <param name="clsid">The CLSID of the component.</param>
185
        /// <param name="fileType">
186
        /// The file type that the context menu handler is associated with. For 
187
        /// example, '*' means all file types; '.txt' means all .txt files. The 
188
        /// parameter must not be NULL or an empty string. 
189
        /// </param>
190
        /// <param name="friendlyName">The friendly name of the component.</param>
191
        public static void RegisterShellExtContextMenuHandler(Guid clsid,
192
            string fileType, string friendlyName)
193
        {
194
            if (clsid == Guid.Empty)
195
            {
196
                throw new ArgumentException("clsid must not be empty");
197
            }
198
            if (string.IsNullOrEmpty(fileType))
199
            {
200
                throw new ArgumentException("fileType must not be null or empty");
201
            }
202

    
203
            // If fileType starts with '.', try to read the default value of the 
204
            // HKCR\<File Type> key which contains the ProgID to which the file type 
205
            // is linked.
206
            if (fileType.StartsWith("."))
207
            {                                
208
                using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
209
                {
210
                    if (key != null)
211
                    {
212
                        // If the key exists and its default value is not empty, use 
213
                        // the ProgID as the file type.
214
                        string defaultVal = key.GetValue(null) as string;
215
                        if (!string.IsNullOrEmpty(defaultVal))
216
                        {
217
                            fileType = defaultVal;
218
                        }
219
                    }
220
                }
221
            }
222

    
223
            // Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
224
            string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
225
                fileType, friendlyName);
226
            using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(keyName))
227
            {
228
                // Set the default value of the key.
229
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
230
                {
231
                    key.SetValue(null, clsid.ToString("B"));
232
                }
233
            }
234
        }
235

    
236
        /// <summary>
237
        /// Unregister the context menu handler.
238
        /// </summary>
239
        /// <param name="clsid">The CLSID of the component.</param>
240
        /// <param name="fileType">
241
        /// The file type that the context menu handler is associated with. For 
242
        /// example, '*' means all file types; '.txt' means all .txt files. The 
243
        /// parameter must not be NULL or an empty string. 
244
        /// </param>
245
        public static void UnregisterShellExtContextMenuHandler(Guid clsid,
246
            string fileType, string friendlyName)
247
        {
248
            if (clsid == null)
249
            {
250
                throw new ArgumentException("clsid must not be null");
251
            }
252
            if (string.IsNullOrEmpty(fileType))
253
            {
254
                throw new ArgumentException("fileType must not be null or empty");
255
            }
256

    
257
            // If fileType starts with '.', try to read the default value of the 
258
            // HKCR\<File Type> key which contains the ProgID to which the file type 
259
            // is linked.
260
            if (fileType.StartsWith("."))
261
            {
262
                using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
263
                {
264
                    if (key != null)
265
                    {
266
                        // If the key exists and its default value is not empty, use 
267
                        // the ProgID as the file type.
268
                        string defaultVal = key.GetValue(null) as string;
269
                        if (!string.IsNullOrEmpty(defaultVal))
270
                        {
271
                            fileType = defaultVal;
272
                        }
273
                    }
274
                }
275
            }
276

    
277
            // Remove the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
278
            string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
279
                fileType, friendlyName);
280
            Registry.ClassesRoot.DeleteSubKeyTree(keyName, false);
281
        }
282

    
283
        public static void MarkApproved(Guid guid, string friendlyName)
284
        {
285
            Debug.WriteLine(String.Format("Marking approved {0} {1}", guid, friendlyName), LogCategories.Shell);
286
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(_approvedKey))
287
            {
288
                // Set the default value of the key.
289
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
290
                {
291
                    key.SetValue(guid.ToString("B"), friendlyName, RegistryValueKind.String);
292
                }
293
                else
294
                {
295
                    Debug.WriteLine("Error - failed to open key " + _approvedKey,LogCategories.Shell);
296
                }
297
            }
298
        }
299

    
300
        public static void RemoveApproved(Guid guid)
301
        {
302
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(_approvedKey))
303
            {
304
                // Set the default value of the key.
305
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
306
                {
307
                    key.DeleteValue(guid.ToString("B"), false);
308
                }
309
                else
310
                {
311
                    Debug.WriteLine("Error - failed to open key " + _approvedKey, LogCategories.Shell);
312
                }
313
            }
314
        }
315
    }
316

    
317
    #endregion
318

    
319

    
320
    #region Enums & Structs
321

    
322
    #region enum HChangeNotifyEventID
323
    /// <summary>
324
    /// Describes the event that has occurred. 
325
    /// Typically, only one event is specified at a time. 
326
    /// If more than one event is specified, the values contained 
327
    /// in the <i>dwItem1</i> and <i>dwItem2</i> 
328
    /// parameters must be the same, respectively, for all specified events. 
329
    /// This parameter can be one or more of the following values. 
330
    /// </summary>
331
    /// <remarks>
332
    /// <para><b>Windows NT/2000/XP:</b> <i>dwItem2</i> contains the index 
333
    /// in the system image list that has changed. 
334
    /// <i>dwItem1</i> is not used and should be <see langword="null"/>.</para>
335
    /// <para><b>Windows 95/98:</b> <i>dwItem1</i> contains the index 
336
    /// in the system image list that has changed. 
337
    /// <i>dwItem2</i> is not used and should be <see langword="null"/>.</para>
338
    /// </remarks>
339
    [Flags]
340
    enum HChangeNotifyEventID
341
    {
342
        /// <summary>
343
        /// All events have occurred. 
344
        /// </summary>
345
        SHCNE_ALLEVENTS = 0x7FFFFFFF,
346

    
347
        /// <summary>
348
        /// A file type association has changed. <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> 
349
        /// must be specified in the <i>uFlags</i> parameter. 
350
        /// <i>dwItem1</i> and <i>dwItem2</i> are not used and must be <see langword="null"/>. 
351
        /// </summary>
352
        SHCNE_ASSOCCHANGED = 0x08000000,
353

    
354
        /// <summary>
355
        /// The attributes of an item or folder have changed. 
356
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
357
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
358
        /// <i>dwItem1</i> contains the item or folder that has changed. 
359
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>.
360
        /// </summary>
361
        SHCNE_ATTRIBUTES = 0x00000800,
362

    
363
        /// <summary>
364
        /// A nonfolder item has been created. 
365
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
366
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
367
        /// <i>dwItem1</i> contains the item that was created. 
368
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>.
369
        /// </summary>
370
        SHCNE_CREATE = 0x00000002,
371

    
372
        /// <summary>
373
        /// A nonfolder item has been deleted. 
374
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
375
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
376
        /// <i>dwItem1</i> contains the item that was deleted. 
377
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
378
        /// </summary>
379
        SHCNE_DELETE = 0x00000004,
380

    
381
        /// <summary>
382
        /// A drive has been added. 
383
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
384
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
385
        /// <i>dwItem1</i> contains the root of the drive that was added. 
386
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
387
        /// </summary>
388
        SHCNE_DRIVEADD = 0x00000100,
389

    
390
        /// <summary>
391
        /// A drive has been added and the Shell should create a new window for the drive. 
392
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
393
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
394
        /// <i>dwItem1</i> contains the root of the drive that was added. 
395
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
396
        /// </summary>
397
        SHCNE_DRIVEADDGUI = 0x00010000,
398

    
399
        /// <summary>
400
        /// A drive has been removed. <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
401
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
402
        /// <i>dwItem1</i> contains the root of the drive that was removed.
403
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
404
        /// </summary>
405
        SHCNE_DRIVEREMOVED = 0x00000080,
406

    
407
        /// <summary>
408
        /// Not currently used. 
409
        /// </summary>
410
        SHCNE_EXTENDED_EVENT = 0x04000000,
411

    
412
        /// <summary>
413
        /// The amount of free space on a drive has changed. 
414
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
415
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
416
        /// <i>dwItem1</i> contains the root of the drive on which the free space changed.
417
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
418
        /// </summary>
419
        SHCNE_FREESPACE = 0x00040000,
420

    
421
        /// <summary>
422
        /// Storage media has been inserted into a drive. 
423
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
424
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
425
        /// <i>dwItem1</i> contains the root of the drive that contains the new media. 
426
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
427
        /// </summary>
428
        SHCNE_MEDIAINSERTED = 0x00000020,
429

    
430
        /// <summary>
431
        /// Storage media has been removed from a drive. 
432
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
433
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
434
        /// <i>dwItem1</i> contains the root of the drive from which the media was removed. 
435
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
436
        /// </summary>
437
        SHCNE_MEDIAREMOVED = 0x00000040,
438

    
439
        /// <summary>
440
        /// A folder has been created. <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> 
441
        /// or <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
442
        /// <i>dwItem1</i> contains the folder that was created. 
443
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
444
        /// </summary>
445
        SHCNE_MKDIR = 0x00000008,
446

    
447
        /// <summary>
448
        /// A folder on the local computer is being shared via the network. 
449
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
450
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
451
        /// <i>dwItem1</i> contains the folder that is being shared. 
452
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
453
        /// </summary>
454
        SHCNE_NETSHARE = 0x00000200,
455

    
456
        /// <summary>
457
        /// A folder on the local computer is no longer being shared via the network. 
458
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
459
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
460
        /// <i>dwItem1</i> contains the folder that is no longer being shared. 
461
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
462
        /// </summary>
463
        SHCNE_NETUNSHARE = 0x00000400,
464

    
465
        /// <summary>
466
        /// The name of a folder has changed. 
467
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
468
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
469
        /// <i>dwItem1</i> contains the previous pointer to an item identifier list (PIDL) or name of the folder. 
470
        /// <i>dwItem2</i> contains the new PIDL or name of the folder. 
471
        /// </summary>
472
        SHCNE_RENAMEFOLDER = 0x00020000,
473

    
474
        /// <summary>
475
        /// The name of a nonfolder item has changed. 
476
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
477
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
478
        /// <i>dwItem1</i> contains the previous PIDL or name of the item. 
479
        /// <i>dwItem2</i> contains the new PIDL or name of the item. 
480
        /// </summary>
481
        SHCNE_RENAMEITEM = 0x00000001,
482

    
483
        /// <summary>
484
        /// A folder has been removed. 
485
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
486
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
487
        /// <i>dwItem1</i> contains the folder that was removed. 
488
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
489
        /// </summary>
490
        SHCNE_RMDIR = 0x00000010,
491

    
492
        /// <summary>
493
        /// The computer has disconnected from a server. 
494
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
495
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
496
        /// <i>dwItem1</i> contains the server from which the computer was disconnected. 
497
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
498
        /// </summary>
499
        SHCNE_SERVERDISCONNECT = 0x00004000,
500

    
501
        /// <summary>
502
        /// The contents of an existing folder have changed, 
503
        /// but the folder still exists and has not been renamed. 
504
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
505
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
506
        /// <i>dwItem1</i> contains the folder that has changed. 
507
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
508
        /// If a folder has been created, deleted, or renamed, use SHCNE_MKDIR, SHCNE_RMDIR, or 
509
        /// SHCNE_RENAMEFOLDER, respectively, instead. 
510
        /// </summary>
511
        SHCNE_UPDATEDIR = 0x00001000,
512

    
513
        /// <summary>
514
        /// An image in the system image list has changed. 
515
        /// <see cref="HChangeNotifyFlags.SHCNF_DWORD"/> must be specified in <i>uFlags</i>. 
516
        /// </summary>
517
        SHCNE_UPDATEIMAGE = 0x00008000,
518

    
519
    }
520
    #endregion // enum HChangeNotifyEventID
521

    
522
    #region public enum HChangeNotifyFlags
523
    /// <summary>
524
    /// Flags that indicate the meaning of the <i>dwItem1</i> and <i>dwItem2</i> parameters. 
525
    /// The uFlags parameter must be one of the following values.
526
    /// </summary>
527
    [Flags]
528
    public enum HChangeNotifyFlags
529
    {
530
        /// <summary>
531
        /// The <i>dwItem1</i> and <i>dwItem2</i> parameters are DWORD values. 
532
        /// </summary>
533
        SHCNF_DWORD = 0x0003,
534
        /// <summary>
535
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of ITEMIDLIST structures that 
536
        /// represent the item(s) affected by the change. 
537
        /// Each ITEMIDLIST must be relative to the desktop folder. 
538
        /// </summary>
539
        SHCNF_IDLIST = 0x0000,
540
        /// <summary>
541
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of null-terminated strings of 
542
        /// maximum length MAX_PATH that contain the full path names 
543
        /// of the items affected by the change. 
544
        /// </summary>
545
        SHCNF_PATHA = 0x0001,
546
        /// <summary>
547
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of null-terminated strings of 
548
        /// maximum length MAX_PATH that contain the full path names 
549
        /// of the items affected by the change. 
550
        /// </summary>
551
        SHCNF_PATHW = 0x0005,
552
        /// <summary>
553
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of null-terminated strings that 
554
        /// represent the friendly names of the printer(s) affected by the change. 
555
        /// </summary>
556
        SHCNF_PRINTERA = 0x0002,
557
        /// <summary>
558
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of null-terminated strings that 
559
        /// represent the friendly names of the printer(s) affected by the change. 
560
        /// </summary>
561
        SHCNF_PRINTERW = 0x0006,
562
        /// <summary>
563
        /// The function should not return until the notification 
564
        /// has been delivered to all affected components. 
565
        /// As this flag modifies other data-type flags, it cannot by used by itself.
566
        /// </summary>
567
        SHCNF_FLUSH = 0x1000,
568
        /// <summary>
569
        /// The function should begin delivering notifications to all affected components 
570
        /// but should return as soon as the notification process has begun. 
571
        /// As this flag modifies other data-type flags, it cannot by used by itself.
572
        /// </summary>
573
        SHCNF_FLUSHNOWAIT = 0x2000
574
    }
575
    #endregion // enum HChangeNotifyFlags
576

    
577
    internal enum GCS : uint
578
    {
579
        GCS_VERBA = 0x00000000,
580
        GCS_HELPTEXTA = 0x00000001,
581
        GCS_VALIDATEA = 0x00000002,
582
        GCS_VERBW = 0x00000004,
583
        GCS_HELPTEXTW = 0x00000005,
584
        GCS_VALIDATEW = 0x00000006,
585
        GCS_VERBICONW = 0x00000014,
586
        GCS_UNICODE = 0x00000004
587
    }
588

    
589
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
590
    internal struct CMINVOKECOMMANDINFO
591
    {
592
        public uint cbSize;
593
        public CMIC fMask;
594
        public IntPtr hwnd;
595
        public IntPtr verb;
596
        [MarshalAs(UnmanagedType.LPStr)]
597
        public string parameters;
598
        [MarshalAs(UnmanagedType.LPStr)]
599
        public string directory;
600
        public int nShow;
601
        public uint dwHotKey;
602
        public IntPtr hIcon;
603
    }
604

    
605
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
606
    internal struct CMINVOKECOMMANDINFOEX
607
    {
608
        public uint cbSize;
609
        public CMIC fMask;
610
        public IntPtr hwnd;
611
        public IntPtr verb;
612
        [MarshalAs(UnmanagedType.LPStr)]
613
        public string parameters;
614
        [MarshalAs(UnmanagedType.LPStr)]
615
        public string directory;
616
        public int nShow;
617
        public uint dwHotKey;
618
        public IntPtr hIcon;
619
        [MarshalAs(UnmanagedType.LPStr)]
620
        public string title;
621
        public IntPtr verbW;
622
        public string parametersW;
623
        public string directoryW;
624
        public string titleW;
625
        POINT ptInvoke;
626
    }
627

    
628
    [Flags]
629
    internal enum CMIC : uint
630
    {
631
        CMIC_MASK_ICON = 0x00000010,
632
        CMIC_MASK_HOTKEY = 0x00000020,
633
        CMIC_MASK_NOASYNC = 0x00000100,
634
        CMIC_MASK_FLAG_NO_UI = 0x00000400,
635
        CMIC_MASK_UNICODE = 0x00004000,
636
        CMIC_MASK_NO_CONSOLE = 0x00008000,
637
        CMIC_MASK_ASYNCOK = 0x00100000,
638
        CMIC_MASK_NOZONECHECKS = 0x00800000,
639
        CMIC_MASK_FLAG_LOG_USAGE = 0x04000000,
640
        CMIC_MASK_SHIFT_DOWN = 0x10000000,
641
        CMIC_MASK_PTINVOKE = 0x20000000,
642
        CMIC_MASK_CONTROL_DOWN = 0x40000000
643
    }
644

    
645
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
646
    public struct POINT
647
    {
648
        public int X;
649
        public int Y;
650
    }
651

    
652
    internal enum CLIPFORMAT : uint
653
    {
654
        CF_TEXT = 1,
655
        CF_BITMAP = 2,
656
        CF_METAFILEPICT = 3,
657
        CF_SYLK = 4,
658
        CF_DIF = 5,
659
        CF_TIFF = 6,
660
        CF_OEMTEXT = 7,
661
        CF_DIB = 8,
662
        CF_PALETTE = 9,
663
        CF_PENDATA = 10,
664
        CF_RIFF = 11,
665
        CF_WAVE = 12,
666
        CF_UNICODETEXT = 13,
667
        CF_ENHMETAFILE = 14,
668
        CF_HDROP = 15,
669
        CF_LOCALE = 16,
670
        CF_MAX = 17,
671

    
672
        CF_OWNERDISPLAY = 0x0080,
673
        CF_DSPTEXT = 0x0081,
674
        CF_DSPBITMAP = 0x0082,
675
        CF_DSPMETAFILEPICT = 0x0083,
676
        CF_DSPENHMETAFILE = 0x008E,
677

    
678
        CF_PRIVATEFIRST = 0x0200,
679
        CF_PRIVATELAST = 0x02FF,
680

    
681
        CF_GDIOBJFIRST = 0x0300,
682
        CF_GDIOBJLAST = 0x03FF
683
    }
684

    
685
    [Flags]
686
    internal enum CMF : uint
687
    {
688
        CMF_NORMAL = 0x00000000,
689
        CMF_DEFAULTONLY = 0x00000001,
690
        CMF_VERBSONLY = 0x00000002,
691
        CMF_EXPLORE = 0x00000004,
692
        CMF_NOVERBS = 0x00000008,
693
        CMF_CANRENAME = 0x00000010,
694
        CMF_NODEFAULT = 0x00000020,
695
        CMF_INCLUDESTATIC = 0x00000040,
696
        CMF_ITEMMENU = 0x00000080,
697
        CMF_EXTENDEDVERBS = 0x00000100,
698
        CMF_DISABLEDVERBS = 0x00000200,
699
        CMF_ASYNCVERBSTATE = 0x00000400,
700
        CMF_OPTIMIZEFORINVOKE = 0x00000800,
701
        CMF_SYNCCASCADEMENU = 0x00001000,
702
        CMF_DONOTPICKDEFAULT = 0x00002000,
703
        CMF_RESERVED = 0xFFFF0000
704
    }
705

    
706
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
707
    internal struct MENUITEMINFO
708
    {
709
        public uint cbSize;
710
        public MIIM fMask;
711
        public MFT fType;
712
        public MFS fState;
713
        public uint wID;
714
        public IntPtr hSubMenu;
715
        public IntPtr hbmpChecked;
716
        public IntPtr hbmpUnchecked;
717
        public UIntPtr dwItemData;
718
        public string dwTypeData;
719
        public uint cch;
720
        public IntPtr hbmpItem;
721
    }
722

    
723
    [Flags]
724
    internal enum MIIM : uint
725
    {
726
        MIIM_STATE = 0x00000001,
727
        MIIM_ID = 0x00000002,
728
        MIIM_SUBMENU = 0x00000004,
729
        MIIM_CHECKMARKS = 0x00000008,
730
        MIIM_TYPE = 0x00000010,
731
        MIIM_DATA = 0x00000020,
732
        MIIM_STRING = 0x00000040,
733
        MIIM_BITMAP = 0x00000080,
734
        MIIM_FTYPE = 0x00000100
735
    }
736
    [Flags]
737
    internal enum MFT : uint
738
    {
739
        MFT_STRING = 0x00000000,
740
        MFT_BITMAP = 0x00000004,
741
        MFT_MENUBARBREAK = 0x00000020,
742
        MFT_MENUBREAK = 0x00000040,
743
        MFT_OWNERDRAW = 0x00000100,
744
        MFT_RADIOCHECK = 0x00000200,
745
        MFT_SEPARATOR = 0x00000800,
746
        MFT_RIGHTORDER = 0x00002000,
747
        MFT_RIGHTJUSTIFY = 0x00004000
748
    }
749

    
750
    [Flags]
751
    internal enum MFS : uint
752
    {
753
        MFS_ENABLED = 0x00000000,
754
        MFS_UNCHECKED = 0x00000000,
755
        MFS_UNHILITE = 0x00000000,
756
        MFS_GRAYED = 0x00000003,
757
        MFS_DISABLED = 0x00000003,
758
        MFS_CHECKED = 0x00000008,
759
        MFS_HILITE = 0x00000080,
760
        MFS_DEFAULT = 0x00001000
761
    }
762

    
763
    [Flags]
764
    internal enum MF: uint
765
    {
766
        MF_BYCOMMAND    =   0x00000000,
767
        MF_ENABLED      =   0x00000000,
768
        MF_DISABLED     =   0x00000002,
769
        MF_BITMAP       =   0x00000004,
770
        MF_CHECKED      =   0x00000008,
771
        MF_BYPOSITION   =   0x00000400,
772
        MF_SEPARATOR    =   0x00000800
773
    }
774

    
775
    #endregion
776

    
777

    
778
    internal class NativeMethods
779
    {
780
        /// <summary>
781
        /// Retrieve the names of dropped files that result from a successful drag-
782
        /// and-drop operation.
783
        /// </summary>
784
        /// <param name="hDrop">
785
        /// Identifier of the structure that contains the file names of the dropped 
786
        /// files.
787
        /// </param>
788
        /// <param name="iFile">
789
        /// Index of the file to query. If the value of this parameter is 0xFFFFFFFF, 
790
        /// DragQueryFile returns a count of the files dropped. 
791
        /// </param>
792
        /// <param name="pszFile">
793
        /// The address of a buffer that receives the file name of a dropped file 
794
        /// when the function returns.
795
        /// </param>
796
        /// <param name="cch">
797
        /// The size, in characters, of the pszFile buffer.
798
        /// </param>
799
        /// <returns>A non-zero value indicates a successful call.</returns>
800
        [DllImport("shell32", CharSet = CharSet.Unicode)]
801
        public static extern uint DragQueryFile(
802
            IntPtr hDrop,
803
            uint iFile,
804
            StringBuilder pszFile,
805
            int cch);
806

    
807
        /// <summary>
808
        /// Free the specified storage medium.
809
        /// </summary>
810
        /// <param name="pmedium">
811
        /// Reference of the storage medium that is to be freed.
812
        /// </param>
813
        [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
814
        public static extern void ReleaseStgMedium(ref STGMEDIUM pmedium);
815

    
816
        /// <summary>
817
        /// Insert a new menu item at the specified position in a menu.
818
        /// </summary>
819
        /// <param name="hMenu">
820
        /// A handle to the menu in which the new menu item is inserted. 
821
        /// </param>
822
        /// <param name="uItem">
823
        /// The identifier or position of the menu item before which to insert the 
824
        /// new item. The meaning of this parameter depends on the value of 
825
        /// fByPosition.
826
        /// </param>
827
        /// <param name="fByPosition">
828
        /// Controls the meaning of uItem. If this parameter is false, uItem is a 
829
        /// menu item identifier. Otherwise, it is a menu item position. 
830
        /// </param>
831
        /// <param name="mii">
832
        /// A reference of a MENUITEMINFO structure that contains information about 
833
        /// the new menu item.
834
        /// </param>
835
        /// <returns>
836
        /// If the function succeeds, the return value is true.
837
        /// </returns>
838
        [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
839
        [return: MarshalAs(UnmanagedType.Bool)]
840
        public static extern bool InsertMenuItem(
841
            IntPtr hMenu,
842
            uint uItem,
843
            [MarshalAs(UnmanagedType.Bool)]bool fByPosition,
844
            ref MENUITEMINFO mii);
845
        
846
        [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
847
        [return: MarshalAs(UnmanagedType.Bool)]
848
        public static extern bool InsertMenu(
849
            IntPtr hMenu,
850
            uint uPosition,
851
            MF uFlags,
852
            uint uIDNewItem,
853
            string lpNewItem);
854

    
855

    
856
        [DllImport("shell32", CharSet = CharSet.Unicode, SetLastError = true)]
857
        [return: MarshalAs(UnmanagedType.Bool)]
858
        public static extern bool SHGetPathFromIDList(
859
            IntPtr pidl,
860
            StringBuilder pszpath);
861

    
862
        [DllImport("shell32.dll")]
863
        public static extern void SHChangeNotify(HChangeNotifyEventID wEventId,
864
                                           HChangeNotifyFlags uFlags,
865
                                           IntPtr dwItem1,
866
                                           IntPtr dwItem2);
867

    
868
        [DllImport("gdi32.dll")]
869
        public static extern bool DeleteObject(IntPtr hObject);
870

    
871

    
872

    
873
        public static int HighWord(int number)
874
        {
875
            return ((number & 0x80000000) == 0x80000000) ?
876
                (number >> 16) : ((number >> 16) & 0xffff);
877
        }
878

    
879
        public static int LowWord(int number)
880
        {
881
            return number & 0xffff;
882
        }
883
    }
884

    
885
    internal static class WinError
886
    {
887
        public const int S_OK = 0x0000;
888
        public const int S_FALSE = 0x0001;
889
        public const int E_FAIL = -2147467259;
890
        public const int E_INVALIDARG = -2147024809;
891
        public const int E_OUTOFMEMORY = -2147024882;
892
        public const int STRSAFE_E_INSUFFICIENT_BUFFER = -2147024774;
893

    
894
        public const uint SEVERITY_SUCCESS = 0;
895
        public const uint SEVERITY_ERROR = 1;
896

    
897
        /// <summary>
898
        /// Create an HRESULT value from component pieces.
899
        /// </summary>
900
        /// <param name="sev">The severity to be used</param>
901
        /// <param name="fac">The facility to be used</param>
902
        /// <param name="code">The error number</param>
903
        /// <returns>A HRESULT constructed from the above 3 values</returns>
904
        public static int MAKE_HRESULT(uint sev, uint fac, uint code)
905
        {
906
            return (int)((sev << 31) | (fac << 16) | code);
907
        }
908
    }
909
}