Vínculos de Shell

Un vínculo de Shell es un objeto de datos que contiene información utilizada para tener acceso a otro objeto en el espacio de nombres del Shell, es decir, cualquier objeto visible a través del Explorador de Windows. Los tipos de objetos a los que se puede acceder a través de vínculos de Shell incluyen archivos, carpetas, unidades de disco e impresoras. Un vínculo de Shell permite a un usuario o una aplicación acceder a un objeto desde cualquier lugar del espacio de nombres. El usuario o la aplicación no necesitan conocer el nombre y la ubicación actuales del objeto.

El usuario crea un vínculo de Shell eligiendo el comando Crear acceso directo en el menú contextual de un objeto. El sistema crea automáticamente un icono para el vínculo shell combinando el icono del objeto con una flecha pequeña (conocida como icono de superposición de vínculo definido por el sistema) que aparece en la esquina inferior izquierda del icono. Un vínculo de Shell que tiene un icono se denomina acceso directo; sin embargo, los términos vínculo y acceso directo de Shell se usan a menudo indistintamente. Normalmente, el usuario crea accesos directos para obtener acceso rápido a los objetos almacenados en subcarpetas o en carpetas compartidas en otros equipos. Por ejemplo, un usuario puede crear un acceso directo a un documento de Microsoft Word que se encuentra en una subcarpeta y colocar el icono de acceso directo en el escritorio. Después, el usuario puede abrir el documento haciendo doble clic en el icono de acceso directo. Si el documento se mueve o cambia de nombre después de crear el acceso directo, el sistema intentará actualizar el acceso directo la próxima vez que el usuario lo seleccione.

Las aplicaciones también pueden crear y usar vínculos y accesos directos de Shell. Por ejemplo, una aplicación de procesamiento de texto podría crear un vínculo de Shell para implementar una lista de los documentos usados más recientemente. Una aplicación crea un vínculo de Shell mediante la interfaz IShellLink para crear un objeto de vínculo de Shell. La aplicación usa la interfaz IPersistFile o IPersistStream para almacenar el objeto en un archivo o secuencia.

Nota

No puede usar IShellLink para crear un vínculo a una dirección URL.

 

En esta introducción se describe la interfaz IShellLink y se explica cómo usarlo para crear y resolver vínculos de Shell desde una aplicación basada en Microsoft Win32. Dado que el diseño de vínculos de Shell se basa en el modelo de objetos componentes OLE (COM), debe estar familiarizado con los conceptos básicos de la programación COM y OLE antes de leer esta información general.

Si un usuario crea un acceso directo a un objeto y posteriormente se cambia el nombre o la ubicación del objeto, el sistema realiza automáticamente los pasos necesarios para actualizar o resolver, el acceso directo la próxima vez que el usuario lo seleccione. Sin embargo, si una aplicación crea un vínculo de Shell y lo almacena en una secuencia, el sistema no intenta resolver automáticamente el vínculo. La aplicación debe resolver el vínculo llamando al método IShellLink::Resolve .

Cuando se crea un vínculo de Shell, el sistema guarda información sobre el vínculo. Al resolver un vínculo (ya sea automáticamente o con una llamada IShellLink::Resolve ), el sistema recupera primero la ruta de acceso asociada al vínculo shell mediante un puntero a la lista de identificadores del vínculo de Shell. Para obtener más información sobre la lista de identificadores, vea Identificadores de elementos y listas de identificadores. El sistema busca el objeto asociado en esa ruta de acceso y, si encuentra el objeto, resuelve el vínculo. Si el sistema no encuentra el objeto, llama al servicio Distributed Link Tracking y Object Identifiers (DLT), si está disponible, para localizar el objeto. Si el servicio DLT no está disponible o no encuentra el objeto , el sistema busca en el mismo directorio un objeto con la misma hora de creación de archivos y atributos, pero con un nombre diferente. Este tipo de búsqueda resuelve un vínculo a un objeto cuyo nombre se ha cambiado.

Si el sistema sigue sin encontrar el objeto, busca en los directorios, el escritorio y los volúmenes locales, buscando de forma recursiva el árbol de directorios de un objeto con el mismo nombre o tiempo de creación. Si el sistema sigue sin encontrar una coincidencia, muestra un cuadro de diálogo que solicita al usuario una ubicación. Una aplicación puede suprimir el cuadro de diálogo especificando el valor SLR_NO_UI en una llamada a IShellLink::Resolve.

Inicialización de la biblioteca de objetos componentes

Para que una aplicación pueda crear y resolver accesos directos, debe inicializar la biblioteca de objetos de componente mediante una llamada a la función CoInitialize . Cada llamada a CoInitialize requiere una llamada correspondiente a la función CoUninitialize , a la que una aplicación debe llamar cuando finaliza. La llamada a CoUninitialize garantiza que la aplicación no finalice hasta que haya recibido todos sus mensajes pendientes.

nombres de Location-Independent

El sistema proporciona nombres independientes de ubicación para los vínculos de Shell a objetos almacenados en carpetas compartidas. Si el objeto se almacena localmente, el sistema proporciona la ruta de acceso local y el nombre de archivo del objeto. Si el objeto se almacena de forma remota, el sistema proporciona un nombre de recurso de red de convención de nomenclatura universal (UNC) para el objeto. Dado que el sistema proporciona nombres independientes de la ubicación, un vínculo de Shell puede servir como nombre universal para un archivo que se puede transferir a otros equipos.

Cuando el usuario crea un acceso directo a un objeto eligiendo el comando Crear acceso directo en el menú contextual del objeto, Windows almacena la información que necesita para tener acceso al objeto en un archivo de vínculo, un archivo binario que tiene la extensión de nombre de archivo .lnk. Un archivo de vínculo contiene la siguiente información:

  • Ubicación (ruta de acceso) del objeto al que hace referencia el acceso directo (denominado objeto correspondiente).
  • Directorio de trabajo del objeto correspondiente.
  • Lista de argumentos que el sistema pasa al objeto correspondiente cuando se activa el método IContextMenu::InvokeCommand para el acceso directo.
  • Comando show usado para establecer el estado de presentación inicial del objeto correspondiente. Se trata de uno de los valores de SW_ descritos en ShowWindow.
  • Ubicación (ruta de acceso e índice) del icono del acceso directo.
  • Cadena de descripción del acceso directo.
  • Método abreviado de teclado para el método abreviado.

Cuando se elimina un archivo de vínculo, el objeto correspondiente no se ve afectado.

Si crea un acceso directo a otro acceso directo, el sistema simplemente copia el archivo de vínculo en lugar de crear un nuevo archivo de vínculo. En este caso, los accesos directos no serán independientes entre sí.

Una aplicación puede registrar una extensión de nombre de archivo como un tipo de archivo abreviado. Si un archivo tiene una extensión de nombre de archivo que se ha registrado como un tipo de archivo de acceso directo, el sistema agrega automáticamente el icono de superposición de vínculo definido por el sistema (una flecha pequeña) al icono del archivo. Para registrar una extensión de nombre de archivo como un tipo de archivo abreviado, debe agregar el valor IsShortcut a la descripción del Registro de la extensión de nombre de archivo, como se muestra en el ejemplo siguiente. Tenga en cuenta que el shell debe reiniciarse para que el icono de superposición surta efecto. IsShortcut no tiene ningún valor de datos.

HKEY_CLASSES_ROOT
   .xyz
      (Default) = XYZApp
   XYZApp
      IsShortcut

Nombres de acceso directo

El nombre del acceso directo, que es una cadena que aparece debajo del icono de vínculo shell, es realmente el nombre de archivo del propio acceso directo. El usuario puede editar la cadena de descripción seleccionándola y escribiendo una nueva cadena.

Ubicación de accesos directos en el espacio de nombres

Un acceso directo puede existir en el escritorio o en cualquier parte del espacio de nombres del Shell. Del mismo modo, el objeto asociado al acceso directo también puede existir en cualquier lugar del espacio de nombres del shell. Una aplicación puede usar el método IShellLink::SetPath para establecer la ruta de acceso y el nombre de archivo del objeto asociado, y el método IShellLink::GetPath para recuperar la ruta de acceso actual y el nombre de archivo del objeto.

Directorio de trabajo de acceso directo

El directorio de trabajo es el directorio donde el objeto correspondiente de un acceso directo carga o almacena archivos cuando el usuario no identifica un directorio específico. Un archivo de vínculo contiene el nombre del directorio de trabajo para el objeto correspondiente. Una aplicación puede establecer el nombre del directorio de trabajo para el objeto correspondiente mediante el método IShellLink::SetWorkingDirectory y puede recuperar el nombre del directorio de trabajo actual para el objeto correspondiente mediante el método IShellLink::GetWorkingDirectory .

Método abreviado de argumentos de línea de comandos

Un archivo de vínculo contiene argumentos de línea de comandos que el Shell pasa al objeto correspondiente cuando el usuario selecciona el vínculo. Una aplicación puede establecer los argumentos de la línea de comandos para un acceso directo mediante el método IShellLink::SetArguments . Resulta útil establecer argumentos de línea de comandos cuando la aplicación correspondiente, como un enlazador o compilador, toma marcas especiales como argumentos. Una aplicación puede recuperar los argumentos de la línea de comandos de un acceso directo mediante el método IShellLink::GetArguments .

Comandos de presentación de acceso directo

Cuando el usuario hace doble clic en un acceso directo, el sistema inicia la aplicación asociada al objeto correspondiente y establece el estado de presentación inicial de la aplicación en función del comando show especificado por el acceso directo. El comando show puede ser cualquiera de los valores de SW_ incluidos en la descripción de la función ShowWindow . Una aplicación puede establecer el comando show para un acceso directo mediante el método IShellLink::SetShowCmd y puede recuperar el comando show actual mediante el método IShellLink::GetShowCmd .

Iconos de acceso directo

Al igual que otros objetos shell, un acceso directo tiene un icono. El usuario accede al objeto asociado a un acceso directo haciendo doble clic en el icono del acceso directo. Cuando el sistema crea un icono para un acceso directo, usa el mapa de bits del objeto correspondiente y agrega el icono de superposición de vínculo definido por el sistema (una flecha pequeña) a la esquina inferior izquierda. Una aplicación puede establecer la ubicación (ruta de acceso e índice) del icono de un acceso directo mediante el método IShellLink::SetIconLocation . Una aplicación puede recuperar esta ubicación mediante el método IShellLink::GetIconLocation .

Descripciones de acceso directo

Los accesos directos tienen descripciones, pero el usuario nunca los ve. Una aplicación puede usar una descripción para almacenar cualquier información de texto. Las descripciones se establecen mediante el método IShellLink::SetDescription y se recuperan mediante el método IShellLink::GetDescription .

Métodos abreviados de teclado

Un objeto de método abreviado puede tener asociado un método abreviado de teclado. Los métodos abreviados de teclado permiten al usuario presionar una combinación de teclas para activar un acceso directo. Una aplicación puede establecer el método abreviado de teclado para un método abreviado mediante el método IShellLink::SetHotkey y puede recuperar el método abreviado de teclado actual mediante el método IShellLink::GetHotkey .

Identificadores de elementos y listas de identificadores

Shell usa identificadores de objeto dentro del espacio de nombres del Shell. Todos los objetos visibles en shell (archivos, directorios, servidores, grupos de trabajo, etc.) tienen identificadores únicos entre los objetos de su carpeta primaria. Estos identificadores se denominan identificadores de elemento y tienen el tipo de datos SHITEMID tal como se define en el archivo de encabezado Shtypes.h. Un identificador de elemento es una secuencia de bytes de longitud variable que contiene información que identifica un objeto dentro de una carpeta. Solo el creador de un identificador de elemento conoce el contenido y el formato del identificador. La única parte de un identificador de elemento que usa shell es los dos primeros bytes, que especifican el tamaño del identificador.

Cada carpeta primaria tiene su propio identificador de elemento que lo identifica dentro de su propia carpeta primaria. Por lo tanto, cualquier objeto shell se puede identificar de forma única mediante una lista de identificadores de elemento. Una carpeta primaria mantiene una lista de identificadores para los elementos que contiene. La lista tiene el tipo de datos ITEMIDLIST . Las listas de identificadores de elementos se asignan mediante shell y se pueden pasar a través de interfaces de Shell, como IShellFolder. Es importante recordar que cada identificador de una lista de identificadores de elemento solo es significativo en el contexto de su carpeta primaria.

Una aplicación puede establecer la lista de identificadores de elementos de un acceso directo mediante el método IShellLink::SetIDList . Este método es útil al establecer un acceso directo a un objeto que no es un archivo, como una impresora o una unidad de disco. Una aplicación puede recuperar la lista de identificadores de elementos de un acceso directo mediante el método IShellLink::GetIDList .

Esta sección contiene ejemplos que muestran cómo crear y resolver accesos directos desde una aplicación basada en Win32. En esta sección se da por supuesto que está familiarizado con la programación Win32, C++y OLE COM.

Crear un acceso directo y un acceso directo de carpeta a un archivo

La función de ejemplo CreateLink del ejemplo siguiente crea un acceso directo. Los parámetros incluyen un puntero al nombre del archivo al que se va a vincular, un puntero al nombre del acceso directo que está creando y un puntero a la descripción del vínculo. La descripción consta de la cadena "Acceso directo al nombre de archivo", donde nombre de archivo es el nombre del archivo al que se va a vincular.

Para crear un acceso directo de carpeta mediante la función de ejemplo CreateLink, llame a CoCreateInstance mediante CLSID_FolderShortcut, en lugar de CLSID_ShellLink (CLSID_FolderShortcut admite IShellLink). El resto de código sigue siendo el mismo.

Dado que CreateLink llama a la función CoCreateInstance , se supone que ya se ha llamado a la función CoInitialize . CreateLink usa la interfaz IPersistFile para guardar el acceso directo y la interfaz IShellLink para almacenar el nombre y la descripción del archivo.

// 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; 

Resolución de un acceso directo

Es posible que una aplicación tenga que acceder a un acceso directo y manipularlo previamente. Esta operación se conoce como resolución del acceso directo.

La función ResolveIt definida por la aplicación en el ejemplo siguiente resuelve un acceso directo. Sus parámetros incluyen un identificador de ventana, un puntero a la ruta de acceso directo y la dirección de un búfer que recibe la nueva ruta de acceso al objeto. El identificador de ventana identifica la ventana primaria de los cuadros de mensaje que el shell puede necesitar para mostrar. Por ejemplo, el Shell puede mostrar un cuadro de mensaje si el vínculo está en medios no compartidos, si se producen problemas de red, si el usuario necesita insertar un disco disquete, etc.

La función ResolveIt llama a la función CoCreateInstance y supone que ya se ha llamado a la función CoInitialize . Tenga en cuenta que ResolveIt debe usar la interfaz IPersistFile para almacenar la información del vínculo. IPersistFile se implementa mediante el objeto IShellLink . La información del vínculo debe cargarse antes de recuperar la información de ruta de acceso, que se muestra más adelante en el ejemplo. Si no se carga la información del vínculo, las llamadas a las funciones miembro IShellLink::GetPath e IShellLink::GetDescription producen un error.

// 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; 
}

Crear un acceso directo a un objeto nonfile

La creación de un acceso directo a un objeto que no sea de archivo, como una impresora, es similar a crear un acceso directo a un archivo, excepto que, en lugar de establecer la ruta de acceso al archivo, debe establecer la lista de identificadores en la impresora. Para establecer la lista de identificadores, llame al método IShellLink::SetIDList y especifique la dirección de una lista de identificadores.

Cada objeto del espacio de nombres del Shell tiene un identificador de elemento. El Shell suele concatenar identificadores de elemento en listas terminadas en valores NULL que constan de cualquier número de identificadores de elemento. Para obtener más información sobre los identificadores de elementos, vea Identificadores de elementos y listas de identificadores.

En general, si necesita establecer un acceso directo a un elemento que no tiene un nombre de archivo, como una impresora, ya tendrá un puntero a la interfaz IShellFolder del objeto. IShellFolder se usa para crear extensiones de espacio de nombres.

Una vez que tenga el identificador de clase para IShellFolder, puede llamar a la función CoCreateInstance para recuperar la dirección de la interfaz. A continuación, puede llamar a la interfaz para enumerar los objetos de la carpeta y recuperar la dirección del identificador de elemento para el objeto que está buscando. Por último, puede usar la dirección en una llamada a la función miembro IShellLink::SetIDList para crear un acceso directo al objeto.