Statistics
| Branch: | Revision:

root / trunk / Pithos.ShellExtensions / Menus / FileContextMenu.cs @ c92e02f3

History | View | Annotate | Download (24.9 kB)

1
using System;
2
using System.Collections.Generic;
3
using System.ComponentModel.Composition;
4
using System.Diagnostics;
5
using System.Diagnostics.Contracts;
6
using System.Drawing;
7
using System.Linq;
8
using System.Runtime.InteropServices;
9
using System.Runtime.InteropServices.ComTypes;
10
using System.Text;
11
using Pithos.ShellExtensions.Properties;
12

    
13
namespace Pithos.ShellExtensions.Menus
14
{
15
    [ClassInterface(ClassInterfaceType.None)]
16
    [Guid("B1F1405D-94A1-4692-B72F-FC8CAF8B8700"), ComVisible(true)]
17
    public class FileContextMenu : IShellExtInit, IContextMenu
18
    {
19
        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger("Pithos.FileContextMenu");
20

    
21
        private const string MenuHandlername = "Pithos.FileContextMenu";
22

    
23

    
24
        private readonly Dictionary<string, MenuItem> _items;
25

    
26

    
27
        [Import]
28
        public FileContext Context { get; set; }
29

    
30
        private IntPtr _gotoBitmap=IntPtr.Zero;
31
        private IntPtr _versionBitmap = IntPtr.Zero;
32
        private IntPtr _propertiesBitmap = IntPtr.Zero;
33

    
34
        public FileContextMenu()
35
        {                        
36
            _gotoBitmap = GetBitmapPtr(Resources.MenuGoToPithos);
37
            _versionBitmap = GetBitmapPtr(Resources.MenuHistory);
38
            _propertiesBitmap = GetBitmapPtr(Resources.MenuProperties);
39

    
40

    
41
            
42

    
43
            _items = new Dictionary<string, MenuItem>{
44
                {"gotoPithos",new MenuItem{
45
                                           MenuText = "&Go to Pithos",
46
                                            Verb = "gotoPithos",
47
                                             VerbCanonicalName = "PITHOSGoTo",
48
                                              VerbHelpText = "Go to Pithos",
49
                                               MenuDisplayId = 1,
50
                                               MenuCommand=OnGotoPithos,
51
                                               DisplayFlags=DisplayFlags.All,
52
                                               MenuBitmap = _gotoBitmap
53
                                           }},
54
                {"showProperties",new MenuItem{
55
                                           MenuText = "&Pithos Properties",
56
                                            Verb = "showProperties",
57
                                             VerbCanonicalName = "PITHOSProperties",
58
                                              VerbHelpText = "Pithos Properties",
59
                                               MenuDisplayId = 2,
60
                                               MenuCommand=OnShowProperties,
61
                                               DisplayFlags=DisplayFlags.All,
62
                                               MenuBitmap = _propertiesBitmap
63
                                           }}/*,
64
                {"prevVersions",new MenuItem{
65
                                           MenuText = "&Show Previous Versions",
66
                                            Verb = "prevVersions",
67
                                             VerbCanonicalName = "PITHOSPrevVersions",
68
                                              VerbHelpText = "Go to Pithos and display previous versions",
69
                                               MenuDisplayId = 3,
70
                                               MenuCommand=OnVerbDisplayFileName,
71
                                               DisplayFlags=DisplayFlags.File,
72
                                               MenuBitmap=_versionBitmap
73
                                           }}*/
74
            };
75

    
76
            IoC.Current.Compose(this);
77

    
78

    
79
        }
80

    
81

    
82
        ~FileContextMenu()
83
        {
84
            if (_gotoBitmap != IntPtr.Zero)
85
            {
86
                NativeMethods.DeleteObject(_gotoBitmap);
87
                _gotoBitmap= IntPtr.Zero;
88
            }
89
            if (_versionBitmap != IntPtr.Zero)
90
            {
91
                NativeMethods.DeleteObject(_versionBitmap);
92
                _versionBitmap = IntPtr.Zero;
93
            }
94
            if (_propertiesBitmap != IntPtr.Zero)
95
            {
96
                NativeMethods.DeleteObject(_propertiesBitmap);
97
                _propertiesBitmap = IntPtr.Zero;
98
            }
99

    
100
        }
101
        private static IntPtr GetBitmapPtr(Bitmap gotoBitmap)
102
        {
103
            gotoBitmap.MakeTransparent(gotoBitmap.GetPixel(0, 0));
104
            var hbitmap = gotoBitmap.GetHbitmap();
105
            return hbitmap;
106
        }
107

    
108
        void OnShowProperties(IntPtr hWnd)
109
        {
110
            var filePath = Context.CurrentFile ?? Context.CurrentFolder;
111
            if (String.IsNullOrWhiteSpace(filePath))
112
            {
113
                Debug.WriteLine("No current file or folder");
114
                return;
115
            }
116
            else
117
            {
118
                Debug.WriteLine("Will display properties for {0}",filePath);
119
            }
120

    
121
            var client = PithosHost.GetCommandsClient();
122
            client.BeginShowProperties(Context.CurrentFile,c=>
123
            {
124
                try
125
                {
126
                    c.AsyncWaitHandle.WaitOne();                    
127
                    client.Close();
128
                }
129
                catch (Exception exc)
130
                {
131
                    Trace.WriteLine(exc.ToString());
132
                }
133
            },null);
134
            
135
        }
136

    
137
        void OnVerbDisplayFileName(IntPtr hWnd)
138
        {
139
            string message = String.Format("The selected file is {0}\r\n\r\nThe selected Path is {1}",
140
                                           Context.CurrentFile,
141
                                           Context.CurrentFolder);
142

    
143
            System.Windows.Forms.MessageBox.Show(
144
                message,
145
                "Pithos Shell Extensions");
146
            NativeMethods.SHChangeNotify(HChangeNotifyEventID.SHCNE_ASSOCCHANGED, HChangeNotifyFlags.SHCNF_IDLIST,
147
                                             IntPtr.Zero, IntPtr.Zero);
148
        }
149

    
150
        void OnGotoPithos(IntPtr hWnd)
151
        {
152
            var settings = Context.Settings;
153
            var activeAccount = settings.Accounts.FirstOrDefault(acc =>  Context.CurrentFile.StartsWith(acc.RootPath,StringComparison.InvariantCultureIgnoreCase));
154
            var address = String.Format("{0}/ui/?token={1}&user={2}",
155
                                        settings.PithosSite,
156
                                        activeAccount.ApiKey,
157
                                        Uri.EscapeUriString(activeAccount.AccountName));
158

    
159
            settings.Reload();
160
            Process.Start(address);
161
        }
162
        
163

    
164
        #region Shell Extension Registration
165

    
166
        [ComRegisterFunction]
167
        public static void Register(Type t)
168
        {
169
            try
170
            {
171
                ShellExtReg.RegisterShellExtContextMenuHandler(t.GUID, ".cs",
172
                    MenuHandlername);
173
                ShellExtReg.RegisterShellExtContextMenuHandler(t.GUID, "Directory",
174
                    MenuHandlername);
175
                ShellExtReg.RegisterShellExtContextMenuHandler(t.GUID, @"Directory\Background",
176
                    MenuHandlername);
177
                ShellExtReg.RegisterShellExtContextMenuHandler(t.GUID, "*",
178
                    MenuHandlername);
179

    
180
                //ShellExtReg.MarkApproved(t.GUID, MenuHandlername);
181
            }
182
            catch (Exception ex)
183
            {
184
                Console.WriteLine(ex.Message); // Log the error
185
                throw;  // Re-throw the exception
186
            }
187
        }
188

    
189
        [ComUnregisterFunction]
190
        public static void Unregister(Type t)
191
        {
192
            try
193
            {
194
                ShellExtReg.UnregisterShellExtContextMenuHandler(t.GUID, ".cs", MenuHandlername);
195
                ShellExtReg.UnregisterShellExtContextMenuHandler(t.GUID, "Directory", MenuHandlername);
196
                ShellExtReg.UnregisterShellExtContextMenuHandler(t.GUID, @"Directory\Background", MenuHandlername);
197
                ShellExtReg.UnregisterShellExtContextMenuHandler(t.GUID, "*", MenuHandlername);
198

    
199
                //ShellExtReg.RemoveApproved(t.GUID, MenuHandlername);
200
            }
201
            catch (Exception ex)
202
            {
203
                Console.WriteLine(ex.Message); // Log the error
204
                throw;  // Re-throw the exception
205
            }
206
        }
207

    
208
        #endregion
209

    
210

    
211
        #region IShellExtInit Members
212

    
213
        /// <summary>
214
        /// Initialize the context menu handler.
215
        /// </summary>
216
        /// <param name="pidlFolder">
217
        /// A pointer to an ITEMIDLIST structure that uniquely identifies a folder.
218
        /// </param>
219
        /// <param name="pDataObj">
220
        /// A pointer to an IDataObject interface object that can be used to retrieve 
221
        /// the objects being acted upon.
222
        /// </param>
223
        /// <param name="hKeyProgID">
224
        /// The registry key for the file object or folder type.
225
        /// </param>
226
        public void Initialize(IntPtr pidlFolder, IntPtr pDataObj, IntPtr hKeyProgID)
227
        {
228
            
229
            if(pDataObj == IntPtr.Zero && pidlFolder == IntPtr.Zero)
230
            {
231
                throw new ArgumentException("pidlFolder and pDataObj shouldn't be null at the same time");
232
            }
233

    
234

    
235
            Debug.WriteLine("Initializing", LogCategories.ShellMenu);
236

    
237
            if (pDataObj != IntPtr.Zero)
238
            {
239
                Debug.WriteLine("Got a data object", LogCategories.ShellMenu);
240

    
241
                FORMATETC fe = new FORMATETC();
242
                fe.cfFormat = (short)CLIPFORMAT.CF_HDROP;
243
                fe.ptd = IntPtr.Zero;
244
                fe.dwAspect = DVASPECT.DVASPECT_CONTENT;
245
                fe.lindex = -1;
246
                fe.tymed = TYMED.TYMED_HGLOBAL;
247
                STGMEDIUM stm = new STGMEDIUM();
248

    
249
                // The pDataObj pointer contains the objects being acted upon. In this 
250
                // example, we get an HDROP handle for enumerating the selected files 
251
                // and folders.
252
                IDataObject dataObject = (IDataObject)Marshal.GetObjectForIUnknown(pDataObj);
253
                dataObject.GetData(ref fe, out stm);
254

    
255
                try
256
                {
257
                    // Get an HDROP handle.
258
                    IntPtr hDrop = stm.unionmember;
259
                    if (hDrop == IntPtr.Zero)
260
                    {
261
                        throw new ArgumentException();
262
                    }
263

    
264
                    // Determine how many files are involved in this operation.
265
                    uint nFiles = NativeMethods.DragQueryFile(hDrop, UInt32.MaxValue, null, 0);
266

    
267
                    Debug.WriteLine(String.Format("Got {0} files", nFiles), LogCategories.ShellMenu);
268
                    // This code sample displays the custom context menu item when only 
269
                    // one file is selected. 
270
                    if (nFiles == 1)
271
                    {
272
                        // Get the path of the file.
273
                        var fileName = new StringBuilder(260);
274
                        if (0 == NativeMethods.DragQueryFile(hDrop, 0, fileName,
275
                                                             fileName.Capacity))
276
                        {
277
                            Marshal.ThrowExceptionForHR(WinError.E_FAIL);
278
                        }
279
                        Context.CurrentFile = fileName.ToString();
280
                    }
281
                    /* else
282
                     {
283
                         Marshal.ThrowExceptionForHR(WinError.E_FAIL);
284
                     }*/
285

    
286
                    // [-or-]
287

    
288
                    // Enumerate the selected files and folders.
289
                    //if (nFiles > 0)
290
                    //{
291
                    //    StringCollection selectedFiles = new StringCollection();
292
                    //    StringBuilder fileName = new StringBuilder(260);
293
                    //    for (uint i = 0; i < nFiles; i++)
294
                    //    {
295
                    //        // Get the next file name.
296
                    //        if (0 != NativeMethods.DragQueryFile(hDrop, i, fileName,
297
                    //            fileName.Capacity))
298
                    //        {
299
                    //            // Add the file name to the list.
300
                    //            selectedFiles.Add(fileName.ToString());
301
                    //        }
302
                    //    }
303
                    //
304
                    //    // If we did not find any files we can work with, throw 
305
                    //    // exception.
306
                    //    if (selectedFiles.Count == 0)
307
                    //    {
308
                    //        Marshal.ThrowExceptionForHR(WinError.E_FAIL);
309
                    //    }
310
                    //}
311
                    //else
312
                    //{
313
                    //    Marshal.ThrowExceptionForHR(WinError.E_FAIL);
314
                    //}
315
                }
316
                finally
317
                {
318
                    NativeMethods.ReleaseStgMedium(ref stm);
319
                }
320
            }
321

    
322
            if (pidlFolder != IntPtr.Zero)
323
            {
324
                Debug.WriteLine("Got a folder", LogCategories.ShellMenu);
325
                StringBuilder path = new StringBuilder();
326
                if (!NativeMethods.SHGetPathFromIDList(pidlFolder, path))
327
                {
328
                    int error = Marshal.GetHRForLastWin32Error();
329
                    Marshal.ThrowExceptionForHR(error);
330
                }
331
                Context.CurrentFolder = path.ToString();
332
                Debug.WriteLine(String.Format("Folder is {0}", Context.CurrentFolder), LogCategories.ShellMenu);
333
            }
334
        }
335

    
336
        #endregion
337

    
338

    
339
        #region IContextMenu Members
340

    
341
        /// <summary>
342
        /// Add commands to a shortcut menu.
343
        /// </summary>
344
        /// <param name="hMenu">A handle to the shortcut menu.</param>
345
        /// <param name="iMenu">
346
        /// The zero-based position at which to insert the first new menu item.
347
        /// </param>
348
        /// <param name="idCmdFirst">
349
        /// The minimum value that the handler can specify for a menu item ID.
350
        /// </param>
351
        /// <param name="idCmdLast">
352
        /// The maximum value that the handler can specify for a menu item ID.
353
        /// </param>
354
        /// <param name="uFlags">
355
        /// Optional flags that specify how the shortcut menu can be changed.
356
        /// </param>
357
        /// <returns>
358
        /// If successful, returns an HRESULT value that has its severity value set 
359
        /// to SEVERITY_SUCCESS and its code value set to the offset of the largest 
360
        /// command identifier that was assigned, plus one.
361
        /// </returns>
362
        public int QueryContextMenu(
363
            IntPtr hMenu,
364
            uint iMenu,
365
            uint idCmdFirst,
366
            uint idCmdLast,
367
            uint uFlags)
368
        {
369
            Debug.WriteLine("Start qcm", LogCategories.ShellMenu);
370
            // If uFlags include CMF_DEFAULTONLY then we should not do anything.
371
            Debug.WriteLine(String.Format("Flags {0}", uFlags), LogCategories.ShellMenu);
372

    
373
            if (((uint)CMF.CMF_DEFAULTONLY & uFlags) != 0)
374
            {
375
                Debug.WriteLine("Default only flag, returning", LogCategories.ShellMenu);
376
                return WinError.MAKE_HRESULT(WinError.SEVERITY_SUCCESS, 0, 0);
377
            }
378

    
379
            if (!Context.IsManaged)
380
            {
381
                Debug.WriteLine("Not a PITHOS folder",LogCategories.ShellMenu);
382
                return WinError.MAKE_HRESULT(WinError.SEVERITY_SUCCESS, 0, 0);
383
            }
384

    
385
            /*
386
                        if (!selectedFolder.ToLower().Contains("pithos"))
387
                            return WinError.MAKE_HRESULT(WinError.SEVERITY_SUCCESS, 0, 0);
388
            */
389

    
390
            // Use either InsertMenu or InsertMenuItem to add menu items.
391

    
392
            uint largestID = 0;
393

    
394
            DisplayFlags itemType = (Context.IsFolder) ? DisplayFlags.Folder : DisplayFlags.File;
395

    
396
            Debug.WriteLine(String.Format("Item Flags {0}", itemType), LogCategories.ShellMenu);
397

    
398
            if (!NativeMethods.InsertMenu(hMenu, idCmdFirst, MF.MF_SEPARATOR | MF.MF_BYPOSITION, 0, String.Empty))
399
            {
400
                Log.ErrorFormat("Error adding separator 1\r\n{0}", Marshal.GetLastWin32Error());
401
                return Marshal.GetHRForLastWin32Error();
402
            }
403

    
404
            foreach (var menuItem in _items.Values)
405
            {
406
                Debug.WriteLine(String.Format("Menu Flags {0}", menuItem.DisplayFlags), LogCategories.ShellMenu);
407
                if ((itemType & menuItem.DisplayFlags) != DisplayFlags.None)
408
                {
409
                    Debug.WriteLine("Adding Menu", LogCategories.ShellMenu);
410

    
411
                    MENUITEMINFO mii = menuItem.CreateInfo(idCmdFirst);
412
                    if (!NativeMethods.InsertMenuItem(hMenu, iMenu, true, ref mii))
413
                    {
414
                        var lastError = Marshal.GetLastWin32Error();
415
                        var lastErrorHR = Marshal.GetHRForLastWin32Error();
416
                        return lastErrorHR;
417
                    }
418
                    if (largestID < menuItem.MenuDisplayId)
419
                        largestID = menuItem.MenuDisplayId;
420
                }
421
            }
422

    
423
            Debug.Write("Adding Separator 1", LogCategories.ShellMenu);
424
            // Add a separator.
425
           /* MENUITEMINFO sep = new MENUITEMINFO();
426
            sep.cbSize = (uint)Marshal.SizeOf(sep);
427
            sep.fMask = MIIM.MIIM_TYPE;
428
            sep.fType = MFT.MFT_SEPARATOR;*/
429
            if (!NativeMethods.InsertMenu(hMenu, (uint)_items.Values.Count + idCmdFirst+1,MF.MF_SEPARATOR|MF.MF_BYPOSITION, 0, String.Empty))
430
            {
431
                Log.ErrorFormat("Error adding separator 1\r\n{0}", Marshal.GetLastWin32Error());
432
                return Marshal.GetHRForLastWin32Error();
433
            }
434

    
435

    
436

    
437

    
438
            Debug.WriteLine("Menus added", LogCategories.ShellOverlays);
439
            // Return an HRESULT value with the severity set to SEVERITY_SUCCESS. 
440
            // Set the code value to the offset of the largest command identifier 
441
            // that was assigned, plus one (1).
442
            return WinError.MAKE_HRESULT(WinError.SEVERITY_SUCCESS, 0,
443
                largestID + 1);
444
        }
445

    
446
        /// <summary>
447
        /// Carry out the command associated with a shortcut menu item.
448
        /// </summary>
449
        /// <param name="pici">
450
        /// A pointer to a CMINVOKECOMMANDINFO or CMINVOKECOMMANDINFOEX structure 
451
        /// containing information about the command. 
452
        /// </param>
453
        public void InvokeCommand(IntPtr pici)
454
        {
455
            bool isUnicode = false;
456

    
457
            // Determine which structure is being passed in, CMINVOKECOMMANDINFO or 
458
            // CMINVOKECOMMANDINFOEX based on the cbSize member of lpcmi. Although 
459
            // the lpcmi parameter is declared in Shlobj.h as a CMINVOKECOMMANDINFO 
460
            // structure, in practice it often points to a CMINVOKECOMMANDINFOEX 
461
            // structure. This struct is an extended version of CMINVOKECOMMANDINFO 
462
            // and has additional members that allow Unicode strings to be passed.
463
            CMINVOKECOMMANDINFO ici = (CMINVOKECOMMANDINFO)Marshal.PtrToStructure(
464
                pici, typeof(CMINVOKECOMMANDINFO));
465
            CMINVOKECOMMANDINFOEX iciex = new CMINVOKECOMMANDINFOEX();
466
            if (ici.cbSize == Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)))
467
            {
468
                if ((ici.fMask & CMIC.CMIC_MASK_UNICODE) != 0)
469
                {
470
                    isUnicode = true;
471
                    iciex = (CMINVOKECOMMANDINFOEX)Marshal.PtrToStructure(pici,
472
                        typeof(CMINVOKECOMMANDINFOEX));
473
                }
474
            }
475

    
476
            // Determines whether the command is identified by its offset or verb.
477
            // There are two ways to identify commands:
478
            // 
479
            //   1) The command's verb string 
480
            //   2) The command's identifier offset
481
            // 
482
            // If the high-order word of lpcmi->lpVerb (for the ANSI case) or 
483
            // lpcmi->lpVerbW (for the Unicode case) is nonzero, lpVerb or lpVerbW 
484
            // holds a verb string. If the high-order word is zero, the command 
485
            // offset is in the low-order word of lpcmi->lpVerb.
486

    
487
            // For the ANSI case, if the high-order word is not zero, the command's 
488
            // verb string is in lpcmi->lpVerb. 
489
            if (!isUnicode && NativeMethods.HighWord(ici.verb.ToInt32()) != 0)
490
            {
491
                // Is the verb supported by this context menu extension?
492
                string verbAnsi = Marshal.PtrToStringAnsi(ici.verb);
493
                if (_items.ContainsKey(verbAnsi))
494
                {
495
                    _items[verbAnsi].MenuCommand(ici.hwnd);
496
                }
497
                else
498
                {
499
                    // If the verb is not recognized by the context menu handler, it 
500
                    // must return E_FAIL to allow it to be passed on to the other 
501
                    // context menu handlers that might implement that verb.
502
                    Marshal.ThrowExceptionForHR(WinError.E_FAIL);
503
                }
504
            }
505

    
506
                // For the Unicode case, if the high-order word is not zero, the 
507
            // command's verb string is in lpcmi->lpVerbW. 
508
            else if (isUnicode && NativeMethods.HighWord(iciex.verbW.ToInt32()) != 0)
509
            {
510
                // Is the verb supported by this context menu extension?
511
                string verbUTF = Marshal.PtrToStringUni(iciex.verbW);
512
                if (_items.ContainsKey(verbUTF))
513
                {
514
                    _items[verbUTF].MenuCommand(ici.hwnd);
515
                }
516
                else
517
                {
518
                    // If the verb is not recognized by the context menu handler, it 
519
                    // must return E_FAIL to allow it to be passed on to the other 
520
                    // context menu handlers that might implement that verb.
521
                    Marshal.ThrowExceptionForHR(WinError.E_FAIL);
522
                }
523
            }
524

    
525
                // If the command cannot be identified through the verb string, then 
526
            // check the identifier offset.
527
            else
528
            {
529
                // Is the command identifier offset supported by this context menu 
530
                // extension?
531
                int menuID = NativeMethods.LowWord(ici.verb.ToInt32());
532
                var menuItem = _items.FirstOrDefault(item => item.Value.MenuDisplayId == menuID).Value;
533
                if (menuItem != null)
534
                {
535
                    menuItem.MenuCommand(ici.hwnd);
536
                }
537
                else
538
                {
539
                    // If the verb is not recognized by the context menu handler, it 
540
                    // must return E_FAIL to allow it to be passed on to the other 
541
                    // context menu handlers that might implement that verb.
542
                    Marshal.ThrowExceptionForHR(WinError.E_FAIL);
543
                }
544
            }
545
        }
546

    
547
        /// <summary>
548
        /// Get information about a shortcut menu command, including the help string 
549
        /// and the language-independent, or canonical, name for the command.
550
        /// </summary>
551
        /// <param name="idCmd">Menu command identifier offset.</param>
552
        /// <param name="uFlags">
553
        /// Flags specifying the information to return. This parameter can have one 
554
        /// of the following values: GCS_HELPTEXTA, GCS_HELPTEXTW, GCS_VALIDATEA, 
555
        /// GCS_VALIDATEW, GCS_VERBA, GCS_VERBW.
556
        /// </param>
557
        /// <param name="pReserved">Reserved. Must be IntPtr.Zero</param>
558
        /// <param name="pszName">
559
        /// The address of the buffer to receive the null-terminated string being 
560
        /// retrieved.
561
        /// </param>
562
        /// <param name="cchMax">
563
        /// Size of the buffer, in characters, to receive the null-terminated string.
564
        /// </param>
565
        public void GetCommandString(
566
            UIntPtr idCmd,
567
            uint uFlags,
568
            IntPtr pReserved,
569
            StringBuilder pszName,
570
            uint cchMax)
571
        {
572
            uint menuID = idCmd.ToUInt32();
573
            var menuItem = _items.FirstOrDefault(item => item.Value.MenuDisplayId == menuID).Value;
574
            if (menuItem != null)
575
            {
576
                switch ((GCS)uFlags)
577
                {
578
                    case GCS.GCS_VERBW:
579
                        if (menuItem.VerbCanonicalName.Length > cchMax - 1)
580
                        {
581
                            Marshal.ThrowExceptionForHR(WinError.STRSAFE_E_INSUFFICIENT_BUFFER);
582
                        }
583
                        else
584
                        {
585
                            pszName.Clear();
586
                            pszName.Append(menuItem.VerbCanonicalName);
587
                        }
588
                        break;
589

    
590
                    case GCS.GCS_HELPTEXTW:
591
                        if (menuItem.VerbHelpText.Length > cchMax - 1)
592
                        {
593
                            Marshal.ThrowExceptionForHR(WinError.STRSAFE_E_INSUFFICIENT_BUFFER);
594
                        }
595
                        else
596
                        {
597
                            pszName.Clear();
598
                            pszName.Append(menuItem.VerbHelpText);
599
                        }
600
                        break;
601
                }
602
            }
603
        }
604

    
605
        #endregion
606
    }
607
}