Obtendo informações sobre o conteúdo de uma pasta
A seção Obtendo a ID de uma pasta discutiu duas abordagens para obter o ponteiro de um objeto de namespace para uma lista de identificadores de item (PIDL). Uma pergunta óbvia é: uma vez que você tem um PIDL, o que você pode fazer com ele? Uma pergunta relacionada é: é se nenhuma abordagem funcionar ou for adequada para sua aplicação? A resposta para ambas as perguntas requer uma análise mais detalhada de como o namespace é implementado. A chave é a interface IShellFolder.
- Usando a interface IShellFolder
- Enumerando o conteúdo de uma pasta
- Determinando nomes de exibição e outras propriedades
- Obtendo um ponteiro para a interface IShellFolder de uma subpasta
- Determinando a pasta pai de um objeto
Anteriormente nesta documentação, as pastas de namespace eram chamadas de objetos. Embora, naquele ponto, o termo fosse usado em um sentido livre, na verdade é verdade em um sentido estrito também. Cada pasta de namespace é representada por um objeto COM (Component Object Model). Cada objeto de pasta expõe uma série de interfaces que podem ser usadas para uma ampla variedade de tarefas. Algumas interfaces que são opcionais podem não ser expostas por todas as pastas. No entanto, todas as pastas devem expor a interface fundamental, IShellFolder.
A primeira etapa no uso de um objeto de pasta é recuperar um ponteiro para sua interface IShellFolder. Além de fornecer acesso às outras interfaces do objeto, IShellFolder expõe um grupo de métodos que lidam com várias tarefas comuns, várias das quais são discutidas nesta seção.
Para recuperar um ponteiro para a interface IShellFolder de um objeto de namespace, você deve primeiro chamar SHGetDesktopFolder. Essa função retorna um ponteiro para a interface IShellFolder da raiz do namespace, a área de trabalho. Depois de ter a interface IShellFolder da área de trabalho, há uma variedade de maneiras de proceder.
Se você já tiver o PIDL da pasta na qual está interessado, por exemplo, chamando SHGetFolderLocation — poderá recuperar sua interface IShellFolder chamando o método IShellFolder::BindToObject da área de trabalho. Se você tiver o caminho de um objeto do sistema de arquivos, primeiro deverá obter seu PIDL chamando o método IShellFolder::ParseDisplayName da área de trabalho e, em seguida, chamar IShellFolder::BindToObject. Se nenhuma dessas abordagens for aplicável, você poderá usar outros métodos IShellFolder para navegar pelo namespace. Para obter mais informações, consulte Navegando no namespace.
A primeira coisa que você geralmente quer fazer com uma pasta é descobrir o que ela contém. Você deve primeiro chamar o método IShellFolder::EnumObjects da pasta. A pasta criará um objeto de enumeração OLE padrão e retornará sua interface IEnumIDList. Essa interface expõe quatro métodos padrão — Clone, Next, Reset e Skip— que podem ser usados para enumerar o conteúdo da pasta.
O procedimento básico para enumerar o conteúdo de uma pasta é:
- Chamar as pastas IShellFolder::EnumObjects método para recuperar um ponteiro para a interface IEnumIDList de um objeto de enumeração.
- Passar um PIDL não alocado para IEnumIDList::Next. Em seguida cuidar da alocação do PIDL, mas o aplicativo deve desalocá-lo quando ele não for mais necessário. Quando Next retornar, o PIDL conterá apenas a ID do item do objeto e os caracteres NULL de encerramento. Em outras palavras, é um PIDL de nível único, relativo à pasta, não um PIDL totalmente qualificado.
- Repita a etapa 2 até que Next retorne S_FALSE para indicar que todos os itens foram enumerados.
- Chame IEnumIDList::Release para liberar o objeto de enumeração.
Observação
É importante acompanhar se você está trabalhando com um PIDL completo ou relativo. Algumas funções e métodos aceitarão qualquer um, mas outros aceitarão apenas um ou outro.
Os três métodos restantes IEnumIDList (Reset, Skip e Clone) são úteis se você precisar fazer enumerações repetidas da pasta. Eles permitem que você redefina a enumeração, ignore um ou mais objetos e faça uma cópia do objeto de enumeração para preservar seu estado.
Depois de enumerar todos os PIDLs contidos em uma pasta, você pode descobrir que tipo de objetos eles representam. A interface IShellFolder fornece uma série de métodos úteis, dois dos quais são discutidos aqui. Outros métodos IShellFolder e outras interfaces de pasta do Shell são discutidos posteriormente.
Uma das propriedades mais úteis é o nome de exibição do objeto. Para recuperar o nome de exibição de um objeto, passe seu PIDL para IShellFolder::GetDisplayNameOf. Embora o objeto possa estar localizado em qualquer lugar abaixo da pasta pai no namespace, seu PIDL deve ser relativo à pasta.
IShellFolder::GetDisplayNameOf retorna o nome para exibição como parte de uma estrutura STRRET. Como extrair o nome de exibição de uma estrutura STRRET pode ser um pouco complicado, o Shell fornece duas funções que fazem o trabalho para você, StrRetToStr e StrRetToBuf. Ambas funções usam uma estrutura STRRET e retornam o nome de exibição como uma cadeia de caracteres normal. Eles diferem apenas em como a cadeia de caracteres é alocada.
Além de seu nome de exibição, um objeto pode ter vários atributos, como se é uma pasta ou se pode ser movido. Você pode recuperar os atributos de um objeto passando seu PIDL para IShellFolder::GetAttributesOf. A lista completa de atributos é bastante grande, então você deve ver a referência para obter detalhes. Observe que o PIDL que você passa para GetAttributesOf deve ser de nível único. Em particular, IShellFolder::GetAttributesOf aceitará as PIDLs retornadas por IEnumIDList::Next. Você pode passar uma matriz de PIDLs e GetAttributesOf retornará os atributos que todos os objetos na matriz têm em comum.
Se você tiver um caminho totalmente qualificado ou PIDL, SHGetFileInfo fornece uma maneira simples de recuperar informações sobre um objeto que é suficiente para muitas finalidades. SHGetFileInfo usa um caminho totalmente qualificado ou PIDL e retorna uma variedade de informações sobre o objeto, incluindo:
- O nome de exibição do objeto
- Os atributos do objeto
- Manipulação dos ícones do objeto
- Um identificador para a lista de imagens do sistema
- O caminho do arquivo que contém o ícone do objeto
Você pode determinar se sua pasta contém subpastas chamando IShellFolder::GetAttributesOf e verificando se o sinalizador SFGAO_FOLDER está definido. Se um objeto for uma pasta, você poderá vinculá-lo, o que fornecerá um ponteiro para sua interface IShellFolder.
Para vincular a uma subpasta, chame o método IShellFolder::BindToObject da pasta pai. Esse método usa o PIDL da subpasta e retorna um ponteiro para sua interface IShellFolder. Depois de ter esse ponteiro, você pode usar os métodos IShellFolder para enumerar o conteúdo das subpastas, determinar suas propriedades e assim por diante.
Se você tiver o PIDL de um objeto, talvez seja necessário um identificador para uma das interfaces expostas por sua pasta pai. Por exemplo, se você deseja determinar o nome de exibição associado a um PIDL usando IShellFolder::GetDisplayNameOf, você deve primeiro recuperar a interface IShellFolder do pai do objeto. É possível fazer isso com as técnicas discutidas nas seções anteriores. No entanto, uma abordagem muito mais simples é usar a função Shell, SHBindToParent. Essa função pega o PIDL totalmente qualificado de um objeto e retorna um ponteiro de interface especificado na pasta pai. Opcionalmente, ele também retorna o PIDL de nível único do item para uso em métodos como IShellFolder::GetAttributesOf.
O aplicativo de console de exemplo a seguir recupera o PIDL da pasta especial do sistema e retorna seu nome de exibição.
#include <shlobj.h>
#include <shlwapi.h>
#include <iostream.h>
#include <objbase.h>
int main()
{
IShellFolder *psfParent = NULL;
LPITEMIDLIST pidlSystem = NULL;
LPCITEMIDLIST pidlRelative = NULL;
STRRET strDispName;
TCHAR szDisplayName[MAX_PATH];
HRESULT hr;
hr = SHGetFolderLocation(NULL, CSIDL_SYSTEM, NULL, NULL, &pidlSystem);
hr = SHBindToParent(pidlSystem, IID_IShellFolder, (void **) &psfParent, &pidlRelative);
if(SUCCEEDED(hr))
{
hr = psfParent->GetDisplayNameOf(pidlRelative, SHGDN_NORMAL, &strDispName);
hr = StrRetToBuf(&strDispName, pidlSystem, szDisplayName, sizeof(szDisplayName));
cout << "SHGDN_NORMAL - " <<szDisplayName << '\n';
}
psfParent->Release();
CoTaskMemFree(pidlSystem);
return 0;
}
O aplicativo primeiro usa SHGetFolderLocation para recuperar o PIDL da pasta System. Em seguida, ele chama SHBindToParent, que retorna um ponteiro para a interface IShellFolder da pasta pai e o PIDL da pasta System em relação ao seu pai. Em seguida, ele usa o método IShellFolder::GetDisplayNameOf da pasta pai para recuperar o nome de exibição da pasta System. Como GetDisplayNameOf retorna uma estrutura STRRET, StrRetToBuf é usado para converter o nome de exibição em uma cadeia de caracteres normal. Depois de exibir o nome de exibição, os ponteiros de interface são liberados e o PIDL do sistema liberado. Observe que você não deve liberar o PIDL relativo retornado por SHBindToParent.