IShellLinkW::GetPath( SLGP_RAWPATH ) не возвращает «необработанную» цель lnk-файла

Я заметил, что метод IShellLinkW:: GetPath возвращает пустую строку, если цель ярлыка указывает на специальную папку, например «Мой компьютер», или апплет панели управления.

Образец кода

' CLSID_ShellLink from ShlGuid.h
Dim cShellLink As New CShellLink() 

' https://msdn.microsoft.com/en-us/library/windows/desktop/ms687223%28v=vs.85%29.aspx
Dim persistFile As IPersistFile = DirectCast(cShellLink, IPersistFile) 
persistFile.Load(lnkFilePath, 0)

Dim target As New StringBuilder(260)

' https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nn-shobjidl_core-ishelllinkw
Dim lnkW As IShellLinkW = DirectCast(cShellLink, IShellLinkW)
lnkW.GetPath(target, target.Capacity, Nothing, IShellLinkGetPathFlags.RawPath)

(Извините, здесь слишком много P/Invoke, но вы можете найти их в репозитории это.)

Приведенный выше код правильно работает для получения цели любого файла .lnk, указывающего на файл или каталог. Он не может получить цель, указывающую на специальный элемент/виртуальные папки.

Мои вопросы:

Это по замыслу?. Если нет, то что я упускаю или делаю неправильно? (может быть, мои определения неверны?). И что мне нужно сделать, чтобы получить специальную цель? Обратите внимание, что я хотел бы получить цель, чтобы отобразить ее в PropertyGrid, а также создать новую цель с клоном специальной цели.

Обратите внимание, что язык программирования, на котором я разрабатывал этот код, не имеет значения, потому что я в первую очередь прошу для ориентации, а также принимаю любое решение, написанное на C#.

Пути работают только для объектов файловой системы. Вам нужно ознакомиться с PIDL, IShellLinkW::GetIDList() возвращает их. Не рекомендуется.

Hans Passant 27.05.2019 23:39

См. SHGetPathFromIDList, SHGetFileInfo (обратите внимание, что он принимает LPCWSTR, но также и pidl), SHGetSpecialFolderLocation. Интерфейс IShellLinkW также предоставляет метод .Resolve(), который может пригодиться. Используйте его на том же объекте оболочки, затем получите адрес out, возвращаемый GetIDList()

Jimi 28.05.2019 02:03

Спасибо за комментарии, но если я вызову IShellLinkW.GetIDList, затем SHGetPathFromIDListW с полученным (действительным, ненулевым) PIDL, я всегда получаю пустую строку, и функция возвращает ложный, но код последней ошибки win32 равен нулю (Сетластеррор установлен в истинный ). Почему?. Пробовал разные подписи, в том числе и с сайта pinvoke.net.

ElektroStudios 28.05.2019 02:37

Кроме того, я не понимаю, в чем смысл использования SHGetFileInfo, потому что, похоже, я смог получить только имя файла (SHGFI_DISPLAYNAME) и описание типа файла (SHGFI_TYPENAME). Кстати, эта функция принимает PIDL, который я получаю с помощью IShellLinkW.GetIDList, но, как я уже упоминал, кажется, что я не могу получить «сырую» целевую строку lnk с помощью этой функции... только имя файла или описание типа файла.

ElektroStudios 28.05.2019 02:39

При анализе этих lnk-файлов в шестнадцатеричном редакторе у них есть CLSID для цели (например, ::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}, который указывает на Мой компьютер), и если я использую этот CLSID при создании ярлыка, вызывающего SetPath (без возни с SetIDList и чем-то тривиальным), это работает как положено. Это обнаружение упрощает решение проблемы, потому что я думаю, что могу получить CLSID из PIDL. PIDL — это концепция, которую я вообще мало читал, так что извините, если говорю глупости. Но я все равно буду исследовать доступные функции win32, чтобы получить значение CLSID...

ElektroStudios 28.05.2019 03:12

После того, как я проанализировал назначение каждой задокументированной функции SH*, я до сих пор не знаю, как это сделать. Кроме того, я не уверен, является ли PIDL, возвращаемый IShellLinkW.GetIDList, «абсолютным» или «относительным» PIDL, что меня смущает. больше, и я не вижу способа определить, какой из трех типов PIDL это, кроме вызова SHGetRealIDL и забыть. Кроме того, я попробовал функцию SHGetPathFromIDListEx, но у меня точно такие же проблемы, как и при вызове SHGetPathFromIDList. Черт, мне просто нужно получить CLSID, записанный в файле lnk... Я не понимаю, как получить этот CLSID из PIDL.

ElektroStudios 28.05.2019 04:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
366
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как упоминалось в поле комментариев к основному сообщению, чтобы получить необработанную цель ссылки оболочки, которая указывает на специальный путь, не относящийся к файловой системе (например, «Мой компьютер»), сначала нам нужно получить PIDL с помощью звоню IShellLinkW::GetIDList().

Затем мы передаем этот (абсолютный) PIDL в SHGetNameFromIDList с флагом SIGDN_DESKTOPABSOLUTEPARSING, и, наконец, это вернет строку CLSID, которую мы можем указать для цели файла .lnk с помощью IShellLinkW::SetPath(). Он работает так, как ожидалось.

Обратите внимание, что я не уверен, могут ли существовать особые сценарии (редкие цели файла lnk), в которых это не может работать должным образом. Я не нашел этот случай ошибки.

А при необходимости нормальное отображаемое имя можно получить с помощью флага SIGDN_NORMALDISPLAY, а также с помощью вызова функции SHGetFileInfo, как указано в поле для комментариев к основному сообщению.


Кредиты для пользователей, которые предложили мне поиск PIDL и его использование, потому что я не был уверен в том, что исследовать, чтобы решить эту проблему.

Я также отдаю должное библиотеке с открытым исходным кодом Ванара, которая помогла мне найти правильные P/Invokes каждой функции SH* в их исходном коде, особенно подпись для SHGetNameFromIDList.

Множество способов получить DisplayName из pidl, некоторые из которых доступны через интерфейс ShellItem (например, GetDisplayName()), для связанных элементов — относительные или абсолютные. То, что вы используете, связано с контекстом и типом пути. Одно замечание по поводу маршаллера: вы часто видите в примере кода использование Marshal.AllocHGlobal. Вы должны использовать Marshal.AllocCoTaskMem (собственный CoTaskMemAlloc) для освобождения, как описано.

Jimi 28.05.2019 13:46

Если вы видите, что кто-то использует SHGetMalloc для инициализации интерфейса IMalloc, это старый код: этот метод заменен CoTaskMemAlloc.

Jimi 28.05.2019 13:50

Спасибо за комментарий и за советы!. Возможно, следующее не по теме, но я хотел бы сказать, что для меня WindowsAPICodePack кажется намного лучшим (последовательным) исходным кодом, чтобы взять в качестве примера (и скопировать) любой интерфейс, связанный с IShellItem/IShellFolder/IShellView и т. д. В любом случае, Vanara имеет обширную коллекцию P/Invokes, и в некоторых случаях это действительно полезно.

ElektroStudios 28.05.2019 14:18

Другие вопросы по теме