/// <summary> /// Retrieves an OLE interface that can be used to carry out actions on the /// specified file objects or folders. Return value: error code, if any /// </summary> /// <param name="hwndOwner">Handle to the owner window that the client should specify if it displays a dialog box or message box.</param> /// <param name="cidl">Number of file objects or subfolders specified in the apidl parameter.</param> /// <param name="apidl">Address of an array of pointers to ITEMIDLIST structures, each of which uniquely identifies a file object or subfolder relative to the parent folder.</param> /// <param name="riid">Identifier of the COM interface object to return.</param> /// <param name="rgfReserved">Reserved.</param> /// <param name="ppv">Pointer to the requested interface.</param> /// <returns> /// If this method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. /// </returns> int IShellFolder.GetUIObjectOf(IntPtr hwndOwner, uint cidl, IntPtr apidl, ref Guid riid, uint rgfReserved, out IntPtr ppv) { // Get the ID lists from the array of PIDLs provided. var idLists = PidlManager.APidlToIdListArray(apidl, (int)cidl); if (riid == typeof(IContextMenu).GUID || riid == typeof(IContextMenu2).GUID || riid == typeof(IContextMenu3).GUID) { // If the folder implments the context menu provider, we can use that. var contextMenuProvider = proxyFolder as IShellNamespaceFolderContextMenuProvider; if (contextMenuProvider != null) { ppv = Marshal.GetComInterfaceForObject(contextMenuProvider.CreateContextMenu(idListAbsolute, idLists), typeof(IContextMenu)); return(WinError.S_OK); } var dcm = new DEFCONTEXTMENU { hwnd = hwndOwner, pcmcb = null, pidlFolder = PidlManager.IdListToPidl(idListAbsolute), psf = this, cidl = cidl, apidl = apidl, punkAssociationInfo = IntPtr.Zero, cKeys = 0, aKeys = null }; // Create the default context menu. var result = Shell32.SHCreateDefaultContextMenu(dcm, riid, out ppv); } else if (riid == Shell32.IID_ExtractIconW) { // If we've been asked for an icon, it should only be for a single PIDL. if (idLists.Length != 1) { Diagnostics.Logging.Error(string.Format("The Shell Folder Impl for folder {0} has been asked for icons for multiple files at once, this is not supportedd.", proxyFolder.GetDisplayName(DisplayNameContext.Normal))); ppv = IntPtr.Zero; return(WinError.E_FAIL); } // Get the idlist and item. var idList = idLists[0]; var item = GetChildItem(idList); // Now get the icon. If we don't provide one we'll use the defaults. var icon = item.GetIcon(); if (icon == null) { ProvideDefaultIExtractIcon(item is IShellNamespaceFolder, out ppv); return(WinError.S_OK); } else { // Create an icon provider. var provider = new Components.ExtractIconImpl() { DoNotCacheIcons = false, Icon = icon }; ppv = Marshal.GetComInterfaceForObject(provider, typeof(IExtractIconW)); return(WinError.S_OK); } } else if (riid == Shell32.IID_IDataObject) { // Create the data object. Shell32.SHCreateDataObject(PidlManager.IdListToPidl(idListAbsolute), cidl, apidl, null, riid, out ppv); } else if (riid == Shell32.IID_IQueryAssociations) { // If we've been asked for a query associations, it should only be for a single PIDL. if (idLists.Length != 1) { Diagnostics.Logging.Error(string.Format("The Shell Folder Impl for folder {0} has been asked for query associations for multiple files at once, this is not supportedd.", proxyFolder.GetDisplayName(DisplayNameContext.Normal))); ppv = IntPtr.Zero; return(WinError.E_FAIL); } var item = GetChildItem(idLists[0]); var isFolder = item is IShellNamespaceFolder; if (isFolder) { // todo perhaps a good class name would simply be the // name of the item type? or an attribute that uses the classname as a // fallback. var associations = new ASSOCIATIONELEMENT[] { new ASSOCIATIONELEMENT { ac = ASSOCCLASS.ASSOCCLASS_PROGID_STR, hkClass = IntPtr.Zero, pszClass = "FolderViewSampleType" }, new ASSOCIATIONELEMENT { ac = ASSOCCLASS.ASSOCCLASS_FOLDER, hkClass = IntPtr.Zero, pszClass = "FolderViewSampleType" } }; Shell32.AssocCreateForClasses(associations, (uint)associations.Length, riid, out ppv); } else { var associations = new ASSOCIATIONELEMENT[] { new ASSOCIATIONELEMENT { ac = ASSOCCLASS.ASSOCCLASS_PROGID_STR, hkClass = IntPtr.Zero, pszClass = "FolderViewSampleType" } }; Shell32.AssocCreateForClasses(associations, (uint)associations.Length, riid, out ppv); } } /* } */ // We have a set of child pidls (i.e. length one). We can now offer interfaces such as: /* * IContextMenu The cidl parameter can be greater than or equal to one. * IContextMenu2 The cidl parameter can be greater than or equal to one. * IDataObject The cidl parameter can be greater than or equal to one. * IDropTarget The cidl parameter can only be one. * IExtractIcon The cidl parameter can only be one. * IQueryInfo The cidl parameter can only be one. * */ // IID_IExtractIconW // IID_IDataObject // IID_IQueryAssociations // Currently, we don't offer any extra child item UI objects. ppv = IntPtr.Zero; return(WinError.E_NOINTERFACE); }