Os recursos do Shell podem ser estendidos com entradas do Registro e arquivos .ini. Embora essa abordagem para estender o Shell seja simples e adequada para muitas finalidades, ela é limitada. Por exemplo, se você usar o Registro para especificar um ícone personalizado para um tipo de arquivo, o mesmo ícone aparecerá para cada arquivo desse tipo. Estender o Shell com o registro não permite que você varie o ícone para arquivos diferentes do mesmo tipo. Outros aspectos do Shell, como a folha de propriedades Propriedades que pode ser exibida quando um arquivo é clicado com o botão direito do mouse, não podem ser modificados com o registro.
Uma abordagem mais poderosa e flexível para estender o Shell é implementar manipuladores de extensão de shell. Esses manipuladores podem ser implementados para uma variedade de ações que o Shell pode executar. Antes de executar a ação, o Shell consulta o manipulador de extensão, dando a ele a oportunidade de modificar a ação. Um exemplo comum é um manipulador de extensão de menu de atalho. Se um for implementado para um tipo de arquivo, ele será consultado sempre que um dos arquivos for clicado com o botão direito do mouse. Em seguida, o manipulador pode especificar itens de menu adicionais em uma base arquivo a arquivo, em vez de ter o mesmo conjunto para todo o tipo de arquivo.
Este documento discute como implementar os manipuladores de extensão que permitem modificar uma variedade de ações do Shell. Os manipuladores a seguir são associados a um tipo de arquivo específico e permitem que você especifique em uma base arquivo a arquivo:
Chamado quando uma operação de arrastar e soltar é executada em objetos dragShell. Ele permite que você forneça formatos de área de transferência adicionais para o destino de soltar.
Chamado antes que o ícone de um arquivo seja exibido. Ele permite que você substitua o ícone padrão do arquivo por um ícone personalizado em uma base arquivo a arquivo.
Fornece acesso de leitura e gravação a metadados (propriedades) armazenados em um arquivo. Isso pode ser usado para estender a exibição Detalhes, dicas de informações, a página de propriedades e os recursos de agrupamento.
Outros manipuladores não estão associados a um tipo de arquivo específico, mas são chamados antes de algumas operações do Shell:
Chamado pelo Windows Explorer antes de exibir a exibição Detalhes de uma pasta. Ele permite que você adicione colunas personalizadas à exibição Detalhes.
Chamado quando um objeto de pasta ou impressora está prestes a ser movido, copiado, excluído ou renomeado. Ele permite que você aprove ou vete a operação.
Chamado para iniciar um mecanismo de pesquisa. Ele permite implementar um mecanismo de pesquisa personalizado acessível no menu Iniciar ou no Windows Explorer.
Os detalhes de como implementar manipuladores de extensão específicos são abordados nas seções listadas acima. O restante deste documento aborda alguns problemas de implementação comuns a todos os manipuladores de extensão do Shell.
Grande parte da implementação de um objeto de manipulador de extensão shell depende de seu tipo. Há, no entanto, alguns elementos comuns. Esta seção discute os aspectos da implementação que são compartilhados por todos os manipuladores de extensão do Shell.
Muitos 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:
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.
A interface IPersistFile deve ser implementada pelo seguinte:
Manipuladores de dados
Remover manipuladores
No passado, manipuladores de ícone também eram necessários para implementar IPersistFile, mas isso não é mais verdade. Para manipuladores de ícones, IPersistFile agora é opcional e outras interfaces, como IInitializeWithItem , são preferenciais.
A interface IShellExtInit deve ser implementada pelo seguinte:
Manipuladores de menu de atalho
Manipuladores de arrastar e soltar
Manipuladores de folha de propriedades
Implementando IPersistFile
A interface IPersistFile destina-se a 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ãontoken.
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 Load e passa dois valores. O primeiro, pszFileName, é 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 geralmente é 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 shell típico 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 CSampleExtHandler é 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.
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.
pIDFolder contém o ponteiro de uma pasta para uma PIDL (lista de identificadores de item). Para extensões de folha de propriedades, é 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 manté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, ele pode conter vários arquivos que precisarão ser extraídos.
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 é o nome da classe usada para implementar a interface . As variáveis m_pIDFolder, m_pDataObject, m_szFileName e m_hRegKey são variáveis privadas usadas para armazenar as informações passadas. Para simplificar, este exemplo pressupõe que apenas um nome de arquivo será mantido pelo objeto de dados. Depois que a estrutura FORMATETC é recuperada do objeto de dados, DragQueryFile é usado para extrair o nome do arquivo do membro medium.hGlobal da estrutura FORMATETC. Se uma chave do Registro for passada, o método usará RegOpenKeyEx para abrir a chave e atribuirá o identificador a m_hRegKey.
Personalização da dica de informações
Há duas maneiras de personalizar dicas de informações:
Especifique uma cadeia de caracteres fixa ou uma lista de propriedades de arquivo específicas a serem exibidas.
Para exibir uma cadeia de caracteres fixa para uma extensão de namespace, crie uma entrada chamada InfoTip na chave {CLSID} da extensão de namespace. Defina o valor dessa entrada como a cadeia de caracteres literal que você deseja exibir, conforme mostrado neste exemplo, ou uma cadeia de caracteres indireta que especifica um recurso e um índice dentro desse recurso (para fins de localização).
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 entrada chamada InfoTip na chave ProgID desse tipo de arquivo. Defina o valor dessa entrada como a cadeia de caracteres literal que você deseja exibir ou uma cadeia de caracteres indireta que especifica um recurso e um índice dentro desse recurso (para fins de localização), conforme mostrado neste exemplo.
Se você quiser que o Shell exiba propriedades de arquivo específicas na dica de informações para um tipo de arquivo específico, crie uma entrada chamada InfoTip na chave ProgID para esse tipo de arquivo. Defina o valor dessa entrada como uma lista delineada por ponto-e-vírgula de nomes de propriedade canônica, pares de IDENTIFICADOR de formato (FMTID)/PID (identificador de propriedade) ou ambos. Esse valor deve começar com "prop:" para identificá-lo como uma cadeia de caracteres de lista de propriedades. Se você omitir "prop:", o valor será visto como uma cadeia de caracteres literal e exibido como tal.
No exemplo a seguir, propname é um nome de propriedade canônica (como System.Date) e {fmtid},pid é um par FMTID/PID .
Aprimorando a Pesquisa do Windows com manipuladores de extensão do Shell
Os manipuladores de extensão do Shell podem ser usados para aprimorar a experiência do usuário fornecida por um manipulador de protocolo do Windows Search. Para habilitar esses aprimoramentos, o manipulador de extensão shell de suporte deve ser projetado para integrar-se ao manipulador de protocolo de pesquisa como uma fonte de dados. Para obter informações sobre como aprimorar um manipulador de protocolo do Windows Search por meio da integração com um manipulador de extensão do Shell, consulte Adicionando ícones, visualizações e menus de atalho. Para obter mais informações sobre manipuladores de protocolo do Windows Search, consulte Desenvolvendo manipuladores de protocolo.
Registrando manipuladores de extensão de shell
Um objeto de manipulador de extensão shell deve ser registrado antes que o Shell possa usá-lo. Esta seção é uma discussão geral sobre como registrar um manipulador de extensão do Shell.
Sempre que você cria ou altera um manipulador de extensão do Shell, é importante notificar o sistema de que você fez uma alteração com SHChangeNotify, especificando o evento SHCNE_ASSOCCHANGED . Se você não chamar SHChangeNotify, a alteração poderá não ser reconhecida até que o sistema seja reinicializado.
Assim como acontece com todos os objetos COM, você deve criar um GUID para o manipulador usando uma ferramenta como UUIDGEN.exe. Crie uma chave em HKEY_CLASSES_ROOT\CLSID cujo nome é a forma de cadeia de caracteres do GUID. Como os manipuladores de extensão do Shell são servidores em processo, você deve criar uma chave InProcServer32 sob a chave GUID com o valor padrão definido como o caminho da DLL do manipulador. Use o modelo de threading Apartment.
Sempre que o Shell executa uma ação que pode envolver um manipulador de extensão do Shell, ele verifica a chave do Registro apropriada. A chave sob a qual um manipulador de extensão é registrado controla, portanto, quando ele será chamado. Por exemplo, é uma prática comum ter um manipulador de menu de atalho chamado quando o Shell exibe um menu de atalho para um membro de um tipo de arquivo. Nesse caso, o manipulador deve ser registrado sob a chave ProgID do tipo de arquivo.
Nomes de manipulador
Para habilitar um manipulador de extensão shell, crie uma subchave com o nome da subchave do manipulador (veja abaixo) na subchave ShellEx do ProgID (para tipos de arquivo) ou o nome do tipo de objeto Shell (para Objetos shell predefinidos).
Por exemplo, se você quisesse registrar um manipulador de extensão de menu de atalho para MyProgram.1, começaria criando a seguinte subchave:
Para os manipuladores a seguir, crie uma subchave abaixo da chave "Nome da subchave do manipulador" cujo nome é a versão de cadeia de caracteres do CLSID da extensão shell. Várias extensões podem ser registradas na chave de nome da subchave do manipulador criando várias subchaves.
Manipulador
Interface
Nome da subchave do manipulador
Manipulador de menu de atalho
Icontextmenu
ContextMenuHandlers
Manipulador de copyhook
ICopyHook
CopyHookHandlers
Manipulador do tipo "arrastar e soltar"
Icontextmenu
DragDropHandlers
Manipulador de folha de propriedades
IShellPropSheetExt
PropertySheetHandlers
Manipulador de provedor de colunas (preterido no Windows Vista)
IColumnProvider
ColumnHandlers
Para os manipuladores a seguir, o valor padrão da chave "Nome da Subchave do Manipulador" é a versão da cadeia de caracteres do CLSID da extensão shell. Somente uma extensão pode ser registrada para esses manipuladores.
Manipulador
Interface
Nome da subchave do manipulador
Manipulador de dados
Idataobject
Datahandler
Manipulador de remoção
Idroptarget
DropHandler
Manipulador de ícones
IExtractIconA/W
IconHandler
Manipulador de imagens
IExtractImage
{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}
Manipulador de imagens em miniatura
IThumbnailProvider
{E357FCCD-A995-4576-B01F-234630154E96}
Manipulador de infodicas
IQueryInfo
{00021500-0000-0000-C000-000000000046}
Link do Shell (ANSI )
IShellLinkA
{000214EE-0000-0000-C000-000000000046}
Link do Shell (UNICODE)
IShellLinkW
{000214F9-0000-0000-C000-000000000046}
Armazenamento estruturado
IStorage
{0000000B-0000-0000-C000-000000000046}
Metadados
Ipropertystore
PropertyHandler
Metadados
IPropertySetStorage (preterido no Windows Vista)
PropertyHandler
Fixar no Menu Iniciar
IStartMenuPinnedList
{a2a9545d-a0c2-42b4-9708-a0b2badd77c8}
Fixar à barra de tarefas
{90AA3A4E-1CBA-4233-B8BB-535773D48449}
As subchaves especificadas para adicionar Pin ao Menu Iniciar e Fixar na Barra de Tarefas ao menu de atalho de um item só são necessárias para tipos de arquivo que incluem a entrada IsShortCut .
O suporte para manipuladores de provedor de colunas foi removido no Windows Vista. Além disso, a partir do Windows Vista, IPropertySetStorage foi preterido em favor do IPropertyStore.
O Shell define objetos adicionais em HKEY_CLASSES_ROOT que podem ser estendidos da mesma forma que os tipos de arquivo. Por exemplo, para adicionar um manipulador de folha de propriedades para todos os arquivos, você pode se registrar na chave PropertySheetHandlers .
HKEY_CLASSES_ROOT
*
shellex
PropertySheetHandlers
A tabela a seguir fornece as várias subchaves de HKEY_CLASSES_ROOT sob as quais os manipuladores de extensão podem ser registrados. Observe que muitos manipuladores de extensão não podem ser registrados em todas as subchaves listadas. Para obter mais detalhes, consulte a documentação do manipulador específico.
Subchave
Descrição
Manipuladores possíveis
Versão
*
Todos os arquivos
Menu de Atalho, Folha de Propriedades, Verbos (veja abaixo)
Tudo
AllFileSystemObjects
Todos os arquivos e pastas de arquivo
Menu de atalho, folha de propriedades, verbos
4,71
Pasta
Todas as pastas
Menu de atalho, folha de propriedades, verbos
Tudo
Diretório
Pastas de arquivo
Menu de atalho, folha de propriedades, verbos
Tudo
Directory\Background
Plano de fundo da pasta de arquivo
Somente menu de atalho
4,71
Dirigir
Todas as unidades no MyComputer, como "C:\"
Menu de atalho, folha de propriedades, verbos
Tudo
Rede
Rede inteira (em Meus Locais de Rede)
Menu de atalho, folha de propriedades, verbos
Tudo
Network\Type\ #
Todos os objetos do tipo # (veja abaixo)
Menu de atalho, Folha de Propriedades, Verbos
4,71
Netshare
Todos os compartilhamentos de rede
Menu de atalho, Folha de Propriedades, Verbos
4,71
NetServer
Todos os servidores de rede
Menu de atalho, Folha de Propriedades, Verbos
4,71
network_provider_name
Todos os objetos fornecidos pelo provedor de rede "network_provider_name"
Menu de atalho, Folha de Propriedades, Verbos
Tudo
Impressoras
Todas as impressoras
Menu de atalho, folha de propriedades
Tudo
Audiocd
CD de áudio na unidade de CD
Somente verbos
Tudo
DVD
Unidade de DVD (Windows 2000)
Menu de atalho, folha de propriedades, verbos
4,71
Observações:
O menu de atalho em segundo plano da pasta de arquivos é acessado clicando com o botão direito do mouse em uma pasta de arquivo, mas não sobre qualquer conteúdo da pasta.
"Verbos" são comandos especiais registrados em HKEY_CLASSES_ROOT\Subkey\Shell\Verb .
ParaTipo\# de Rede\ , "#" é um código de tipo de provedor de rede em decimal. O código de tipo de provedor de rede é a palavra alta de um tipo de rede. A lista de tipos de rede é fornecida no arquivo de cabeçalho Winnetwk.h (valores WNNC_NET_*). Por exemplo, WNNC_NET_SHIVA é 0x00330000, portanto, a chave de tipo correspondente seria HKEY_CLASSES_ROOT\Tipo\ deRede\51 .
"network_provider_name" é um nome de provedor de rede, conforme especificado por WNetGetProviderName, com os espaços convertidos em sublinhados. Por exemplo, se o provedor de rede da Microsoft Networking estiver instalado, seu nome de provedor será "Microsoft Windows Network" e o network_provider_name correspondente será Microsoft_Windows_Network.
Exemplo de um registro de manipulador de extensão
Para habilitar um manipulador específico, crie uma subchave na chave de tipo do manipulador de extensão com o nome do manipulador. O Shell não usa o nome do manipulador, mas deve ser diferente de todos os outros nomes sob essa subchave de tipo. Defina o valor padrão da subchave de nome para a forma de cadeia de caracteres do GUID do manipulador.
O exemplo a seguir ilustra as entradas do Registro que habilitam manipuladores de extensão de folha de propriedades e menu de atalho, usando um exemplo de tipo de arquivo .myp:
Os aplicativos de finanças e operações são personalizados por meio de extensões, o que permite adicionar funcionalidade aos elementos de modelo e ao código-fonte na AOT (árvore de objetos de aplicativo) usando o Visual Studio.