Creación de controladores de extensiones de shell

Las funcionalidades del Shell se pueden ampliar con entradas del Registro y archivos .ini. Aunque este enfoque para extender el Shell es sencillo y adecuado para muchos propósitos, es limitado. Por ejemplo, si usa el Registro para especificar un icono personalizado para un tipo de archivo, aparecerá el mismo icono para cada archivo de ese tipo. La extensión del shell con el registro no permite variar el icono de archivos diferentes del mismo tipo. Otros aspectos del Shell, como la hoja de propiedades Propiedades que se puede mostrar cuando se hace clic con el botón derecho en un archivo, no se pueden modificar en absoluto con el Registro.

Un enfoque más eficaz y flexible para extender el shell es implementar controladores de extensión de shell. Estos controladores se pueden implementar para una variedad de acciones que el Shell puede realizar. Antes de realizar la acción, shell consulta el controlador de extensión, lo que le da la oportunidad de modificar la acción. Un ejemplo común es un controlador de extensión de menú contextual. Si se implementa uno para un tipo de archivo, se consultará cada vez que se haga clic con el botón derecho en uno de los archivos. Después, el controlador puede especificar elementos de menú adicionales en un archivo por archivo, en lugar de tener el mismo conjunto para todo el tipo de archivo.

En este documento se describe cómo implementar los controladores de extensión que permiten modificar una variedad de acciones de Shell. Los siguientes controladores están asociados a un tipo de archivo determinado y le permiten especificar en un archivo por archivo:

Controlador Descripción
Controlador de menú contextual Se llama antes de que se muestre el menú contextual de un archivo. Permite agregar elementos al menú contextual en un archivo por archivo.
Controlador de datos Se llama cuando se realiza una operación de arrastrar y colocar en objetos de ArrastrarShell. Permite proporcionar formatos adicionales del Portapapeles al destino de colocación.
Controlador de colocación Se llama cuando un objeto de datos se arrastra o se coloca en un archivo. Permite convertir un archivo en un destino de colocación.
Controlador de iconos Se llama antes de que se muestre el icono de un archivo. Permite reemplazar el icono predeterminado del archivo por un icono personalizado en un archivo por archivo.
Controlador de la hoja de propiedades Se llama antes de que se muestre la hoja de propiedades Properties de un objeto. Permite agregar o reemplazar páginas.
Controlador de imágenes en miniatura Proporciona una imagen para representar el elemento.
Controlador de recuadro informativo Proporciona texto emergente cuando el usuario mantiene el puntero del mouse sobre el objeto.
Controlador de metadatos Proporciona acceso de lectura y escritura a metadatos (propiedades) almacenados en un archivo. Esto se puede usar para ampliar la vista Detalles, la información sobre información, la página de propiedades y las características de agrupación.

 

Otros controladores no están asociados a un tipo de archivo determinado, pero se llaman antes de algunas operaciones de Shell:

Controlador Descripción
Controlador de columnas Lo llama el Explorador de Windows antes de mostrar la vista Detalles de una carpeta. Permite agregar columnas personalizadas a la vista Detalles.
Controlador de enlace de copia Se llama cuando se va a mover, copiar, eliminar o cambiar el nombre de un objeto de carpeta o impresora. Le permite aprobar o vetar la operación.
Controlador de arrastrar y colocar Se llama cuando se arrastra un archivo con el botón derecho del mouse. Permite modificar el menú contextual que se muestra.
Icono Controlador de superposición Se llama antes de que se muestre el icono de un archivo. Permite especificar una superposición para el icono del archivo.
Controlador de búsqueda Se llama para iniciar un motor de búsqueda. Permite implementar un motor de búsqueda personalizado accesible desde el menú Inicio o el Explorador de Windows.

 

Los detalles de cómo implementar controladores de extensión específicos se tratan en las secciones enumeradas anteriormente. En el resto de este documento se tratan algunos problemas de implementación que son comunes a todos los controladores de extensión de Shell.

Implementación de controladores de extensión de Shell

Gran parte de la implementación de un objeto de controlador de extensiones de Shell depende de su tipo. Sin embargo, hay algunos elementos comunes. En esta sección se describen los aspectos de la implementación que comparten todos los controladores de extensión de Shell.

Muchos controladores de extensión de Shell son objetos del modelo de objetos componentes (COM) en proceso. Se deben asignar un GUID y registrarse como se describe en Registro de controladores de extensión de shell. Se implementan como archivos DLL y deben exportar las siguientes funciones estándar:

  • DllMain. Punto de entrada estándar al archivo DLL.
  • DllGetClassObject. Expone el generador de clases del objeto.
  • DllCanUnloadNow. COM llama a esta función para determinar si el objeto está atendiendo a cualquier cliente. Si no es así, el sistema puede descargar el archivo DLL y liberar la memoria asociada.

Al igual que todos los objetos COM, los controladores de extensión de Shell deben implementar una interfaz IUnknown y un generador de clases. La mayoría de los controladores de extensión también deben implementar una interfaz IPersistFile o IShellExtInit en Windows XP o versiones anteriores. Estos se reemplazaron por IInitializeWithStream, IInitializeWithItem e IInitializeWithFile en Windows Vista. El Shell usa estas interfaces para inicializar el controlador.

La interfaz IPersistFile debe implementarse mediante lo siguiente:

  • Controladores de datos
  • Controladores de colocación

En el pasado, también se necesitaban controladores de iconos para implementar IPersistFile, pero esto ya no es cierto. En el caso de los controladores de iconos, IPersistFile ahora es opcional y se prefieren otras interfaces como IInitializeWithItem .

La interfaz IShellExtInit debe implementarse mediante lo siguiente:

  • Controladores de menú contextual
  • Controladores de arrastrar y colocar
  • Controladores de hoja de propiedades

Implementación de IPersistFile

La interfaz IPersistFile está pensada para permitir que un objeto se cargue o se guarde en un archivo de disco. Tiene seis métodos además de IUnknown, cinco propios, y el método GetClassID que hereda de IPersist. Con las extensiones de Shell, IPersist solo se usa para inicializar un objeto de controlador de extensión de Shell. Dado que normalmente no es necesario leer ni escribir en el disco, solo los métodos GetClassID y Load requieren una implementación que no sea de seguridad.

El shell llama primero a GetClassID y la función devuelve el identificador de clase (CLSID) del objeto de controlador de extensión. A continuación, shell llama a Load y pasa dos valores. El primero, pszFileName, es una cadena Unicode con el nombre del archivo o la carpeta en la que shell está a punto de funcionar. El segundo es dwMode, que indica el modo de acceso a archivos. Dado que normalmente no es necesario tener acceso a los archivos, dwMode suele ser cero. El método almacena estos valores según sea necesario para una referencia posterior.

En el fragmento de código siguiente se muestra cómo un controlador de extensión de Shell típico implementa los métodos GetClassID y Load . Está diseñado para controlar ANSI o Unicode. CLSID_SampleExtHandler es el GUID del objeto de controlador de extensión y CSampleExtHandler es el nombre de la clase utilizada para implementar la interfaz. Las variables m_szFileName y m_dwMode son variables privadas que se usan para almacenar el nombre y las marcas de acceso del archivo.

wchar_t m_szFileName[MAX_PATH];    // The file name
DWORD m_dwMode;                  // The file access mode

CSampleExtHandler::GetClassID(CLSID *pCLSID)
{
    *pCLSID = CLSID_SampleExtHandler;
}

CSampleExtHandler::Load(PCWSTR pszFile, DWORD dwMode)
{
    m_dwMode = dwMode;
    return StringCchCopy(_szFileName, ARRAYSIZE(m_szFileName), pszFile);
}

Implementación de IShellExtInit

La interfaz IShellExtInit solo tiene un método, IShellExtInit::Initialize, además de IUnknown. El método tiene tres parámetros que el Shell puede usar para pasar varios tipos de información. Los valores pasados dependen del tipo de controlador y algunos se pueden establecer en NULL.

  • pIDFolder contiene el puntero de una carpeta a una lista de identificadores de elemento (PIDL). Para las extensiones de hoja de propiedades, es NULL. Para las extensiones de menú contextual, es el PIDL de la carpeta que contiene el elemento cuyo menú contextual se muestra. En el caso de los controladores de arrastrar y colocar no predeterminados, es el PIDL de la carpeta de destino.
  • pDataObject contiene un puntero a la interfaz IDataObject de un objeto de datos. El objeto de datos contiene uno o varios nombres de archivo en formato CF_HDROP .
  • hRegKey contiene una clave del Registro para el tipo de carpeta o objeto de archivo.

El método IShellExtInit::Initialize almacena el nombre de archivo, el puntero IDataObject y la clave del Registro según sea necesario para su uso posterior. En el fragmento de código siguiente se muestra una implementación de IShellExtInit::Initialize. Por motivos de simplicidad, en este ejemplo se supone que el objeto de datos contiene solo un único archivo. En general, puede contener varios archivos que deban extraerse cada uno.

LPCITEMIDLIST  m_pIDFolder;           //The folder's PIDL
wchar_t        m_szFile[MAX_PATH];    //The file name
IDataObject   *m_pDataObj;            //The IDataObject pointer
HKEY           m_hRegKey;             //The file or folder's registry key

STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder, 
                                   IDataObject *pDataObj, 
                                   HKEY hRegKey) 
{ 
    // If Initialize has already been called, release the old PIDL
    ILFree(m_pIDFolder);
    m_pIDFolder = nullptr;

    // Store the new PIDL.
    if (pIDFolder)
    {
        m_pIDFolder = ILClone(pIDFolder);
    }
    
    // If Initialize has already been called, release the old
    // IDataObject pointer.
    if (m_pDataObj)
    { 
        m_pDataObj->Release(); 
    }
     
    // If a data object pointer was passed in, save it and
    // extract the file name. 
    if (pDataObj) 
    { 
        m_pDataObj = pDataObj; 
        pDataObj->AddRef(); 
      
        STGMEDIUM   medium;
        FORMATETC   fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
        UINT        uCount;

        if (SUCCEEDED(m_pDataObj->GetData(&fe, &medium)))
        {
            // Get the count of files dropped.
            uCount = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0);

            // Get the first file name from the CF_HDROP.
            if (uCount)
                DragQueryFile((HDROP)medium.hGlobal, 0, m_szFile, 
                              sizeof(m_szFile)/sizeof(TCHAR));

            ReleaseStgMedium(&medium);
        }
    }

    // Duplicate the registry handle. 
    if (hRegKey) 
        RegOpenKeyEx(hRegKey, nullptr, 0L, MAXIMUM_ALLOWED, &m_hRegKey); 
    return S_OK; 
}

CSampleExtHandler es el nombre de la clase utilizada para implementar la interfaz . Las variables m_pIDFolder, m_pDataObject, m_szFileName y m_hRegKey son variables privadas que se usan para almacenar la información que se pasa. Por motivos de simplicidad, en este ejemplo se supone que solo el objeto de datos conservará un nombre de archivo. Después de recuperar la estructura FORMATETC del objeto de datos, DragQueryFile se usa para extraer el nombre de archivo del miembro medium.hGlobal de la estructura FORMATETC. Si se pasa una clave del Registro, el método usa RegOpenKeyEx para abrir la clave y asigna el identificador a m_hRegKey.

Personalización de información sobre información

Hay dos maneras de personalizar la información sobre información:

  • Implemente un objeto que admita IQueryInfo y, a continuación, registre ese objeto en la subclave adecuada en el Registro (vea Registrar controladores de extensiones de shell a continuación).
  • Especifique una cadena fija o una lista de propiedades de archivo específicas que se mostrarán.

Para mostrar una cadena fija para una extensión de espacio de nombres, cree una entrada denominada InfoTip en la clave {CLSID} de la extensión de espacio de nombres. Establezca el valor de esa entrada para que sea la cadena literal que desea mostrar, como se muestra en este ejemplo, o una cadena indirecta que especifica un recurso e índice dentro de ese recurso (con fines de localización).

HKEY_CLASSES_ROOT
   CLSID
      {CLSID}
         InfoTip = InfoTip string for your namespace extension

Para mostrar una cadena fija para un tipo de archivo, cree una entrada denominada InfoTip en la clave ProgID de ese tipo de archivo. Establezca el valor de esa entrada para que sea la cadena literal que desea mostrar o una cadena indirecta que especifique un recurso y un índice dentro de ese recurso (con fines de localización), como se muestra en este ejemplo.

HKEY_CLASSES_ROOT
   ProgID
      InfoTip = Resource.dll, 3

Si desea que el Shell muestre propiedades de archivo específicas en la información sobre un tipo de archivo específico, cree una entrada denominada InfoTip en la clave ProgID para ese tipo de archivo. Establezca el valor de esa entrada para que sea una lista delimitadas por punto y coma de nombres de propiedad canónica, identificador de formato (FMTID)/pares de identificador de propiedad (PID) o ambos. Este valor debe comenzar por "prop:" para identificarlo como una cadena de lista de propiedades. Si omite "prop:", el valor se ve como una cadena literal y se muestra como tal.

En el ejemplo siguiente, propname es un nombre de propiedad canónico (como System.Date) y {fmtid},pid es un par FMTID/PID .

HKEY_CLASSES_ROOT
   ProgID
      InfoTip = prop:propname;propname;{fmtid},pid;{fmtid},pid

Se pueden usar los siguientes nombres de propiedad:

Nombre de propiedad Descripción Recuperado de
Autor Autor del documento PIDSI_AUTHOR
Título Título del documento PIDSI_TITLE
Asunto Resumen del asunto PIDSI_SUBJECT
Comentario Comentarios de documentos propiedades de PIDSI_COMMENT o carpeta o controlador
PageCount Número de páginas PIDSI_PAGECOUNT
Nombre Nombre descriptivo Vista de carpeta estándar
OriginalLocation Ubicación del archivo original Carpeta maletín y carpeta papelera de reciclaje
DateDeleted Se eliminó el archivo de fecha Carpeta papelera de reciclaje
Tipo Tipo de archivo Vista de detalles de carpeta estándar
Size Tamaño del archivo Vista de detalles de carpeta estándar
SyncCopyIn Igual que OriginalLocation Igual que OriginalLocation
Modificado Fecha de última modificación Vista de detalles de carpeta estándar
Creado Fecha de creación Vista de detalles de carpeta estándar
Acceso Fecha a la que se obtuvo acceso por última vez Vista de detalles de carpeta estándar
InFolder Directorio que contiene el archivo Resultados de la búsqueda de documentos
Rank Coincidencia de calidad de búsqueda Resultados de la búsqueda de documentos
FreeSpace Espacio de almacenamiento disponible Unidades de disco
NumberOfVisits Número de visitas carpeta Favoritos
Atributos Atributos de archivo Vista de detalles de carpeta estándar
Compañía Nombre de la compañía PIDDSI_COMPANY
Category Categoría de documento PIDDSI_CATEGORY
Copyright Derechos de autor de los medios PIDMSI_COPYRIGHT
HTMLInfoTipFile Archivo de información sobre HTML Desktop.ini archivo para la carpeta

 

Mejora de la búsqueda de Windows con controladores de extensión de Shell

Los controladores de extensión de Shell se pueden usar para mejorar la experiencia del usuario proporcionada por un controlador de protocolo de Windows Search. Para habilitar estas mejoras, el controlador de extensión de Shell auxiliar debe diseñarse para integrarse con el controlador de protocolo de búsqueda como origen de datos. Para obtener información sobre cómo mejorar un controlador de protocolo de Búsqueda de Windows a través de la integración con un controlador de extensión de Shell, vea Agregar iconos, vistas previas y menús contextuales. Para obtener más información sobre los controladores de protocolos de Búsqueda de Windows, vea Desarrollar controladores de protocolo.

Registro de controladores de extensiones de shell

Se debe registrar un objeto de controlador de extensión de Shell para poder usarlo. Esta sección es una explicación general de cómo registrar un controlador de extensión de Shell.

Cada vez que cree o cambie un controlador de extensión de Shell, es importante notificar al sistema que ha realizado un cambio con SHChangeNotify, especificando el evento SHCNE_ASSOCCHANGED . Si no llama a SHChangeNotify, es posible que el cambio no se reconozca hasta que se reinicie el sistema.

Al igual que con todos los objetos COM, debe crear un GUID para el controlador mediante una herramienta como UUIDGEN.exe. Cree una clave en HKEY_CLASSES_ROOT\CLSID cuyo nombre sea la forma de cadena del GUID. Dado que los controladores de extensión de Shell son servidores en proceso, debe crear una clave InProcServer32 en la clave GUID con el valor predeterminado establecido en la ruta de acceso del archivo DLL del controlador. Use el modelo de subprocesos de apartamento.

Cada vez que el Shell realiza una acción que puede implicar un controlador de extensión de Shell, comprueba la clave del Registro adecuada. La clave con la que se registra un controlador de extensión controla por lo tanto cuándo se llamará. Por ejemplo, es una práctica habitual tener un controlador de menú contextual al que se llama cuando shell muestra un menú contextual para un miembro de un tipo de archivo. En este caso, el controlador debe estar registrado en la clave ProgID del tipo de archivo.

Nombres de controlador

Para habilitar un controlador de extensión de Shell, cree una subclave con el nombre de subclave del controlador (vea a continuación) en la subclave ShellEx de ProgID (para tipos de archivo) o el nombre del tipo de objeto shell (para objetos shell predefinidos).

Por ejemplo, si desea registrar un controlador de extensión de menú contextual para MyProgram.1, empezaría creando la siguiente subclave:

HKEY_CLASSES_ROOT
   MyProgram.1
      ShellEx
         ContextMenuHandlers

Para los siguientes controladores, cree una subclave debajo de la clave "Nombre de subclave del controlador" cuyo nombre es la versión de cadena del CLSID de la extensión shell. Se pueden registrar varias extensiones en la clave de nombre de subclave del controlador mediante la creación de varias subclaves.

Controlador Interfaz Nombre de subclave del controlador
Controlador de menú contextual IContextMenu ContextMenuHandlers
Controlador de copyhook ICopyHook CopyHookHandlers
Controlador de arrastrar y colocar IContextMenu DragDropHandlers
Controlador de la hoja de propiedades IShellPropSheetExt PropertySheetHandlers
Controlador de proveedor de columnas (en desuso en Windows Vista) IColumnProvider ColumnHandlers

 

Para los siguientes controladores, el valor predeterminado de la clave "Nombre de subclave del controlador" es la versión de cadena del CLSID de la extensión shell. Solo se puede registrar una extensión para estos controladores.

Controlador Interfaz Nombre de subclave del controlador
Controlador de datos IDataObject Datahandler
Controlador de colocación IDropTarget DropHandler
Controlador de iconos IExtractIconA/W IconHandler
Controlador de imágenes IExtractImage {BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}
Controlador de imágenes en miniatura IThumbnailProvider {E357FCCD-A995-4576-B01F-234630154E96}
Controlador de recuadro informativo IQueryInfo {00021500-0000-0000-C000-000000000046}
Vínculo de Shell (ANSI) IShellLinkA {000214EE-0000-0000-C000-000000000046}
Vínculo de Shell (UNICODE) IShellLinkW {000214F9-0000-0000-C000-000000000046}
Almacenamiento estructurado IStorage {0000000B-0000-0000-C0000-00000000046}
Metadatos IPropertyStore PropertyHandler
Metadatos IPropertySetStorage (en desuso en Windows Vista) PropertyHandler
Anclar al menú Inicio IStartMenuPinnedList {a2a9545d-a0c2-42b4-9708-a0b2badd77c8}
Anclar a la barra de tareas {90AA3A4E-1CBA-4233-B8BB-535773D48449}

 

Las subclaves especificadas para agregar Anclar al menú Inicio y Anclar a la barra de tareas al menú contextual de un elemento solo son necesarias para los tipos de archivo que incluyen la entrada IsShortCut .

Se quitó la compatibilidad con los controladores de proveedor de columnas en Windows Vista. Además, a partir de Windows Vista, IPropertySetStorage ha quedado en desuso en favor de IPropertyStore.

Aunque IExtractImage sigue siendo compatible, se prefiere IThumbnailProvider para Windows Vista y versiones posteriores.

Objetos de Shell predefinidos

El Shell define objetos adicionales en HKEY_CLASSES_ROOT que se pueden extender de la misma manera que los tipos de archivo. Por ejemplo, para agregar un controlador de hoja de propiedades para todos los archivos, puede registrarse en la clave PropertySheetHandlers .

HKEY_CLASSES_ROOT
   *
      shellex
         PropertySheetHandlers

En la tabla siguiente se proporcionan las distintas subclaves de HKEY_CLASSES_ROOT en las que se pueden registrar controladores de extensión. Tenga en cuenta que muchos controladores de extensión no se pueden registrar en todas las subclaves enumeradas. Para obtener más información, consulte la documentación del controlador específico.

Subclave Descripción Posibles controladores Versión
* Todos los archivos Menú contextual, Hoja de propiedades, Verbos (ver a continuación) Todo
AllFileSystemObjects Todos los archivos y carpetas de archivos Menú contextual, Hoja de propiedades, Verbos 4.71
Carpeta Todas las carpetas Menú contextual, Hoja de propiedades, Verbos Todo
Directorio Carpetas de archivos Menú contextual, Hoja de propiedades, Verbos Todo
Directorio\Fondo Fondo de la carpeta de archivos Solo menú contextual 4.71
Conducir Todas las unidades de MyComputer, como "C:\" Menú contextual, Hoja de propiedades, Verbos Todo
Network Toda la red (en Mis sitios de red) Menú contextual, Hoja de propiedades, Verbos Todo
Network\Type\ # Todos los objetos de tipo # (consulte a continuación) Menú contextual, Hoja de propiedades, Verbos 4.71
NetShare Todos los recursos compartidos de red Menú contextual, Hoja de propiedades, Verbos 4.71
Netserver Todos los servidores de red Menú contextual, Hoja de propiedades, Verbos 4.71
network_provider_name Todos los objetos proporcionados por el proveedor de red "network_provider_name" Menú contextual, Hoja de propiedades, Verbos Todo
Impresoras Todas las impresoras Menú contextual, Hoja de propiedades Todo
AudioCD CD de audio en la unidad de CD Solo verbos Todo
DVD Unidad de DVD (Windows 2000) Menú contextual, Hoja de propiedades, Verbos 4.71

 

Notas:

  • Para acceder al menú contextual de fondo de la carpeta de archivos, haga clic con el botón derecho en una carpeta de archivos, pero no sobre ninguno de los contenidos de la carpeta.
  • "Verbos" son comandos especiales registrados en HKEY_CLASSES_ROOT\Subclave\Shell\Verb .
  • ParaTipo\#de red\ , "#" es un código de tipo de proveedor de red en decimal. El código de tipo de proveedor de red es la palabra alta de un tipo de red. La lista de tipos de red se da en el archivo de encabezado Winnetwk.h (valores WNNC_NET_*). Por ejemplo, WNNC_NET_SHIVA es 0x00330000, por lo que la clave de tipo correspondiente sería HKEY_CLASSES_ROOT\Tipo\ dered\51 .
  • "network_provider_name" es un nombre de proveedor de red especificado por WNetGetProviderName, con los espacios convertidos en caracteres de subrayado. Por ejemplo, si está instalado el proveedor de red de redes de Microsoft, su nombre de proveedor es "Microsoft Windows Network" y el network_provider_name correspondiente es Microsoft_Windows_Network.

Ejemplo de registro de controlador de extensión

Para habilitar un controlador determinado, cree una subclave en la clave de tipo de controlador de extensión con el nombre del controlador. El Shell no usa el nombre del controlador, pero debe ser diferente de todos los demás nombres de esa subclave de tipo. Establezca el valor predeterminado de la subclave name en el formato de cadena del GUID del controlador.

En el ejemplo siguiente se muestran las entradas del Registro que habilitan los controladores de extensión de hoja de propiedades y menú contextual, mediante un tipo de archivo .myp de ejemplo:

HKEY_CLASSES_ROOT
   .myp
      (Default) = MyProgram.1
   CLSID
      {00000000-1111-2222-3333-444444444444}
         InProcServer32
            (Default) = C:\MyDir\MyCommand.dll
            ThreadingModel = Apartment
      {11111111-2222-3333-4444-555555555555}
         InProcServer32
            (Default) = C:\MyDir\MyPropSheet.dll
            ThreadingModel = Apartment
   MyProgram.1
      (Default) = MyProgram Application
      Shellex
         ContextMenuHandler
            MyCommand
               (Default) = {00000000-1111-2222-3333-444444444444}
         PropertySheetHandlers
            MyPropSheet
               (Default) = {11111111-2222-3333-4444-555555555555}

El procedimiento de registro descrito en esta sección debe seguirse para todos los sistemas Windows.

Guía para implementar extensiones de In-Process