Shell 链接

Shell 链接是一个数据对象,其中包含用于访问 Shell 命名空间中的另一个对象(即通过 Windows 资源管理器可见的任何对象)的信息。 可通过 Shell 链接访问的对象类型包括文件、文件夹、磁盘驱动器和打印机。 Shell 链接允许用户或应用程序从命名空间中的任意位置访问对象。 用户或应用程序不需要知道对象的当前名称和位置。

用户通过从对象的快捷菜单中选择“ 创建快捷方式” 命令来创建 Shell 链接。 系统将对象的图标与显示在图标左下角的称为系统定义链接覆盖图标) 的小 (箭头相结合,自动为 Shell 链接创建一个图标。 具有图标的 Shell 链接称为快捷方式;但是,术语“Shell 链接”和“快捷方式”通常可互换使用。 通常,用户创建快捷方式来快速访问存储在子文件夹或其他计算机上的共享文件夹中的对象。 例如,用户可以创建位于子文件夹中的 Microsoft Word 文档的快捷方式,并将快捷方式图标放在桌面上。 然后,用户可以通过双击快捷方式图标打开文档。 如果在创建快捷方式后移动或重命名文档,系统将在用户下次选择该快捷方式时尝试更新该快捷方式。

应用程序还可以创建和使用 Shell 链接和快捷方式。 例如,字处理应用程序可能会创建 Shell 链接来实现最近使用的文档的列表。 应用程序通过使用 IShellLink 接口创建 Shell 链接对象来创建 Shell 链接。 应用程序使用 IPersistFileIPersistStream 接口将对象存储在文件或流中。

注意

不能使用 IShellLink 创建指向 URL 的链接。

 

本概述介绍 IShellLink 接口,并说明如何使用它从基于 Microsoft Win32 的应用程序中创建和解析 Shell 链接。 由于 Shell 链接的设计基于 OLE 组件对象模型 (COM) ,因此在阅读本概述之前,应熟悉 COM 和 OLE 编程的基本概念。

如果用户创建了对象的快捷方式,并且该对象的名称或位置稍后发生更改,则当用户下次选择该快捷方式时,系统会自动执行更新或解析该快捷方式的步骤。 但是,如果应用程序创建 Shell 链接并将其存储在流中,则系统不会自动尝试解析该链接。 应用程序必须通过调用 IShellLink::Resolve 方法解析链接。

创建 Shell 链接时,系统会保存有关该链接的信息。 自动解析链接或使用 IShellLink::Resolve 调用解析链接时,系统首先使用指向 Shell 链接标识符列表的指针检索与 Shell 链接关联的路径。 有关标识符列表的详细信息,请参阅 项标识符和标识符列表。 系统在该路径中搜索关联的对象,如果找到该对象,则解析该链接。 如果系统找不到该对象,它会调用 分布式链接跟踪和对象标识符 (DLT) 服务(如果可用)来查找对象。 如果 DLT 服务不可用或找不到该对象,系统会在同一目录中查找具有相同文件创建时间和属性但名称不同的对象。 此类型的搜索解析指向已重命名的对象的链接。

如果系统仍然找不到该对象,它会搜索目录、桌面和本地卷,通过目录树以递归方式查找具有相同名称或创建时间的对象。 如果系统仍然找不到匹配项,则会显示一个对话框,提示用户输入位置。 应用程序可以通过在调用 IShellLink::Resolve 时指定SLR_NO_UI值来禁止显示对话框。

组件对象库的初始化

在应用程序创建和解析快捷方式之前,它必须通过调用 CoInitialize 函数来初始化组件对象库。 每次调用 CoInitialize 都需要对 CoUninitialize 函数进行相应的调用,应用程序应在终止时调用该函数。 对 CoUninitialize 的调用可确保应用程序在收到其所有挂起的消息之前不会终止。

Location-Independent名称

系统为 Shell 链接提供与位置无关的名称,这些链接指向存储在共享文件夹中的对象。 如果对象存储在本地,则系统会提供对象的本地路径和文件名。 如果对象是远程存储的,则系统会为对象提供通用命名约定 (UNC) 网络资源名称。 由于系统提供与位置无关的名称,因此 Shell 链接可用作可传输到其他计算机的文件的通用名称。

当用户通过从对象的快捷菜单中选择“ 创建快捷方式” 命令来创建对象的快捷方式时,Windows 会将访问该对象的所需信息存储在链接文件中(一个文件扩展名为 .lnk 的二进制文件)。 链接文件包含以下信息:

  • 快捷方式 (调用相应对象) 所引用的对象的位置 (路径) 。
  • 相应对象的工作目录。
  • 激活 快捷方式的 IContextMenu::InvokeCommand 方法时,系统传递给相应对象的参数列表。
  • 用于设置相应对象的初始显示状态的 show 命令。 这是 ShowWindow 中描述的SW_值之一。
  • 快捷方式图标的位置 (路径和索引) 。
  • 快捷方式的说明字符串。
  • 快捷方式的键盘快捷方式。

删除链接文件时,相应的对象不受影响。

如果创建另一个快捷方式的快捷方式,则系统只会复制链接文件,而不是创建新的链接文件。 在这种情况下,快捷方式不会相互独立。

应用程序可以将文件扩展名注册为快捷方式文件类型。 如果文件的文件扩展名已注册为快捷方式文件类型,则系统会自动将系统定义的链接覆盖图标 (文件图标) 的小箭头添加到该文件的图标上。 若要将文件扩展名注册为快捷方式文件类型,必须将 IsShortcut 值添加到文件扩展名的注册表说明中,如以下示例所示。 请注意,必须重启 Shell 才能使覆盖图标生效。 IsShortcut 没有数据值。

HKEY_CLASSES_ROOT
   .xyz
      (Default) = XYZApp
   XYZApp
      IsShortcut

快捷方式名称

快捷方式的名称(出现在 Shell 链接图标下方的字符串)实际上是快捷方式本身的文件名。 用户可以通过选择说明字符串并输入新字符串来编辑该字符串。

命名空间中快捷方式的位置

快捷方式可以存在于桌面上或 Shell 命名空间中的任何位置。 同样,与快捷方式关联的 对象也可以存在于 Shell 命名空间中的任意位置。 应用程序可以使用 IShellLink::SetPath 方法设置关联对象的路径和文件名,并使用 IShellLink::GetPath 方法检索对象的当前路径和文件名。

快捷方式工作目录

工作目录是快捷方式的相应对象在用户未标识特定目录时加载或存储文件的目录。 链接文件包含相应对象的工作目录的名称。 应用程序可以使用 IShellLink::SetWorkingDirectory 方法为相应对象设置工作目录的名称,并且可以使用 IShellLink::GetWorkingDirectory 方法检索相应对象的当前工作目录的名称。

快捷方式命令行参数

链接文件包含命令行参数,当用户选择链接时,Shell 会将这些参数传递给相应的对象。 应用程序可以使用 IShellLink::SetArguments 方法设置快捷方式的命令行参数。 当相应的应用程序(如链接器或编译器)采用特殊标志作为参数时,设置命令行参数很有用。 应用程序可以使用 IShellLink::GetArguments 方法从快捷方式检索命令行参数。

快捷方式显示命令

当用户双击快捷方式时,系统将启动与相应对象关联的应用程序,并根据快捷方式指定的 show 命令设置应用程序的初始显示状态。 show 命令可以是 ShowWindow 函数说明中包含的任何SW_值。 应用程序可以使用 IShellLink::SetShowCmd 方法设置快捷方式的 show 命令,并且可以使用 IShellLink::GetShowCmd 方法检索当前 show 命令。

快捷方式图标

与其他 Shell 对象一样,快捷方式具有图标。 用户通过双击快捷方式的图标访问与快捷方式关联的对象。 当系统为快捷方式创建图标时,它将使用相应对象的位图,并将系统定义的链接覆盖图标添加到左下角 (一个小箭头) 。 应用程序可以使用 IShellLink::SetIconLocation 方法设置快捷方式图标的位置 (路径和索引) 。 应用程序可以使用 IShellLink::GetIconLocation 方法检索此位置。

快捷方式说明

快捷方式具有说明,但用户永远不会看到它们。 应用程序可以使用说明来存储任何文本信息。 说明使用 IShellLink::SetDescription 方法进行设置,并使用 IShellLink::GetDescription 方法检索。

快捷键盘快捷方式

快捷方式对象可以具有与之关联的键盘快捷方式。 键盘快捷方式允许用户按组合键来激活快捷方式。 应用程序可以使用 IShellLink::SetHotkey 方法设置快捷方式的键盘快捷方式,并且可以使用 IShellLink::GetHotkey 方法检索当前键盘快捷方式。

项标识符和标识符列表

Shell 使用 Shell 命名空间中的对象标识符。 Shell 中可见的所有对象 (文件、目录、服务器、工作组等) 在其父文件夹中的对象之间具有唯一标识符。 这些标识符称为项标识符,它们具有 Shtypes.h 头文件中定义的 SHITEMID 数据类型。 项标识符是一个可变长度的字节流,其中包含标识文件夹中对象的信息。 只有项标识符的创建者知道标识符的内容和格式。 Shell 使用的项目标识符的唯一部分是前两个字节,它们指定标识符的大小。

每个父文件夹都有自己的项目标识符,用于在自己的父文件夹中标识它。 因此,任何 Shell 对象都可以由项标识符列表唯一标识。 父文件夹保留其包含的项目的标识符列表。 列表具有 ITEMIDLIST 数据类型。 项标识符列表由 Shell 分配,可以跨 Shell 接口(如 IShellFolder)传递。 请务必记住,项目标识符列表中的每个标识符仅在其父文件夹的上下文中有意义。

应用程序可以使用 IShellLink::SetIDList 方法设置快捷方式的项标识符列表。 将快捷方式设置为非文件的对象(例如打印机或磁盘驱动器)时,此方法非常有用。 应用程序可以使用 IShellLink::GetIDList 方法检索快捷方式的项标识符列表。

本部分包含的示例演示如何在基于 Win32 的应用程序中创建和解析快捷方式。 本部分假定你熟悉 Win32、C++和 OLE COM 编程。

创建文件的快捷方式和文件夹快捷方式

以下示例中的 CreateLink 示例函数创建快捷方式。 参数包括指向要链接到的文件名称的指针、指向要创建的快捷方式名称的指针,以及指向链接说明的指针。 说明由字符串“ 文件名快捷方式”组成,其中 文件名 是要链接到的文件的名称。

若要使用 CreateLink 示例函数创建文件夹快捷方式,请使用 CLSID_FolderShortcut 调用 CoCreateInstance ,而不是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 函数解析快捷方式。 其参数包括窗口句柄、指向快捷方式路径的指针,以及接收对象新路径的缓冲区的地址。 窗口句柄标识 Shell 可能需要显示的任何消息框的父窗口。 例如,如果链接位于非共享媒体上、发生网络问题、用户需要插入软盘等,Shell 可以显示消息框。

ResolveIt 函数调用 CoCreateInstance 函数,并假定已调用 CoInitialize 函数。 请注意,ResolveIt 需要使用 IPersistFile 接口来存储链接信息。 IPersistFileIShellLink 对象实现。 必须先加载链接信息,然后才能检索路径信息,本示例稍后将显示该信息。 未能加载链接信息会导致对 IShellLink::GetPathIShellLink::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 方法,指定标识符列表的地址。

Shell 命名空间中的每个对象都有一个项标识符。 Shell 通常会将项标识符串联到以 null 结尾的列表中,这些列表由任意数量的项标识符组成。 有关项标识符的详细信息,请参阅 项标识符和标识符列表

一般情况下,如果需要将快捷方式设置为没有文件名的项(例如打印机),则已经有指向对象的 IShellFolder 接口的指针。 IShellFolder 用于创建命名空间扩展。

获得 IShellFolder 的类标识符后,可以调用 CoCreateInstance 函数来检索接口的地址。 然后,可以调用 接口来枚举 文件夹中的对象,并检索要搜索的对象的项目标识符的地址。 最后,可以在调用 IShellLink::SetIDList 成员函数时使用 地址来创建对象的快捷方式。