Ссылки оболочки

Ссылка на оболочку — это объект данных, содержащий сведения, используемые для доступа к другому объекту в пространстве имен оболочки, т. е. любому объекту, видимому через Windows Обозреватель. К типам объектов, доступ к которым можно получить через ссылки оболочки, относятся файлы, папки, диски и принтеры. Ссылка на оболочку позволяет пользователю или приложению получить доступ к объекту из любой точки пространства имен. Пользователю или приложению не нужно знать текущее имя и расположение объекта.

Пользователь создает ссылку на оболочку, выбрав команду Создать ярлык в контекстном меню объекта. Система автоматически создает значок для ссылки оболочки, объединяя значок объекта с небольшой стрелкой (известной как системный значок наложения ссылки), которая отображается в левом нижнем углу значка. Ссылка на оболочку со значком называется ярлыком; однако термины ссылка на оболочку и ярлык часто используются взаимозаменяемо. Как правило, пользователь создает ярлыки для быстрого доступа к объектам, хранящимся во вложенных папках или общих папках на других компьютерах. Например, пользователь может создать ярлык для документа Microsoft Word, который находится во вложенной папке, и разместить значок ярлыка на рабочем столе. Затем пользователь может открыть документ, дважды щелкнув значок ярлыка. Если документ перемещен или переименован после создания ярлыка, система попытается обновить ярлык при следующем его выборе пользователем.

Приложения также могут создавать и использовать ссылки и ярлыки оболочки. Например, текстовое приложение может создать ссылку на оболочку для реализации списка последних использованных документов. Приложение создает ссылку оболочки с помощью интерфейса IShellLink для создания объекта ссылки оболочки. Приложение использует интерфейс IPersistFile или IPersistStream для хранения объекта в файле или потоке.

Примечание

IShellLink нельзя использовать для создания ссылки на URL-адрес.

 

В этом обзоре описан интерфейс IShellLink и объясняется, как использовать его для создания и разрешения ссылок оболочки в приложении на основе Microsoft Win32. Так как структуры ссылок оболочки основаны на МОДЕЛИ ОБЪЕКТОВ КОМПОНЕНТОВ OLE (COM), вы должны ознакомиться с основными понятиями программирования COM и OLE, прежде чем читать этот обзор.

Если пользователь создает ярлык для объекта, а имя или расположение объекта позже изменяется, система автоматически выполняет действия по обновлению или разрешению ярлыка при следующем его выборе. Однако если приложение создает ссылку оболочки и сохраняет ее в потоке, система не пытается автоматически разрешить эту ссылку. Приложение должно разрешить ссылку, вызвав метод IShellLink::Resolve .

При создании ссылки оболочки система сохраняет сведения о ней. При разрешении ссылки (автоматически или с помощью вызова IShellLink::Resolve ) система сначала получает путь, связанный со ссылкой оболочки, с помощью указателя на список идентификаторов ссылки оболочки. Дополнительные сведения о списке идентификаторов см. в разделах Идентификаторы элементов и Списки идентификаторов. Система выполняет поиск связанного объекта в этом пути и, если находит объект, разрешает ссылку. Если системе не удается найти объект, она вызывает службу отслеживания распределенных ссылок и идентификаторов объектов (DLT), если она доступна, чтобы найти объект. Если служба DLT недоступна или не может найти объект, система ищет объект в том же каталоге с тем же временем создания файла и атрибутами, но с другим именем. Этот тип поиска разрешает ссылку на объект, который был переименован.

Если системе по-прежнему не удается найти объект, она выполняет поиск по каталогам, рабочему столу и локальным томам, рекурсивно просматривая в дереве каталогов объект с тем же именем или временем создания. Если система по-прежнему не находит совпадение, отображается диалоговое окно с запросом у пользователя ввести расположение. Приложение может подавить диалоговое окно, указав значение SLR_NO_UI в вызове IShellLink::Resolve.

Инициализация библиотеки объектов компонентов

Прежде чем приложение сможет создавать и разрешать ярлыки, оно должно инициализировать библиотеку объектов компонентов, вызвав функцию CoInitialize . Для каждого вызова CoInitialize требуется соответствующий вызов функции CoUninitialize , которую приложение должно вызывать при завершении работы. Вызов CoUninitialize гарантирует, что приложение не завершит работу, пока не получит все ожидающие сообщения.

Имена Location-Independent

Система предоставляет независимые от расположения имена для ссылок оболочки на объекты, хранящиеся в общих папках. Если объект хранится локально, система предоставляет локальный путь и имя файла для объекта. Если объект хранится удаленно, система предоставляет имя сетевого ресурса универсального соглашения об именовании (UNC) для объекта. Так как система предоставляет имена, независимые от расположения, ссылка на оболочку может служить универсальным именем для файла, который можно передать на другие компьютеры.

Когда пользователь создает ярлык для объекта, выбрав команду Создать ярлык в контекстном меню объекта, Windows сохраняет сведения, необходимые для доступа к объекту, в файле ссылки — двоичном файле с расширением LNK. Файл ссылки содержит следующие сведения:

  • Расположение (путь) объекта, на который ссылается ярлык (называемый соответствующим объектом).
  • Рабочий каталог соответствующего объекта.
  • Список аргументов, которые система передает соответствующему объекту при активации метода IContextMenu::InvokeCommand для ярлыка.
  • Команда show, используемая для задания начального состояния отображения соответствующего объекта. Это одно из SW_ значений, описанных в разделе ShowWindow.
  • Расположение (путь и индекс) значка ярлыка.
  • Строка описания ярлыка.
  • Сочетание клавиш для сочетания клавиш.

При удалении файла ссылки соответствующий объект не затрагивается.

Если вы создаете ярлык для другого ярлыка, система просто копирует файл ссылки, а не создает новый файл ссылки. В этом случае сочетания клавиш не будут независимы друг от друга.

Приложение может зарегистрировать расширение имени файла в качестве ярлыка типа файла. Если файл имеет расширение имени файла, которое было зарегистрировано как тип файла ярлыка, система автоматически добавляет в значок файла определенный системой значок наложения ссылок (небольшая стрелка). Чтобы зарегистрировать расширение имени файла в качестве ярлыка типа файла, необходимо добавить значение IsShortcut в описание реестра расширения имени файла, как показано в примере ниже. Обратите внимание, что для того, чтобы значок наложения вступил в силу, необходимо перезапустить оболочку. IsShortcut не имеет значения данных.

HKEY_CLASSES_ROOT
   .xyz
      (Default) = XYZApp
   XYZApp
      IsShortcut

Имена сочетаний клавиш

Имя ярлыка, которое представляет собой строку, которая отображается под значком ссылки оболочки, на самом деле является именем файла самого ярлыка. Пользователь может изменить строку описания, выбрав ее и введя новую строку.

Расположение ярлыков в пространстве имен

Ярлык может существовать на рабочем столе или в любом месте пространства имен оболочки. Аналогичным образом, объект, связанный с ярлыком, также может существовать в любом месте пространства имен оболочки. Приложение может использовать метод IShellLink::SetPath , чтобы задать путь и имя файла для связанного объекта, а метод IShellLink::GetPath — для получения текущего пути и имени файла для объекта.

Ярлык рабочего каталога

Рабочий каталог — это каталог, в котором соответствующий объект ярлыка загружает или хранит файлы, если пользователь не идентифицирует определенный каталог. Файл ссылки содержит имя рабочего каталога для соответствующего объекта. Приложение может задать имя рабочего каталога для соответствующего объекта с помощью метода IShellLink::SetWorkingDirectory и получить имя текущего рабочего каталога для соответствующего объекта с помощью метода IShellLink::GetWorkingDirectory .

Сочетания аргументов командной строки

Файл ссылки содержит аргументы командной строки, которые оболочка передает соответствующему объекту, когда пользователь выбирает ссылку. Приложение может задать аргументы командной строки для ярлыка с помощью метода IShellLink::SetArguments . Полезно задать аргументы командной строки, когда соответствующее приложение, например компоновщик или компилятор, принимает специальные флаги в качестве аргументов. Приложение может получить аргументы командной строки из ярлыка с помощью метода IShellLink::GetArguments .

Команды отображения ярлыков

Когда пользователь дважды щелкает ярлык, система запускает приложение, связанное с соответствующим объектом, и задает начальное состояние отображения приложения на основе команды show, указанной ярлыком. Команда show может быть любым из SW_ значений, включенных в описание функции ShowWindow . Приложение может задать команду show для ярлыка с помощью метода IShellLink::SetShowCmd и получить текущую команду show с помощью метода IShellLink::GetShowCmd .

Ярлыки

Как и другие объекты оболочки, ярлык имеет значок. Пользователь обращается к объекту, связанному с ярлыком, дважды щелкнув значок ярлыка. Когда система создает значок для ярлыка, она использует растровое изображение соответствующего объекта и добавляет системный значок наложения ссылки (небольшая стрелка) в левый нижний угол. Приложение может задать расположение (путь и индекс) значка ярлыка с помощью метода IShellLink::SetIconLocation . Приложение может получить это расположение с помощью метода IShellLink::GetIconLocation .

Описания сочетаний клавиш

Ярлыки имеют описания, но пользователь никогда не видит их. Приложение может использовать описание для хранения любой текстовой информации. Описания задаются с помощью метода IShellLink::SetDescription и извлекаются с помощью метода IShellLink::GetDescription .

Сочетания клавиш

С объектом сочетания клавиш может быть связано сочетание клавиш. Сочетания клавиш позволяют пользователю нажимать сочетание клавиш для активации сочетания клавиш. Приложение может задать сочетание клавиш для сочетания клавиш с помощью метода IShellLink::SetHotkey и получить текущее сочетание клавиш с помощью метода IShellLink::GetHotkey .

Идентификаторы элементов и списки идентификаторов

Оболочка использует идентификаторы объектов в пространстве имен оболочки. Все объекты, видимые в оболочке (файлы, каталоги, серверы, рабочие группы и т. д.), имеют уникальные идентификаторы среди объектов в родительской папке. Эти идентификаторы называются идентификаторами элементов и имеют тип данных SHITEMID , как определено в файле заголовка Shtypes.h. Идентификатор элемента — это поток байтов переменной длины, содержащий сведения, идентифицирующий объект в папке. Только создатель идентификатора элемента знает его содержимое и формат. Единственная часть идентификатора элемента, которую использует оболочка, — это первые два байта, которые определяют размер идентификатора.

Каждая родительская папка имеет собственный идентификатор элемента, который идентифицирует ее в своей родительской папке. Таким образом, любой объект оболочки можно однозначно идентифицировать с помощью списка идентификаторов элементов. В родительской папке хранится список идентификаторов для содержащихся в ней элементов. Список имеет тип данных ITEMIDLIST . Списки идентификаторов элементов выделяются оболочкой и могут передаваться через интерфейсы оболочки, например IShellFolder. Важно помнить, что каждый идентификатор в списке идентификаторов элементов имеет смысл только в контексте родительской папки.

Приложение может задать список идентификаторов элементов ярлыка с помощью метода IShellLink::SetIDList . Этот метод полезен при настройке ярлыка для объекта, который не является файлом, например принтера или диска. Приложение может получить список идентификаторов элементов ярлыка с помощью метода IShellLink::GetIDList .

В этом разделе приведены примеры, демонстрирующие создание и разрешение ярлыков в приложении на основе Win32. В этом разделе предполагается, что вы знакомы с программированием Win32, C++ и OLE COM.

Создание ярлыка и ярлыка папки для файла

Пример функции CreateLink в следующем примере создает ярлык. Параметры включают указатель на имя файла для ссылки, указатель на имя создаваемого ярлыка и указатель на описание ссылки. Описание состоит из строки "Ярлык к имени файла", где имя файла — это имя файла, на который необходимо создать ссылку.

Чтобы создать ярлык папки с помощью примера функции CreateLink, вызовите CoCreateInstance с помощью CLSID_FolderShortcut вместо CLSID_ShellLink (CLSID_FolderShortcut поддерживает IShellLink). Весь остальной код остается прежним.

Так как CreateLink вызывает функцию CoCreateInstance , предполагается, что функция CoInitialize уже была вызвана. CreateLink использует интерфейс IPersistFile для сохранения ярлыка и интерфейс IShellLink для хранения имени и описания файла.

// CreateLink - Uses the Shell's IShellLink and IPersistFile interfaces 
//              to create and store a shortcut to the specified object. 
//
// Returns the result of calling the member functions of the interfaces. 
//
// Parameters:
// lpszPathObj  - Address of a buffer that contains the path of the object,
//                including the file name.
// lpszPathLink - Address of a buffer that contains the path where the 
//                Shell link is to be stored, including the file name.
// lpszDesc     - Address of a buffer that contains a description of the 
//                Shell link, stored in the Comment field of the link
//                properties.

#include "stdafx.h"
#include "windows.h"
#include "winnls.h"
#include "shobjidl.h"
#include "objbase.h"
#include "objidl.h"
#include "shlguid.h"

HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc) 
{ 
    HRESULT hres; 
    IShellLink* psl; 
 
    // Get a pointer to the IShellLink interface. It is assumed that CoInitialize
    // has already been called.
    hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); 
    if (SUCCEEDED(hres)) 
    { 
        IPersistFile* ppf; 
 
        // Set the path to the shortcut target and add the description. 
        psl->SetPath(lpszPathObj); 
        psl->SetDescription(lpszDesc); 
 
        // Query IShellLink for the IPersistFile interface, used for saving the 
        // shortcut in persistent storage. 
        hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); 
 
        if (SUCCEEDED(hres)) 
        { 
            WCHAR wsz[MAX_PATH]; 
 
            // Ensure that the string is Unicode. 
            MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH); 
            
            // Add code here to check return value from MultiByteWideChar 
            // for success.
 
            // Save the link by calling IPersistFile::Save. 
            hres = ppf->Save(wsz, TRUE); 
            ppf->Release(); 
        } 
        psl->Release(); 
    } 
    return hres; 

Разрешение ярлыка

Приложению может потребоваться доступ к ярлыку, который был создан ранее, и управлять им. Эта операция называется разрешением ярлыка.

Определяемая приложением функция ResolveIt в следующем примере разрешает ярлык. Его параметры включают дескриптор окна, указатель на путь ярлыка и адрес буфера, который получает новый путь к объекту. Дескриптор окна определяет родительское окно для всех окон сообщений, которые может потребоваться отобразить оболочке. Например, оболочка может отображать окно сообщения, если ссылка находится на носителе без общего доступа, если возникают проблемы с сетью, если пользователю необходимо вставить гибкий диск и т. д.

Функция ResolveIt вызывает функцию CoCreateInstance и предполагает, что функция CoInitialize уже была вызвана. Обратите внимание, что ResolveIt должен использовать интерфейс IPersistFile для хранения сведений о ссылке. IPersistFile реализуется объектом IShellLink . Сведения о ссылке должны быть загружены до получения сведений о пути, как показано далее в примере. Если не загрузить сведения о ссылке, вызовы функций-членов IShellLink::GetPath и IShellLink::GetDescription завершаются сбоем.

// ResolveIt - Uses the Shell's IShellLink and IPersistFile interfaces 
//             to retrieve the path and description from an existing shortcut. 
//
// Returns the result of calling the member functions of the interfaces. 
//
// Parameters:
// hwnd         - A handle to the parent window. The Shell uses this window to 
//                display a dialog box if it needs to prompt the user for more 
//                information while resolving the link.
// lpszLinkFile - Address of a buffer that contains the path of the link,
//                including the file name.
// lpszPath     - Address of a buffer that receives the path of the link
                  target, including the file name.
// lpszDesc     - Address of a buffer that receives the description of the 
//                Shell link, stored in the Comment field of the link
//                properties.

#include "stdafx.h"
#include "windows.h"
#include "shobjidl.h"
#include "shlguid.h"
#include "strsafe.h"
                            
HRESULT ResolveIt(HWND hwnd, LPCSTR lpszLinkFile, LPWSTR lpszPath, int iPathBufferSize) 
{ 
    HRESULT hres; 
    IShellLink* psl; 
    WCHAR szGotPath[MAX_PATH]; 
    WCHAR szDescription[MAX_PATH]; 
    WIN32_FIND_DATA wfd; 
 
    *lpszPath = 0; // Assume failure 

    // Get a pointer to the IShellLink interface. It is assumed that CoInitialize
    // has already been called. 
    hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); 
    if (SUCCEEDED(hres)) 
    { 
        IPersistFile* ppf; 
 
        // Get a pointer to the IPersistFile interface. 
        hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); 
        
        if (SUCCEEDED(hres)) 
        { 
            WCHAR wsz[MAX_PATH]; 
 
            // Ensure that the string is Unicode. 
            MultiByteToWideChar(CP_ACP, 0, lpszLinkFile, -1, wsz, MAX_PATH); 
 
            // Add code here to check return value from MultiByteWideChar 
            // for success.
 
            // Load the shortcut. 
            hres = ppf->Load(wsz, STGM_READ); 
            
            if (SUCCEEDED(hres)) 
            { 
                // Resolve the link. 
                hres = psl->Resolve(hwnd, 0); 

                if (SUCCEEDED(hres)) 
                { 
                    // Get the path to the link target. 
                    hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATA*)&wfd, SLGP_SHORTPATH); 

                    if (SUCCEEDED(hres)) 
                    { 
                        // Get the description of the target. 
                        hres = psl->GetDescription(szDescription, MAX_PATH); 

                        if (SUCCEEDED(hres)) 
                        {
                            hres = StringCbCopy(lpszPath, iPathBufferSize, szGotPath);
                            if (SUCCEEDED(hres))
                            {
                                // Handle success
                            }
                            else
                            {
                                // Handle the error
                            }
                        }
                    }
                } 
            } 

            // Release the pointer to the IPersistFile interface. 
            ppf->Release(); 
        } 

        // Release the pointer to the IShellLink interface. 
        psl->Release(); 
    } 
    return hres; 
}

Создание ярлыка для нефайлового объекта

Создание ярлыка для нефайлового объекта, например принтера, аналогично созданию ярлыка для файла, но вместо задания пути к файлу необходимо задать список идентификаторов для принтера. Чтобы задать список идентификаторов, вызовите метод IShellLink::SetIDList , указав адрес списка идентификаторов.

Каждый объект в пространстве имен оболочки имеет идентификатор элемента. Оболочка часто объединяет идентификаторы элементов в списки, завершающиеся нулевым значением, состоящие из любого количества идентификаторов элементов. Дополнительные сведения об идентификаторах элементов см. в разделах Идентификаторы элементов и Списки идентификаторов.

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

Получив идентификатор класса для IShellFolder, можно вызвать функцию CoCreateInstance , чтобы получить адрес интерфейса. Затем можно вызвать интерфейс для перечисления объектов в папке и получения адреса идентификатора элемента для объекта, который вы ищете. Наконец, можно использовать адрес в вызове функции-члена IShellLink::SetIDList , чтобы создать ярлык для объекта .