Statistics
| Branch: | Revision:

root / trunk / Pithos.ShellExtensions / ShellExtLib.cs @ 5bcf6d70

History | View | Annotate | Download (31 kB)

1
using System;
2
using System.Diagnostics;
3
using System.Text;
4
using Microsoft.Win32;
5
using System.Runtime.InteropServices;
6
using System.Runtime.InteropServices.ComTypes;
7

    
8

    
9
namespace Pithos.ShellExtensions
10
{
11
    #region Shell Interfaces
12
    [Flags]
13
    public enum ISIOI
14
    {
15
        ISIOI_ICONFILE = 1,
16
        ISIOI_ICONINDEX = 2
17
    }
18

    
19
    [ComVisible(false)]
20
    [ComImport]
21
    [Guid("0C6C4200-C589-11D0-999A-00C04FD655E1")]
22
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
23
    public interface IShellIconOverlayIdentifier
24
    {
25

    
26
        [PreserveSig]
27
        int IsMemberOf(
28
            [MarshalAs(UnmanagedType.LPWStr)] string path,
29

    
30
            uint attributes);
31

    
32
        [PreserveSig]
33
        int GetOverlayInfo(
34
            IntPtr iconFileBuffer,
35
            int iconFileBufferSize,
36
            out int iconIndex,
37
            out uint flags);
38

    
39
        [PreserveSig]
40
        int GetPriority(
41
            out int priority);
42

    
43
    }
44

    
45

    
46

    
47
    [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
48
    [Guid("000214e8-0000-0000-c000-000000000046")]
49
    internal interface IShellExtInit
50
    {
51
        void Initialize(
52
            IntPtr /*LPCITEMIDLIST*/ pidlFolder,
53
            IntPtr /*LPDATAOBJECT*/ pDataObj,
54
            IntPtr /*HKEY*/ hKeyProgID);
55
    }
56

    
57

    
58
    [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
59
    [Guid("000214e4-0000-0000-c000-000000000046")]
60
    internal interface IContextMenu
61
    {
62
        [PreserveSig]
63
        int QueryContextMenu(
64
            IntPtr /*HMENU*/ hMenu,
65
            uint iMenu,
66
            uint idCmdFirst,
67
            uint idCmdLast,
68
            uint uFlags);
69

    
70
        void InvokeCommand(IntPtr pici);
71

    
72
        void GetCommandString(
73
            UIntPtr idCmd,
74
            uint uFlags,
75
            IntPtr pReserved,
76
            StringBuilder pszName,
77
            uint cchMax);
78
    }
79

    
80
    #endregion
81

    
82

    
83
    #region Shell Registration
84

    
85
    internal class ShellExtReg
86
    {
87
        private const string _approvedKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved";
88

    
89
        public static void RegisterIconOverlayIdentifier(Guid clsid,
90
            string friendlyName)
91
        {
92
            if (clsid == Guid.Empty)
93
            {
94
                throw new ArgumentException("clsid must not be empty");
95
            }
96
            if (string.IsNullOrEmpty(friendlyName))
97
            {
98
                throw new ArgumentException("friendlyName must not be null or empty");
99
            }
100

    
101
            // Create the key HKLM\SOFTWARE\TortoiseOverlays\<IconName>\Pithos={<CLSID>}.
102
            string keyName = string.Format(@"SOFTWARE\TortoiseOverlays\{0}",
103
                friendlyName);
104
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyName,true))
105
            {
106
                // Set the default value of the key.
107
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
108
                {
109
                    key.SetValue("Pithos", clsid.ToString("B"),RegistryValueKind.String);
110
                }
111
            }
112
        }
113

    
114
        internal static void UnregisterIconOverlayIdentifier(Guid clsid,
115
            string friendlyName)
116
        {
117
            if (clsid == null)
118
            {
119
                throw new ArgumentException("clsid must not be null");
120
            }
121
            if (string.IsNullOrEmpty(friendlyName))
122
            {
123
                throw new ArgumentException("friendlyName must not be null or empty");
124
            }
125

    
126

    
127
            string keyName = string.Format(@"SOFTWARE\TortoiseOverlays\{0}",
128
                friendlyName);
129
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(keyName, true))
130
            {
131
                // Set the default value of the key.
132
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
133
                {
134
                    key.DeleteValue("Pithos");
135
                }
136
            }
137
        }
138

    
139

    
140
        /// <summary>
141
        /// Register the context menu handler.
142
        /// </summary>
143
        /// <param name="clsid">The CLSID of the component.</param>
144
        /// <param name="fileType">
145
        /// The file type that the context menu handler is associated with. For 
146
        /// example, '*' means all file types; '.txt' means all .txt files. The 
147
        /// parameter must not be NULL or an empty string. 
148
        /// </param>
149
        /// <param name="friendlyName">The friendly name of the component.</param>
150
        public static void RegisterShellExtContextMenuHandler(Guid clsid,
151
            string fileType, string friendlyName)
152
        {
153
            if (clsid == Guid.Empty)
154
            {
155
                throw new ArgumentException("clsid must not be empty");
156
            }
157
            if (string.IsNullOrEmpty(fileType))
158
            {
159
                throw new ArgumentException("fileType must not be null or empty");
160
            }
161

    
162
            // If fileType starts with '.', try to read the default value of the 
163
            // HKCR\<File Type> key which contains the ProgID to which the file type 
164
            // is linked.
165
            if (fileType.StartsWith("."))
166
            {
167
                using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
168
                {
169
                    if (key != null)
170
                    {
171
                        // If the key exists and its default value is not empty, use 
172
                        // the ProgID as the file type.
173
                        string defaultVal = key.GetValue(null) as string;
174
                        if (!string.IsNullOrEmpty(defaultVal))
175
                        {
176
                            fileType = defaultVal;
177
                        }
178
                    }
179
                }
180
            }
181

    
182
            // Create the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
183
            string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
184
                fileType, friendlyName);
185
            using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(keyName))
186
            {
187
                // Set the default value of the key.
188
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
189
                {
190
                    key.SetValue(null, clsid.ToString("B"));
191
                }
192
            }
193
        }
194

    
195
        /// <summary>
196
        /// Unregister the context menu handler.
197
        /// </summary>
198
        /// <param name="clsid">The CLSID of the component.</param>
199
        /// <param name="fileType">
200
        /// The file type that the context menu handler is associated with. For 
201
        /// example, '*' means all file types; '.txt' means all .txt files. The 
202
        /// parameter must not be NULL or an empty string. 
203
        /// </param>
204
        public static void UnregisterShellExtContextMenuHandler(Guid clsid,
205
            string fileType, string friendlyName)
206
        {
207
            if (clsid == null)
208
            {
209
                throw new ArgumentException("clsid must not be null");
210
            }
211
            if (string.IsNullOrEmpty(fileType))
212
            {
213
                throw new ArgumentException("fileType must not be null or empty");
214
            }
215

    
216
            // If fileType starts with '.', try to read the default value of the 
217
            // HKCR\<File Type> key which contains the ProgID to which the file type 
218
            // is linked.
219
            if (fileType.StartsWith("."))
220
            {
221
                using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(fileType))
222
                {
223
                    if (key != null)
224
                    {
225
                        // If the key exists and its default value is not empty, use 
226
                        // the ProgID as the file type.
227
                        string defaultVal = key.GetValue(null) as string;
228
                        if (!string.IsNullOrEmpty(defaultVal))
229
                        {
230
                            fileType = defaultVal;
231
                        }
232
                    }
233
                }
234
            }
235

    
236
            // Remove the key HKCR\<File Type>\shellex\ContextMenuHandlers\{<CLSID>}.
237
            string keyName = string.Format(@"{0}\shellex\ContextMenuHandlers\{1}",
238
                fileType, friendlyName);
239
            Registry.ClassesRoot.DeleteSubKeyTree(keyName, false);
240
        }
241

    
242
        public static void MarkApproved(Guid guid, string friendlyName)
243
        {
244
            Trace.Write(String.Format("Marking approved {0} {1}", guid, friendlyName));
245
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(_approvedKey))
246
            {
247
                // Set the default value of the key.
248
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
249
                {
250
                    key.SetValue(guid.ToString("B"), friendlyName, RegistryValueKind.String);
251
                }
252
                else
253
                {
254
                    Trace.Write("Error - failed to open key " + _approvedKey);
255
                }
256
            }
257
        }
258

    
259
        public static void RemoveApproved(Guid guid, string csshellextcontextmenuhandlerFilecontextmenuext)
260
        {
261
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey(_approvedKey))
262
            {
263
                // Set the default value of the key.
264
                if (key != null)//&& !string.IsNullOrEmpty(clsid.ToString("B")))
265
                {
266
                    key.DeleteValue(guid.ToString("B"), false);
267
                }
268
                else
269
                {
270
                    Trace.Write("Error - failed to open key " + _approvedKey);
271
                }
272
            }
273
        }
274
    }
275

    
276
    #endregion
277

    
278

    
279
    #region Enums & Structs
280

    
281
    #region enum HChangeNotifyEventID
282
    /// <summary>
283
    /// Describes the event that has occurred. 
284
    /// Typically, only one event is specified at a time. 
285
    /// If more than one event is specified, the values contained 
286
    /// in the <i>dwItem1</i> and <i>dwItem2</i> 
287
    /// parameters must be the same, respectively, for all specified events. 
288
    /// This parameter can be one or more of the following values. 
289
    /// </summary>
290
    /// <remarks>
291
    /// <para><b>Windows NT/2000/XP:</b> <i>dwItem2</i> contains the index 
292
    /// in the system image list that has changed. 
293
    /// <i>dwItem1</i> is not used and should be <see langword="null"/>.</para>
294
    /// <para><b>Windows 95/98:</b> <i>dwItem1</i> contains the index 
295
    /// in the system image list that has changed. 
296
    /// <i>dwItem2</i> is not used and should be <see langword="null"/>.</para>
297
    /// </remarks>
298
    [Flags]
299
    enum HChangeNotifyEventID
300
    {
301
        /// <summary>
302
        /// All events have occurred. 
303
        /// </summary>
304
        SHCNE_ALLEVENTS = 0x7FFFFFFF,
305

    
306
        /// <summary>
307
        /// A file type association has changed. <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> 
308
        /// must be specified in the <i>uFlags</i> parameter. 
309
        /// <i>dwItem1</i> and <i>dwItem2</i> are not used and must be <see langword="null"/>. 
310
        /// </summary>
311
        SHCNE_ASSOCCHANGED = 0x08000000,
312

    
313
        /// <summary>
314
        /// The attributes of an item or folder have changed. 
315
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
316
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
317
        /// <i>dwItem1</i> contains the item or folder that has changed. 
318
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>.
319
        /// </summary>
320
        SHCNE_ATTRIBUTES = 0x00000800,
321

    
322
        /// <summary>
323
        /// A nonfolder item has been created. 
324
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
325
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
326
        /// <i>dwItem1</i> contains the item that was created. 
327
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>.
328
        /// </summary>
329
        SHCNE_CREATE = 0x00000002,
330

    
331
        /// <summary>
332
        /// A nonfolder item has been deleted. 
333
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
334
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
335
        /// <i>dwItem1</i> contains the item that was deleted. 
336
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
337
        /// </summary>
338
        SHCNE_DELETE = 0x00000004,
339

    
340
        /// <summary>
341
        /// A drive has been added. 
342
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
343
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
344
        /// <i>dwItem1</i> contains the root of the drive that was added. 
345
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
346
        /// </summary>
347
        SHCNE_DRIVEADD = 0x00000100,
348

    
349
        /// <summary>
350
        /// A drive has been added and the Shell should create a new window for the drive. 
351
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
352
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
353
        /// <i>dwItem1</i> contains the root of the drive that was added. 
354
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
355
        /// </summary>
356
        SHCNE_DRIVEADDGUI = 0x00010000,
357

    
358
        /// <summary>
359
        /// A drive has been removed. <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
360
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
361
        /// <i>dwItem1</i> contains the root of the drive that was removed.
362
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
363
        /// </summary>
364
        SHCNE_DRIVEREMOVED = 0x00000080,
365

    
366
        /// <summary>
367
        /// Not currently used. 
368
        /// </summary>
369
        SHCNE_EXTENDED_EVENT = 0x04000000,
370

    
371
        /// <summary>
372
        /// The amount of free space on a drive has changed. 
373
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
374
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
375
        /// <i>dwItem1</i> contains the root of the drive on which the free space changed.
376
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
377
        /// </summary>
378
        SHCNE_FREESPACE = 0x00040000,
379

    
380
        /// <summary>
381
        /// Storage media has been inserted into a drive. 
382
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
383
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
384
        /// <i>dwItem1</i> contains the root of the drive that contains the new media. 
385
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
386
        /// </summary>
387
        SHCNE_MEDIAINSERTED = 0x00000020,
388

    
389
        /// <summary>
390
        /// Storage media has been removed from a drive. 
391
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
392
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
393
        /// <i>dwItem1</i> contains the root of the drive from which the media was removed. 
394
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
395
        /// </summary>
396
        SHCNE_MEDIAREMOVED = 0x00000040,
397

    
398
        /// <summary>
399
        /// A folder has been created. <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> 
400
        /// or <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
401
        /// <i>dwItem1</i> contains the folder that was created. 
402
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
403
        /// </summary>
404
        SHCNE_MKDIR = 0x00000008,
405

    
406
        /// <summary>
407
        /// A folder on the local computer is being shared via the network. 
408
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
409
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
410
        /// <i>dwItem1</i> contains the folder that is being shared. 
411
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
412
        /// </summary>
413
        SHCNE_NETSHARE = 0x00000200,
414

    
415
        /// <summary>
416
        /// A folder on the local computer is no longer being shared via the network. 
417
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
418
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
419
        /// <i>dwItem1</i> contains the folder that is no longer being shared. 
420
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
421
        /// </summary>
422
        SHCNE_NETUNSHARE = 0x00000400,
423

    
424
        /// <summary>
425
        /// The name of a folder has changed. 
426
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
427
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
428
        /// <i>dwItem1</i> contains the previous pointer to an item identifier list (PIDL) or name of the folder. 
429
        /// <i>dwItem2</i> contains the new PIDL or name of the folder. 
430
        /// </summary>
431
        SHCNE_RENAMEFOLDER = 0x00020000,
432

    
433
        /// <summary>
434
        /// The name of a nonfolder item has changed. 
435
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
436
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
437
        /// <i>dwItem1</i> contains the previous PIDL or name of the item. 
438
        /// <i>dwItem2</i> contains the new PIDL or name of the item. 
439
        /// </summary>
440
        SHCNE_RENAMEITEM = 0x00000001,
441

    
442
        /// <summary>
443
        /// A folder has been removed. 
444
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
445
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
446
        /// <i>dwItem1</i> contains the folder that was removed. 
447
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
448
        /// </summary>
449
        SHCNE_RMDIR = 0x00000010,
450

    
451
        /// <summary>
452
        /// The computer has disconnected from a server. 
453
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
454
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
455
        /// <i>dwItem1</i> contains the server from which the computer was disconnected. 
456
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
457
        /// </summary>
458
        SHCNE_SERVERDISCONNECT = 0x00004000,
459

    
460
        /// <summary>
461
        /// The contents of an existing folder have changed, 
462
        /// but the folder still exists and has not been renamed. 
463
        /// <see cref="HChangeNotifyFlags.SHCNF_IDLIST"/> or 
464
        /// <see cref="HChangeNotifyFlags.SHCNF_PATH"/> must be specified in <i>uFlags</i>. 
465
        /// <i>dwItem1</i> contains the folder that has changed. 
466
        /// <i>dwItem2</i> is not used and should be <see langword="null"/>. 
467
        /// If a folder has been created, deleted, or renamed, use SHCNE_MKDIR, SHCNE_RMDIR, or 
468
        /// SHCNE_RENAMEFOLDER, respectively, instead. 
469
        /// </summary>
470
        SHCNE_UPDATEDIR = 0x00001000,
471

    
472
        /// <summary>
473
        /// An image in the system image list has changed. 
474
        /// <see cref="HChangeNotifyFlags.SHCNF_DWORD"/> must be specified in <i>uFlags</i>. 
475
        /// </summary>
476
        SHCNE_UPDATEIMAGE = 0x00008000,
477

    
478
    }
479
    #endregion // enum HChangeNotifyEventID
480

    
481
    #region public enum HChangeNotifyFlags
482
    /// <summary>
483
    /// Flags that indicate the meaning of the <i>dwItem1</i> and <i>dwItem2</i> parameters. 
484
    /// The uFlags parameter must be one of the following values.
485
    /// </summary>
486
    [Flags]
487
    public enum HChangeNotifyFlags
488
    {
489
        /// <summary>
490
        /// The <i>dwItem1</i> and <i>dwItem2</i> parameters are DWORD values. 
491
        /// </summary>
492
        SHCNF_DWORD = 0x0003,
493
        /// <summary>
494
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of ITEMIDLIST structures that 
495
        /// represent the item(s) affected by the change. 
496
        /// Each ITEMIDLIST must be relative to the desktop folder. 
497
        /// </summary>
498
        SHCNF_IDLIST = 0x0000,
499
        /// <summary>
500
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of null-terminated strings of 
501
        /// maximum length MAX_PATH that contain the full path names 
502
        /// of the items affected by the change. 
503
        /// </summary>
504
        SHCNF_PATHA = 0x0001,
505
        /// <summary>
506
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of null-terminated strings of 
507
        /// maximum length MAX_PATH that contain the full path names 
508
        /// of the items affected by the change. 
509
        /// </summary>
510
        SHCNF_PATHW = 0x0005,
511
        /// <summary>
512
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of null-terminated strings that 
513
        /// represent the friendly names of the printer(s) affected by the change. 
514
        /// </summary>
515
        SHCNF_PRINTERA = 0x0002,
516
        /// <summary>
517
        /// <i>dwItem1</i> and <i>dwItem2</i> are the addresses of null-terminated strings that 
518
        /// represent the friendly names of the printer(s) affected by the change. 
519
        /// </summary>
520
        SHCNF_PRINTERW = 0x0006,
521
        /// <summary>
522
        /// The function should not return until the notification 
523
        /// has been delivered to all affected components. 
524
        /// As this flag modifies other data-type flags, it cannot by used by itself.
525
        /// </summary>
526
        SHCNF_FLUSH = 0x1000,
527
        /// <summary>
528
        /// The function should begin delivering notifications to all affected components 
529
        /// but should return as soon as the notification process has begun. 
530
        /// As this flag modifies other data-type flags, it cannot by used by itself.
531
        /// </summary>
532
        SHCNF_FLUSHNOWAIT = 0x2000
533
    }
534
    #endregion // enum HChangeNotifyFlags
535

    
536
    internal enum GCS : uint
537
    {
538
        GCS_VERBA = 0x00000000,
539
        GCS_HELPTEXTA = 0x00000001,
540
        GCS_VALIDATEA = 0x00000002,
541
        GCS_VERBW = 0x00000004,
542
        GCS_HELPTEXTW = 0x00000005,
543
        GCS_VALIDATEW = 0x00000006,
544
        GCS_VERBICONW = 0x00000014,
545
        GCS_UNICODE = 0x00000004
546
    }
547

    
548
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
549
    internal struct CMINVOKECOMMANDINFO
550
    {
551
        public uint cbSize;
552
        public CMIC fMask;
553
        public IntPtr hwnd;
554
        public IntPtr verb;
555
        [MarshalAs(UnmanagedType.LPStr)]
556
        public string parameters;
557
        [MarshalAs(UnmanagedType.LPStr)]
558
        public string directory;
559
        public int nShow;
560
        public uint dwHotKey;
561
        public IntPtr hIcon;
562
    }
563

    
564
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
565
    internal struct CMINVOKECOMMANDINFOEX
566
    {
567
        public uint cbSize;
568
        public CMIC fMask;
569
        public IntPtr hwnd;
570
        public IntPtr verb;
571
        [MarshalAs(UnmanagedType.LPStr)]
572
        public string parameters;
573
        [MarshalAs(UnmanagedType.LPStr)]
574
        public string directory;
575
        public int nShow;
576
        public uint dwHotKey;
577
        public IntPtr hIcon;
578
        [MarshalAs(UnmanagedType.LPStr)]
579
        public string title;
580
        public IntPtr verbW;
581
        public string parametersW;
582
        public string directoryW;
583
        public string titleW;
584
        POINT ptInvoke;
585
    }
586

    
587
    [Flags]
588
    internal enum CMIC : uint
589
    {
590
        CMIC_MASK_ICON = 0x00000010,
591
        CMIC_MASK_HOTKEY = 0x00000020,
592
        CMIC_MASK_NOASYNC = 0x00000100,
593
        CMIC_MASK_FLAG_NO_UI = 0x00000400,
594
        CMIC_MASK_UNICODE = 0x00004000,
595
        CMIC_MASK_NO_CONSOLE = 0x00008000,
596
        CMIC_MASK_ASYNCOK = 0x00100000,
597
        CMIC_MASK_NOZONECHECKS = 0x00800000,
598
        CMIC_MASK_FLAG_LOG_USAGE = 0x04000000,
599
        CMIC_MASK_SHIFT_DOWN = 0x10000000,
600
        CMIC_MASK_PTINVOKE = 0x20000000,
601
        CMIC_MASK_CONTROL_DOWN = 0x40000000
602
    }
603

    
604
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
605
    public struct POINT
606
    {
607
        public int X;
608
        public int Y;
609
    }
610

    
611
    internal enum CLIPFORMAT : uint
612
    {
613
        CF_TEXT = 1,
614
        CF_BITMAP = 2,
615
        CF_METAFILEPICT = 3,
616
        CF_SYLK = 4,
617
        CF_DIF = 5,
618
        CF_TIFF = 6,
619
        CF_OEMTEXT = 7,
620
        CF_DIB = 8,
621
        CF_PALETTE = 9,
622
        CF_PENDATA = 10,
623
        CF_RIFF = 11,
624
        CF_WAVE = 12,
625
        CF_UNICODETEXT = 13,
626
        CF_ENHMETAFILE = 14,
627
        CF_HDROP = 15,
628
        CF_LOCALE = 16,
629
        CF_MAX = 17,
630

    
631
        CF_OWNERDISPLAY = 0x0080,
632
        CF_DSPTEXT = 0x0081,
633
        CF_DSPBITMAP = 0x0082,
634
        CF_DSPMETAFILEPICT = 0x0083,
635
        CF_DSPENHMETAFILE = 0x008E,
636

    
637
        CF_PRIVATEFIRST = 0x0200,
638
        CF_PRIVATELAST = 0x02FF,
639

    
640
        CF_GDIOBJFIRST = 0x0300,
641
        CF_GDIOBJLAST = 0x03FF
642
    }
643

    
644
    [Flags]
645
    internal enum CMF : uint
646
    {
647
        CMF_NORMAL = 0x00000000,
648
        CMF_DEFAULTONLY = 0x00000001,
649
        CMF_VERBSONLY = 0x00000002,
650
        CMF_EXPLORE = 0x00000004,
651
        CMF_NOVERBS = 0x00000008,
652
        CMF_CANRENAME = 0x00000010,
653
        CMF_NODEFAULT = 0x00000020,
654
        CMF_INCLUDESTATIC = 0x00000040,
655
        CMF_ITEMMENU = 0x00000080,
656
        CMF_EXTENDEDVERBS = 0x00000100,
657
        CMF_DISABLEDVERBS = 0x00000200,
658
        CMF_ASYNCVERBSTATE = 0x00000400,
659
        CMF_OPTIMIZEFORINVOKE = 0x00000800,
660
        CMF_SYNCCASCADEMENU = 0x00001000,
661
        CMF_DONOTPICKDEFAULT = 0x00002000,
662
        CMF_RESERVED = 0xFFFF0000
663
    }
664

    
665
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
666
    internal struct MENUITEMINFO
667
    {
668
        public uint cbSize;
669
        public MIIM fMask;
670
        public MFT fType;
671
        public MFS fState;
672
        public uint wID;
673
        public IntPtr hSubMenu;
674
        public IntPtr hbmpChecked;
675
        public IntPtr hbmpUnchecked;
676
        public UIntPtr dwItemData;
677
        public string dwTypeData;
678
        public uint cch;
679
        public IntPtr hbmpItem;
680
    }
681

    
682
    [Flags]
683
    internal enum MIIM : uint
684
    {
685
        MIIM_STATE = 0x00000001,
686
        MIIM_ID = 0x00000002,
687
        MIIM_SUBMENU = 0x00000004,
688
        MIIM_CHECKMARKS = 0x00000008,
689
        MIIM_TYPE = 0x00000010,
690
        MIIM_DATA = 0x00000020,
691
        MIIM_STRING = 0x00000040,
692
        MIIM_BITMAP = 0x00000080,
693
        MIIM_FTYPE = 0x00000100
694
    }
695

    
696
    internal enum MFT : uint
697
    {
698
        MFT_STRING = 0x00000000,
699
        MFT_BITMAP = 0x00000004,
700
        MFT_MENUBARBREAK = 0x00000020,
701
        MFT_MENUBREAK = 0x00000040,
702
        MFT_OWNERDRAW = 0x00000100,
703
        MFT_RADIOCHECK = 0x00000200,
704
        MFT_SEPARATOR = 0x00000800,
705
        MFT_RIGHTORDER = 0x00002000,
706
        MFT_RIGHTJUSTIFY = 0x00004000
707
    }
708

    
709
    internal enum MFS : uint
710
    {
711
        MFS_ENABLED = 0x00000000,
712
        MFS_UNCHECKED = 0x00000000,
713
        MFS_UNHILITE = 0x00000000,
714
        MFS_GRAYED = 0x00000003,
715
        MFS_DISABLED = 0x00000003,
716
        MFS_CHECKED = 0x00000008,
717
        MFS_HILITE = 0x00000080,
718
        MFS_DEFAULT = 0x00001000
719
    }
720

    
721
    #endregion
722

    
723

    
724
    internal class NativeMethods
725
    {
726
        /// <summary>
727
        /// Retrieve the names of dropped files that result from a successful drag-
728
        /// and-drop operation.
729
        /// </summary>
730
        /// <param name="hDrop">
731
        /// Identifier of the structure that contains the file names of the dropped 
732
        /// files.
733
        /// </param>
734
        /// <param name="iFile">
735
        /// Index of the file to query. If the value of this parameter is 0xFFFFFFFF, 
736
        /// DragQueryFile returns a count of the files dropped. 
737
        /// </param>
738
        /// <param name="pszFile">
739
        /// The address of a buffer that receives the file name of a dropped file 
740
        /// when the function returns.
741
        /// </param>
742
        /// <param name="cch">
743
        /// The size, in characters, of the pszFile buffer.
744
        /// </param>
745
        /// <returns>A non-zero value indicates a successful call.</returns>
746
        [DllImport("shell32", CharSet = CharSet.Unicode)]
747
        public static extern uint DragQueryFile(
748
            IntPtr hDrop,
749
            uint iFile,
750
            StringBuilder pszFile,
751
            int cch);
752

    
753
        /// <summary>
754
        /// Free the specified storage medium.
755
        /// </summary>
756
        /// <param name="pmedium">
757
        /// Reference of the storage medium that is to be freed.
758
        /// </param>
759
        [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
760
        public static extern void ReleaseStgMedium(ref STGMEDIUM pmedium);
761

    
762
        /// <summary>
763
        /// Insert a new menu item at the specified position in a menu.
764
        /// </summary>
765
        /// <param name="hMenu">
766
        /// A handle to the menu in which the new menu item is inserted. 
767
        /// </param>
768
        /// <param name="uItem">
769
        /// The identifier or position of the menu item before which to insert the 
770
        /// new item. The meaning of this parameter depends on the value of 
771
        /// fByPosition.
772
        /// </param>
773
        /// <param name="fByPosition">
774
        /// Controls the meaning of uItem. If this parameter is false, uItem is a 
775
        /// menu item identifier. Otherwise, it is a menu item position. 
776
        /// </param>
777
        /// <param name="mii">
778
        /// A reference of a MENUITEMINFO structure that contains information about 
779
        /// the new menu item.
780
        /// </param>
781
        /// <returns>
782
        /// If the function succeeds, the return value is true.
783
        /// </returns>
784
        [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
785
        [return: MarshalAs(UnmanagedType.Bool)]
786
        public static extern bool InsertMenuItem(
787
            IntPtr hMenu,
788
            uint uItem,
789
            [MarshalAs(UnmanagedType.Bool)]bool fByPosition,
790
            ref MENUITEMINFO mii);
791

    
792
        [DllImport("shell32", CharSet = CharSet.Unicode, SetLastError = true)]
793
        [return: MarshalAs(UnmanagedType.Bool)]
794
        public static extern bool SHGetPathFromIDList(
795
            IntPtr pidl,
796
            StringBuilder pszpath);
797

    
798
        [DllImport("shell32.dll")]
799
        public static extern void SHChangeNotify(HChangeNotifyEventID wEventId,
800
                                           HChangeNotifyFlags uFlags,
801
                                           IntPtr dwItem1,
802
                                           IntPtr dwItem2);
803

    
804
        [DllImport("gdi32.dll")]
805
        public static extern bool DeleteObject(IntPtr hObject);
806

    
807

    
808

    
809
        public static int HighWord(int number)
810
        {
811
            return ((number & 0x80000000) == 0x80000000) ?
812
                (number >> 16) : ((number >> 16) & 0xffff);
813
        }
814

    
815
        public static int LowWord(int number)
816
        {
817
            return number & 0xffff;
818
        }
819
    }
820

    
821
    internal static class WinError
822
    {
823
        public const int S_OK = 0x0000;
824
        public const int S_FALSE = 0x0001;
825
        public const int E_FAIL = -2147467259;
826
        public const int E_INVALIDARG = -2147024809;
827
        public const int E_OUTOFMEMORY = -2147024882;
828
        public const int STRSAFE_E_INSUFFICIENT_BUFFER = -2147024774;
829

    
830
        public const uint SEVERITY_SUCCESS = 0;
831
        public const uint SEVERITY_ERROR = 1;
832

    
833
        /// <summary>
834
        /// Create an HRESULT value from component pieces.
835
        /// </summary>
836
        /// <param name="sev">The severity to be used</param>
837
        /// <param name="fac">The facility to be used</param>
838
        /// <param name="code">The error number</param>
839
        /// <returns>A HRESULT constructed from the above 3 values</returns>
840
        public static int MAKE_HRESULT(uint sev, uint fac, uint code)
841
        {
842
            return (int)((sev << 31) | (fac << 16) | code);
843
        }
844
    }
845
}