Tags, Permissions, Public for Files are working
[pithos-ms-client] / trunk / Pithos.ShellExtensions / ShellExtLib.cs
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             Debug.WriteLine(String.Format("Marking approved {0} {1}", guid, friendlyName), LogCategories.Shell);
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                     Debug.WriteLine("Error - failed to open key " + _approvedKey,LogCategories.Shell);
255                 }
256             }
257         }
258
259         public static void RemoveApproved(Guid guid)
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                     Debug.WriteLine("Error - failed to open key " + _approvedKey, LogCategories.Shell);
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     [Flags]
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     [Flags]
710     internal enum MFS : uint
711     {
712         MFS_ENABLED = 0x00000000,
713         MFS_UNCHECKED = 0x00000000,
714         MFS_UNHILITE = 0x00000000,
715         MFS_GRAYED = 0x00000003,
716         MFS_DISABLED = 0x00000003,
717         MFS_CHECKED = 0x00000008,
718         MFS_HILITE = 0x00000080,
719         MFS_DEFAULT = 0x00001000
720     }
721
722     [Flags]
723     internal enum MF: uint
724     {
725         MF_BYCOMMAND    =   0x00000000,
726         MF_ENABLED      =   0x00000000,
727         MF_DISABLED     =   0x00000002,
728         MF_BITMAP       =   0x00000004,
729         MF_CHECKED      =   0x00000008,
730         MF_BYPOSITION   =   0x00000400,
731         MF_SEPARATOR    =   0x00000800
732     }
733
734     #endregion
735
736
737     internal class NativeMethods
738     {
739         /// <summary>
740         /// Retrieve the names of dropped files that result from a successful drag-
741         /// and-drop operation.
742         /// </summary>
743         /// <param name="hDrop">
744         /// Identifier of the structure that contains the file names of the dropped 
745         /// files.
746         /// </param>
747         /// <param name="iFile">
748         /// Index of the file to query. If the value of this parameter is 0xFFFFFFFF, 
749         /// DragQueryFile returns a count of the files dropped. 
750         /// </param>
751         /// <param name="pszFile">
752         /// The address of a buffer that receives the file name of a dropped file 
753         /// when the function returns.
754         /// </param>
755         /// <param name="cch">
756         /// The size, in characters, of the pszFile buffer.
757         /// </param>
758         /// <returns>A non-zero value indicates a successful call.</returns>
759         [DllImport("shell32", CharSet = CharSet.Unicode)]
760         public static extern uint DragQueryFile(
761             IntPtr hDrop,
762             uint iFile,
763             StringBuilder pszFile,
764             int cch);
765
766         /// <summary>
767         /// Free the specified storage medium.
768         /// </summary>
769         /// <param name="pmedium">
770         /// Reference of the storage medium that is to be freed.
771         /// </param>
772         [DllImport("ole32.dll", CharSet = CharSet.Unicode)]
773         public static extern void ReleaseStgMedium(ref STGMEDIUM pmedium);
774
775         /// <summary>
776         /// Insert a new menu item at the specified position in a menu.
777         /// </summary>
778         /// <param name="hMenu">
779         /// A handle to the menu in which the new menu item is inserted. 
780         /// </param>
781         /// <param name="uItem">
782         /// The identifier or position of the menu item before which to insert the 
783         /// new item. The meaning of this parameter depends on the value of 
784         /// fByPosition.
785         /// </param>
786         /// <param name="fByPosition">
787         /// Controls the meaning of uItem. If this parameter is false, uItem is a 
788         /// menu item identifier. Otherwise, it is a menu item position. 
789         /// </param>
790         /// <param name="mii">
791         /// A reference of a MENUITEMINFO structure that contains information about 
792         /// the new menu item.
793         /// </param>
794         /// <returns>
795         /// If the function succeeds, the return value is true.
796         /// </returns>
797         [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
798         [return: MarshalAs(UnmanagedType.Bool)]
799         public static extern bool InsertMenuItem(
800             IntPtr hMenu,
801             uint uItem,
802             [MarshalAs(UnmanagedType.Bool)]bool fByPosition,
803             ref MENUITEMINFO mii);
804         
805         [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)]
806         [return: MarshalAs(UnmanagedType.Bool)]
807         public static extern bool InsertMenu(
808             IntPtr hMenu,
809             uint uPosition,
810             MF uFlags,
811             uint uIDNewItem,
812             string lpNewItem);
813
814
815         [DllImport("shell32", CharSet = CharSet.Unicode, SetLastError = true)]
816         [return: MarshalAs(UnmanagedType.Bool)]
817         public static extern bool SHGetPathFromIDList(
818             IntPtr pidl,
819             StringBuilder pszpath);
820
821         [DllImport("shell32.dll")]
822         public static extern void SHChangeNotify(HChangeNotifyEventID wEventId,
823                                            HChangeNotifyFlags uFlags,
824                                            IntPtr dwItem1,
825                                            IntPtr dwItem2);
826
827         [DllImport("gdi32.dll")]
828         public static extern bool DeleteObject(IntPtr hObject);
829
830
831
832         public static int HighWord(int number)
833         {
834             return ((number & 0x80000000) == 0x80000000) ?
835                 (number >> 16) : ((number >> 16) & 0xffff);
836         }
837
838         public static int LowWord(int number)
839         {
840             return number & 0xffff;
841         }
842     }
843
844     internal static class WinError
845     {
846         public const int S_OK = 0x0000;
847         public const int S_FALSE = 0x0001;
848         public const int E_FAIL = -2147467259;
849         public const int E_INVALIDARG = -2147024809;
850         public const int E_OUTOFMEMORY = -2147024882;
851         public const int STRSAFE_E_INSUFFICIENT_BUFFER = -2147024774;
852
853         public const uint SEVERITY_SUCCESS = 0;
854         public const uint SEVERITY_ERROR = 1;
855
856         /// <summary>
857         /// Create an HRESULT value from component pieces.
858         /// </summary>
859         /// <param name="sev">The severity to be used</param>
860         /// <param name="fac">The facility to be used</param>
861         /// <param name="code">The error number</param>
862         /// <returns>A HRESULT constructed from the above 3 values</returns>
863         public static int MAKE_HRESULT(uint sev, uint fac, uint code)
864         {
865             return (int)((sev << 31) | (fac << 16) | code);
866         }
867     }
868 }