Inicializando manipuladores de extensão do Shell

Grande parte da implementação de um objeto de manipulador de extensão shell é determinada por seu tipo. Há, no entanto, alguns elementos comuns. Este tópico discute os aspectos da implementação que são compartilhados por todos os manipuladores de extensão do Shell.

Todos os manipuladores de extensão shell são objetos COM (Component Object Model) em processo. Eles devem ser atribuídos a um GUID e registrados conforme descrito em Registrando manipuladores de extensão do shell. Elas são implementadas como DLLs e devem exportar as seguintes funções padrão:

  • DllMain. O ponto de entrada padrão para a DLL.
  • DllGetClassObject. Expõe a fábrica de classes do objeto.
  • DllCanUnloadNow. O COM chama essa função para determinar se o objeto está atendendo clientes. Caso contrário, o sistema pode descarregar a DLL e liberar a memória associada.

Como todos os objetos COM, os manipuladores de extensão do Shell devem implementar uma interface IUnknown e uma fábrica de classes. A maioria também deve implementar uma interface IPersistFile ou IShellExtInit no Windows XP ou anterior. Eles foram substituídos por IInitializeWithStream, IInitializeWithItem e IInitializeWithFile no Windows Vista. O Shell usa essas interfaces para inicializar o manipulador.

A interface IPersistFile deve ser implementada pelo seguinte:

  • Manipuladores de ícones
  • Manipuladores de dados
  • Remover manipuladores

A interface IShellExtInit deve ser implementada pelo seguinte:

  • Manipuladores de menu de atalho
  • Manipuladores de arrastar e soltar
  • Manipuladores de folha de propriedades

Os seguintes assuntos são discutidos no restante deste tópico:

Implementando IPersistFile

A interface IPersistFile foi projetada para permitir que um objeto seja carregado ou salvo em um arquivo de disco. Ele tem seis métodos além de IUnknown, cinco deles próprios e o método GetClassID que herda do IPersist. Com as extensões do Shell, o IPersist é usado apenas para inicializar um objeto de manipulador de extensão shell. Como normalmente não há necessidade de ler ou gravar no disco, somente os métodos GetClassID e Load exigem uma implementação não ininterrupta.

O Shell chama GetClassID primeiro e a função retorna o CLSID (identificador de classe) do objeto do manipulador de extensão. Em seguida, o Shell chama Carregar e passa dois valores. O primeiro, pszFile, é uma cadeia de caracteres Unicode com o nome do arquivo ou pasta em que o Shell está prestes a operar. O segundo é dwMode, que indica o modo de acesso ao arquivo. Como normalmente não há necessidade de acessar arquivos, dwMode normalmente é zero. O método armazena esses valores conforme necessário para referência posterior.

O fragmento de código a seguir ilustra como um manipulador de extensão típico do Shell implementa os métodos GetClassID e Load . Ele foi projetado para lidar com ANSI ou Unicode. CLSID_SampleExtHandler é o GUID do objeto do manipulador de extensão e CSampleShellExtension é o nome da classe usada para implementar a interface. As variáveis m_szFileName e m_dwMode são variáveis privadas usadas para armazenar o nome do arquivo e os sinalizadores de acesso.

class CSampleShellExtension : public IPersistFile
{
    // Method declarations not included

    private:
    WCHAR m_szFileName[MAX_PATH];    // The file name
    DWORD m_dwMode;                  // The file access mode
}

IFACEMETHODIMP CSampleShellExtension::GetClassID(__out CLSID *pCLSID)
{
    *pCLSID = CLSID_SampleExtHandler;
}

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

// The implementation sample is continued in the next section.

Implementando IShellExtInit

A interface IShellExtInit tem apenas um método, IShellExtInit::Initialize, além de IUnknown. O método tem três parâmetros que o Shell pode usar para passar vários tipos de informações. Os valores passados dependem do tipo de manipulador e alguns podem ser definidos como NULL.

  • pidlFolder contém o ponteiro de uma pasta para uma lista de identificadores de item (PIDL). Este é um PIDL absoluto. Para extensões de folha de propriedades, esse valor é NULL. Para extensões de menu de atalho, é o PIDL da pasta que contém o item cujo menu de atalho está sendo exibido. Para manipuladores não padrão de arrastar e soltar, é o PIDL da pasta de destino.
  • pDataObject contém um ponteiro para a interface IDataObject de um objeto de dados. O objeto de dados contém um ou mais nomes de arquivo no formato CF_HDROP .
  • hRegKey contém uma chave do Registro para o objeto de arquivo ou o tipo de pasta.

O método IShellExtInit::Initialize armazena o nome do arquivo, o ponteiro IDataObject e a chave do Registro, conforme necessário para uso posterior. O fragmento de código a seguir ilustra uma implementação de IShellExtInit::Initialize. Para simplificar, este exemplo pressupõe que o objeto de dados contenha apenas um único arquivo. Em geral, o objeto de dados pode conter vários arquivos, cada um dos quais precisará ser extraído.

// This code continues the CSampleShellExtension sample shown in the
// "Implementing IPersistFile" section above.

class CSampleShellExtension : public IShellExtInit
{
    // Method declarations not included
    
    private:
    // IDList of the folder for extensions invoked on the folder, such as 
    // background context menu handlers or nondefault drag-and-drop handlers. 
    PIDLIST_ABSOLUTE m_pidlFolder;
    
    // The data object contains an expression of the items that the handler is 
    // being initialized for. Use SHCreateShellItemArrayFromDataObject to 
    // convert this object to an array of items. Use SHGetItemFromObject if you
    // are only interested in a single Shell item. If you need a file system
    // path, use IShellItem::GetDisplayName(SIGDN_FILESYSPATH, ...).
    IDataObject *m_pdtobj;
    
    // For context menu handlers, the registry key provides access to verb 
    // instance data that might be stored there. This is a rare feature to use 
    // so most extensions do not need this variable.
    HKEY m_hRegKey;             
}
    
// This method must be very efficient. Do not do any unnecessary work here.
// Use Initialize to acquire resources that will be used later.

IFACEMETHODIMP CSampleShellExtension::Initialize(__in_opt PCIDLIST_ABSOLUTE pidlFolder,
                                                 __in_opt IDataObject *pDataObject, 
                                                 __in_opt HKEY hRegKey) 
{ 
    // In some cases, handlers are initialized multiple times. Therefore, 
    // clear any previous state here.
    CoTaskMemFree(m_pidlFolder);
    m_pidlFolder = NULL;
    
    if (m_pdtobj)
    { 
        m_pdtobj->Release(); 
    }
    
    if (m_hRegKey)
    {
        RegCloseKey(m_hRegKey);
        m_hRegKey = NULL;
    }
    
    // Capture the inputs for use later.
    HRESULT hr = S_OK;
    
    if (pidlFolder)
    {
        m_pidlFolder = ILClone(pidlFolder);   // Make a copy to use later.
        hr = m_pidlFolder ? S_OK : E_OUTOFMEMORY;
    }
    
    if (SUCCEEDED(hr))
    {
        // If a data object pointer was passed into the method, save it and
        // extract the file name. 
        if (pDataObject) 
        { 
            m_pdtobj = pDataObject; 
            m_pdtobj->AddRef(); 
        }
    
        // It is uncommon to use the registry handle, but if you need it,
        // duplicate it now.
        if (hRegKey)
        {
            LSTATUS const result = RegOpenKeyEx(hRegKey, NULL, 0, KEY_READ, &m_hRegKey); 
            hr = HRESULT_FROM_WIN32(result);
        }
    }
    
    return hr;
}

Personalização do Infotip

Há duas maneiras de personalizar dicas de informações. Uma maneira é implementar um objeto que dá suporte a IQueryInfo e, em seguida, registrar o objeto sob a subchave apropriada no Registro (veja abaixo). Como alternativa, você pode especificar uma cadeia de caracteres fixa ou uma lista de determinadas propriedades de arquivo a serem exibidas.

Para exibir uma cadeia de caracteres fixa para uma extensão de namespace, crie uma subchave chamada InfoTip abaixo da chave CLSID da extensão de namespace. Defina os dados dessa subchave como a cadeia de caracteres que você deseja exibir.

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

Para exibir uma cadeia de caracteres fixa para um tipo de arquivo, crie uma subchave chamada InfoTip abaixo da chave ProgID do tipo de arquivo para o qual você deseja fornecer dicas de informações. Defina os dados dessa subchave como a cadeia de caracteres que você deseja exibir.

HKEY_CLASSES_ROOT
   ProgID
      InfoTip = InfoTip string for all files of this type

Se você quiser que o Shell mostre determinadas propriedades de arquivo na dica de informações para um tipo de arquivo específico, crie uma subchave chamada InfoTip abaixo da chave ProgID desse tipo de arquivo. Defina os dados dessa subchave como uma lista delineada por ponto e vírgula de nomes de propriedade canônica ou {fmtid}, pares pid em que propname é um nome de propriedade canônica e {fmtid},pid é um par FMTID/PID.

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

Os nomes de propriedade a seguir podem ser usados.

Nome da propriedade Descrição Recuperado de
Autor Autor do documento PIDSI_AUTHOR
Título Título do documento PIDSI_TITLE
Assunto Resumo do assunto PIDSI_SUBJECT
Comentário Comentários do documento PIDSI_COMMENT ou propriedades de pasta/unidade
PageCount Número de páginas PIDSI_PAGECOUNT
Nome Nome amigável Exibição de pasta padrão
OriginalLocation Local do arquivo original Pasta de pasta e pasta Lixeira
DateDeleted O arquivo de data foi excluído Pasta Lixeira
Type Tipo de arquivo Exibição de detalhes da pasta padrão
Tamanho Tamanho do arquivo Exibição de detalhes da pasta padrão
SyncCopyIn O mesmo que OriginalLocation O mesmo que OriginalLocation
Modificado Data da última modificação Exibição de detalhes da pasta padrão
Criado Data de criação Exibição de detalhes da pasta padrão
Acessado Data de acesso pela última vez Exibição de detalhes da pasta padrão
InFolder Diretório que contém o arquivo Resultados da pesquisa de documentos
Rank Qualidade da correspondência de pesquisa Resultados da pesquisa de documentos
FreeSpace Espaço de armazenamento disponível Unidades de disco
NumberOfVisits Número de visitas Pasta Favoritos
Atributos Atributos do arquivo Exibição de detalhes da pasta padrão
Empresa Nome da empresa PIDDSI_COMPANY
Categoria Categoria do documento PIDDSI_CATEGORY
Direitos autorais Direitos autorais de mídia PIDMSI_COPYRIGHT
HTMLInfoTipFile Arquivo HTML InfoTip Desktop.ini arquivo para pasta

 

Registrando manipuladores de extensão de shell