/// <summary> /// Generate a unique string for the ShellLink that can be used for equality checks. /// </summary> private static string ShellLinkToString(IShellLinkW shellLink) { var pathBuilder = new StringBuilder(Win32Constant.MAX_PATH); shellLink.GetPath(pathBuilder, pathBuilder.Capacity, null, SLGP.RAWPATH); string title = null; // Need to use the property store to get the title for the link. using (PROPVARIANT pv = new PROPVARIANT()) { var propStore = (IPropertyStore)shellLink; PKEY pkeyTitle = PKEY.Title; propStore.GetValue(ref pkeyTitle, pv); // PKEY_Title should be an LPWSTR if it's not empty. title = pv.GetValue() ?? ""; } var argsBuilder = new StringBuilder(Win32Constant.INFOTIPSIZE); shellLink.GetArguments(argsBuilder, argsBuilder.Capacity); // Path and title should be case insensitive. // Shell treats arguments as case sensitive because apps can handle those differently. return(pathBuilder.ToString().ToUpperInvariant() + title.ToUpperInvariant() + argsBuilder.ToString()); }
private static JumpItem GetJumpItemForShellObject(object shellObject) { var shellItem = shellObject as IShellItem2; var shellLink = shellObject as IShellLinkW; if (shellItem != null) { JumpPath path = new JumpPath { Path = shellItem.GetDisplayName(SIGDN.DESKTOPABSOLUTEPARSING), }; return(path); } if (shellLink != null) { var pathBuilder = new StringBuilder(Win32Constant.MAX_PATH); shellLink.GetPath(pathBuilder, pathBuilder.Capacity, null, SLGP.RAWPATH); var argsBuilder = new StringBuilder(Win32Constant.INFOTIPSIZE); shellLink.GetArguments(argsBuilder, argsBuilder.Capacity); var descBuilder = new StringBuilder(Win32Constant.INFOTIPSIZE); shellLink.GetDescription(descBuilder, descBuilder.Capacity); var iconBuilder = new StringBuilder(Win32Constant.MAX_PATH); int iconIndex; shellLink.GetIconLocation(iconBuilder, iconBuilder.Capacity, out iconIndex); var dirBuilder = new StringBuilder(Win32Constant.MAX_PATH); shellLink.GetWorkingDirectory(dirBuilder, dirBuilder.Capacity); JumpTask task = new JumpTask { // Set ApplicationPath and IconResources, even if they're from the current application. // This means that equivalent JumpTasks won't necessarily compare property-for-property. ApplicationPath = pathBuilder.ToString(), Arguments = argsBuilder.ToString(), Description = descBuilder.ToString(), IconResourceIndex = iconIndex, IconResourcePath = iconBuilder.ToString(), WorkingDirectory = dirBuilder.ToString(), }; using (PROPVARIANT pv = new PROPVARIANT()) { var propStore = (IPropertyStore)shellLink; PKEY pkeyTitle = PKEY.Title; propStore.GetValue(ref pkeyTitle, pv); // PKEY_Title should be an LPWSTR if it's not empty. task.Title = pv.GetValue() ?? ""; } return(task); } // Unsupported type? Debug.Assert(false); return(null); }
private static JumpItem GetJumpItemForShellObject(object shellObject) { IShellItem2 shellItem = shellObject as IShellItem2; IShellLinkW shellLinkW = shellObject as IShellLinkW; if (shellItem != null) { return(new JumpPath { Path = shellItem.GetDisplayName((SIGDN)2147647488u) }); } if (shellLinkW != null) { StringBuilder stringBuilder = new StringBuilder(260); shellLinkW.GetPath(stringBuilder, stringBuilder.Capacity, null, SLGP.RAWPATH); StringBuilder stringBuilder2 = new StringBuilder(1024); shellLinkW.GetArguments(stringBuilder2, stringBuilder2.Capacity); StringBuilder stringBuilder3 = new StringBuilder(1024); shellLinkW.GetDescription(stringBuilder3, stringBuilder3.Capacity); StringBuilder stringBuilder4 = new StringBuilder(260); int iconResourceIndex; shellLinkW.GetIconLocation(stringBuilder4, stringBuilder4.Capacity, out iconResourceIndex); StringBuilder stringBuilder5 = new StringBuilder(260); shellLinkW.GetWorkingDirectory(stringBuilder5, stringBuilder5.Capacity); JumpTask jumpTask = new JumpTask { ApplicationPath = stringBuilder.ToString(), Arguments = stringBuilder2.ToString(), Description = stringBuilder3.ToString(), IconResourceIndex = iconResourceIndex, IconResourcePath = stringBuilder4.ToString(), WorkingDirectory = stringBuilder5.ToString() }; using (PROPVARIANT propvariant = new PROPVARIANT()) { IPropertyStore propertyStore = (IPropertyStore)shellLinkW; PKEY title = PKEY.Title; propertyStore.GetValue(ref title, propvariant); jumpTask.Title = (propvariant.GetValue() ?? ""); } return(jumpTask); } return(null); }
private static string ShellLinkToString(IShellLinkW shellLink) { StringBuilder stringBuilder = new StringBuilder(260); shellLink.GetPath(stringBuilder, stringBuilder.Capacity, null, SLGP.RAWPATH); string text = null; using (PROPVARIANT propvariant = new PROPVARIANT()) { IPropertyStore propertyStore = (IPropertyStore)shellLink; PKEY title = PKEY.Title; propertyStore.GetValue(ref title, propvariant); text = (propvariant.GetValue() ?? ""); } StringBuilder stringBuilder2 = new StringBuilder(1024); shellLink.GetArguments(stringBuilder2, stringBuilder2.Capacity); return(stringBuilder.ToString().ToUpperInvariant() + text.ToUpperInvariant() + stringBuilder2.ToString()); }
private static IShellLinkW CreateLinkFromJumpTask(JumpTask jumpTask, bool allowSeparators) { if (string.IsNullOrEmpty(jumpTask.Title) && (!allowSeparators || !string.IsNullOrEmpty(jumpTask.CustomCategory))) { return(null); } IShellLinkW shellLinkW = (IShellLinkW)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("00021401-0000-0000-C000-000000000046"))); IShellLinkW result; try { string path = JumpList._FullName; if (!string.IsNullOrEmpty(jumpTask.ApplicationPath)) { path = jumpTask.ApplicationPath; } shellLinkW.SetPath(path); if (!string.IsNullOrEmpty(jumpTask.WorkingDirectory)) { shellLinkW.SetWorkingDirectory(jumpTask.WorkingDirectory); } if (!string.IsNullOrEmpty(jumpTask.Arguments)) { shellLinkW.SetArguments(jumpTask.Arguments); } if (jumpTask.IconResourceIndex != -1) { string pszIconPath = JumpList._FullName; if (!string.IsNullOrEmpty(jumpTask.IconResourcePath)) { if ((long)jumpTask.IconResourcePath.Length >= 260L) { return(null); } pszIconPath = jumpTask.IconResourcePath; } shellLinkW.SetIconLocation(pszIconPath, jumpTask.IconResourceIndex); } if (!string.IsNullOrEmpty(jumpTask.Description)) { shellLinkW.SetDescription(jumpTask.Description); } IPropertyStore propertyStore = (IPropertyStore)shellLinkW; using (PROPVARIANT propvariant = new PROPVARIANT()) { PKEY pkey = default(PKEY); if (!string.IsNullOrEmpty(jumpTask.Title)) { propvariant.SetValue(jumpTask.Title); pkey = PKEY.Title; } else { propvariant.SetValue(true); pkey = PKEY.AppUserModel_IsDestListSeparator; } propertyStore.SetValue(ref pkey, propvariant); } propertyStore.Commit(); IShellLinkW shellLinkW2 = shellLinkW; shellLinkW = null; result = shellLinkW2; } catch (Exception) { result = null; } finally { Utility.SafeRelease <IShellLinkW>(ref shellLinkW); } return(result); }
private static IShellLinkW CreateLinkFromJumpTask(JumpTask jumpTask, bool allowSeparators) { Debug.Assert(jumpTask != null); // Title is generally required. If it's missing we need to treat this like a separator. // Everything else can still appear on separator elements, // but separators can only exist in the Tasks category. if (string.IsNullOrEmpty(jumpTask.Title)) { if (!allowSeparators || !string.IsNullOrEmpty(jumpTask.CustomCategory)) { // Just treat this situation as an InvalidItem. return(null); } } var link = (IShellLinkW)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(CLSID.ShellLink))); try { string appPath = _FullName; if (!string.IsNullOrEmpty(jumpTask.ApplicationPath)) { appPath = jumpTask.ApplicationPath; } link.SetPath(appPath); // This is optional. Don't set it if the app hasn't explicitly requested it. if (!string.IsNullOrEmpty(jumpTask.WorkingDirectory)) { // Don't verify this. It's possible that the directory doesn't exist now, but it will later. // Shell handles this fine when we try to set an improperly formatted path. link.SetWorkingDirectory(jumpTask.WorkingDirectory); } if (!string.IsNullOrEmpty(jumpTask.Arguments)) { link.SetArguments(jumpTask.Arguments); } // -1 is a sentinel value indicating not to use the icon. if (jumpTask.IconResourceIndex != -1) { string resourcePath = _FullName; if (!string.IsNullOrEmpty(jumpTask.IconResourcePath)) { // Shell bug (Windows 7 595770): IShellLink doesn't correctly limit icon location path to MAX_PATH. // It's really too bad we have to enforce this here. When the shortcut gets // serialized it streams the full string. On deserialization it only retrieves // MAX_PATH for this field leaving junk behind for subsequent gets, leading to data corruption. // Because we don't want to allow the app to do create something that we know may // be corrupt we have to enforce this ourselves. If Shell fixes this later then // we need to remove this check to let them handle this as they see fit. // If they fix it by supporting longer paths, then we're artificially constraining this value... if (jumpTask.IconResourcePath.Length >= Win32Constant.MAX_PATH) { // we could throw the exception here, but we're already globally catching everything. return(null); } resourcePath = jumpTask.IconResourcePath; } link.SetIconLocation(resourcePath, jumpTask.IconResourceIndex); } if (!string.IsNullOrEmpty(jumpTask.Description)) { link.SetDescription(jumpTask.Description); } IPropertyStore propStore = (IPropertyStore)link; var pv = new PROPVARIANT(); try { PKEY pkey = default(PKEY); if (!string.IsNullOrEmpty(jumpTask.Title)) { pv.SetValue(jumpTask.Title); pkey = PKEY.Title; } else { pv.SetValue(true); pkey = PKEY.AppUserModel_IsDestListSeparator; } propStore.SetValue(ref pkey, pv); } finally { Utilities.SafeDispose(ref pv); } propStore.Commit(); IShellLinkW retLink = link; link = null; return(retLink); } catch (Exception) { // IShellLinkW::Set* methods tend to return E_FAIL when trying to set invalid data. // The create methods don't explicitly check for these kinds of errors. // If we aren't able to create the item for any reason just return null to indicate an invalid item. return(null); } finally { Utilities.SafeRelease(ref link); } }