Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O objeto de dados é central para todas as transferências de dados do Shell. É principalmente um contêiner para armazenar os dados transferidos. No entanto, o destino também pode se comunicar com o objeto de dados para facilitar alguns tipos especializados de transferência de dados do Shell, como movimentos otimizados. Este tópico fornece uma discussão geral sobre como os objetos de dados do Shell funcionam, como eles são construídos por uma fonte e como são manipulados por um destino. Para obter uma discussão detalhada sobre como usar objetos de dados para transferir diferentes tipos de dados do Shell, consulte Manipulando cenários de transferência de dados do Shell.
- Como os objetos de dados funcionam
- Como uma fonte cria um objeto de dados
- Como um destino lida com um objeto de dados
- Usando o objeto auxiliar de arrastar e soltar
Como funcionam os objetos de dados
Os objetos de dados são objetos COM (Component Object Model), criados pela fonte de dados para transferir dados para um destino. Eles normalmente carregam mais de um item de dados. Existem duas razões para esta prática:
- Embora quase qualquer tipo de dados possa ser transferido com um objeto de dados, a fonte normalmente não sabe que tipo de dados o destino pode aceitar. Por exemplo, os dados podem ser uma parte de um documento de texto formatado. Embora o destino possa ser capaz de lidar com informações de formatação complexas, ele também pode ser capaz de aceitar apenas texto ANSI. Por esse motivo, os objetos de dados geralmente incluem os mesmos dados em vários formatos diferentes. O destino pode então extrair os dados em um formato que ele pode manipular.
- Os objetos de dados também podem conter itens de dados auxiliares que não são versões de dados de origem. Esse tipo de item de dados normalmente fornece informações adicionais sobre a operação de transferência de dados. Por exemplo, o Shell usa itens de dados auxiliares para indicar se um arquivo deve ser copiado ou movido.
Formatos da área de transferência
Cada item de dados em um objeto de dados tem um formato associado, geralmente chamado de formato de área de transferência . Há uma série de formatos de área de transferência padrão, declarados em Winuser.h, que correspondem aos tipos de dados comumente usados. Os formatos da área de transferência são inteiros, mas normalmente são referidos pelo seu nome equivalente, que tem a forma CF_XXX. Por exemplo, o formato da área de transferência para texto ANSI é CF_TEXT.
Os aplicativos podem ampliar a gama de formatos de área de transferência disponíveis definindo formatos privados. Para definir um formato privado, um aplicativo chama RegisterClipboardFormat com uma cadeia de caracteres que identifica o formato. O inteiro não assinado que a função retorna é um valor de formato válido que pode ser usado como um formato de área de transferência padrão. No entanto, tanto a origem quanto o destino devem registrar o formato para usá-lo. Com uma exceção —CF_HDROP—, os formatos da área de transferência usados para transferir dados do Shell são definidos como formatos privados. Eles devem ser registrados pela fonte e pelo destino antes de poderem ser usados. Para obter uma descrição dos formatos de área de transferência do Shell disponíveis, consulte Formatos da área de transferência do Shell.
Embora existam algumas exceções, os objetos de dados normalmente contêm apenas um item de dados para cada formato de área de transferência suportado. Essa correlação um-para-um entre o formato e os dados permite que o valor do formato seja usado como um identificador para o item de dados associado. Na verdade, ao discutir o conteúdo de um objeto de dados, um determinado item de dados é normalmente chamado de "formato" e é referido pelo seu nome de formato. Por exemplo, frases como "Extrair o formato CF_TEXT..." são normalmente usados ao discutir o item de dados de texto ANSI de um objeto de dados.
Quando o destino de descarte recebe o ponteiro para o objeto de dados, o destino de soltar enumera os formatos disponíveis para determinar quais tipos de dados estão disponíveis. Em seguida, solicita um ou mais dos formatos disponíveis e extrai os dados. A maneira específica como o destino extrai dados do Shell de um objeto de dados varia com o formato; isso é discutido em detalhes em Como um destino manipula um objeto de dados.
Com transferências de dados simples da área de transferência, os dados são colocados em um objeto de memória global. O endereço desse objeto é colocado na área de transferência, juntamente com seu formato. O formato da área de transferência informa ao alvo que tipo de dados ele encontrará no endereço associado. Embora as transferências simples da área de transferência sejam fáceis de implementar:
- Os objetos de dados fornecem uma maneira muito mais flexível de transferir dados.
- Os objetos de dados são mais adequados para transferir grandes quantidades de dados.
- Os objetos de dados devem ser usados para transferir dados com uma operação de arrastar e soltar.
Por esses motivos, todas as transferências de dados do Shell usam objetos de dados. Com objetos de dados, os formatos da área de transferência não são usados diretamente. Em vez disso, os itens de dados são identificados com uma generalização do formato da área de transferência, uma FORMATETC estrutura.
Estrutura FORMATETC
A estrutura FORMATETC é uma versão estendida de um formato de área de transferência. Como usado para transferências de dados do Shell, a estrutura FORMATETC tem as seguintes características:
Um item de dados ainda é identificado por seu formato de área de transferência, no cfFormat membro.
A transferência de dados não está limitada a objetos de memória global. O membro vinculado é usado para indicar o mecanismo de transferência de dados contido na estrutura deSTGMEDIUMassociada. É definido como um dos valores TYMED_XXX.
O Shell usa o membro lIndex com seu formato CFSTR_FILECONTENTS para permitir que um objeto de dados contenha mais de um item de dados por formato. Para obter uma discussão sobre como usar esse formato, consulte a seção Usando o formato CFSTR_FILECONTENTS para extrair dados de um arquivo de Manipulando cenários de transferência de dados do Shell.
O membro dwAspect normalmente é definido como DVASPECT_CONTENT. No entanto, há três valores definidos em Shlobj.h que podem ser usados para transferência de dados do Shell.
Valor Descrição DVASPECT_COPY Usado para indicar que o formato representa uma cópia dos dados. DVASPECT_LINK Usado para indicar que o formato representa um atalho para os dados. DVASPECT_SHORTNAME Usado com o formato CF_HDROP para solicitar um caminho de arquivo com os nomes encurtados para o formato 8.3. O membro ptd não é usado para transferências de dados do Shell e normalmente é definido como NULL.
Estrutura STGMEDIUM
A estrutura STGMEDIUM fornece acesso aos dados que estão sendo transferidos. Três mecanismos de transferência de dados são suportados para dados do Shell:
O vinculado membro da estruturaSTGMEDIUMé um valor TYMED_XXX que identifica o mecanismo de transferência de dados. O segundo membro é um ponteiro que é usado pelo destino para extrair os dados. O ponteiro pode ser de vários tipos, dependendo do valor vinculado. Os três valores de vinculados usados para transferências de dados do Shell são resumidos na tabela a seguir, juntamente com seus correspondentes STGMEDIUM nome do membro.
| Valor atrelado | Nome do membro | Descrição |
|---|---|---|
| TYMED_HGLOBAL | hGlobal | Um ponteiro para um objeto de memória global. Esse tipo de ponteiro é normalmente usado para transferir pequenas quantidades de dados. Por exemplo, o Shell usa objetos de memória global para transferir cadeias de texto curtas, como nomes de arquivos ou URLs. |
| TYMED_ISTREAM | pstm | Um ponteiro para um IStream interface. Esse tipo de ponteiro é preferido para a maioria das transferências de dados do Shell porque requer relativamente pouca memória em comparação com o TYMED_HGLOBAL. Além disso, o mecanismo de transferência de dados TYMED_ISTREAM não exige que a fonte armazene seus dados de nenhuma maneira específica. |
| TYMED_ISTORAGE | pstg | Um ponteiro para um IStorage interface. O destino chama os métodos de interface para extrair os dados. Como TYMED_ISTREAM, esse tipo de ponteiro requer relativamente pouca memória. No entanto, como TYMED_ISTORAGE é menos flexível do que TYMED_ISTREAM, não é tão comumente usado. |
Como uma fonte cria um objeto de dados
Quando um usuário inicia uma transferência de dados do Shell, a fonte é responsável por criar um objeto de dados e carregá-lo com dados. O procedimento a seguir resume o processo:
- Chame RegisterClipboardFormat para obter um valor de formato de área de transferência válido para cada formato de Shell que será incluído no objeto de dados. Lembre-se que CF_HDROP já é um formato de área de transferência válido e não precisa ser registrado.
- Para cada formato a ser transferido, coloque os dados associados em um objeto de memória global ou crie um objeto que forneça acesso a esses dados por meio de umIStreamou interface IStorage. As interfaces IStream e IStorage são criadas usando técnicas COM padrão. Para obter uma discussão sobre como manipular objetos de memória global, consulte Como adicionar um objeto de memória global a um objeto de dados.
- Crie FORMATETC e estruturas de STGMEDIUM para cada formato.
- Instanciar um objeto de dados.
- Carregue os dados no objeto de dados chamando o método IDataObject::SetData para cada formato suportado e passando asFORMATETC do formato e estruturas de STGMEDIUM.
- Com transferências de dados da área de transferência, chame OleSetClipboard para colocar um ponteiro para a interface IDataObject do objeto de dados na área de transferência. Para transferências de arrastar e soltar, inicie um de loop de arrastar chamando DoDragDrop. O ponteiro IDataObject será passado para o destino de soltar quando os dados forem soltos, encerrando o loop de arrasto.
O objeto de dados agora está pronto para ser transferido para o destino. Para transferências de dados da área de transferência, o objeto é simplesmente mantido até que o destino o solicite chamando OleGetClipboard. Para transferências de dados de arrastar e soltar, o objeto de dados é responsável por criar um ícone para representar os dados e movê-los à medida que o usuário move o cursor. Enquanto o objeto está no loop de arrasto, a fonte recebe informações de status por meio de sua interfaceIDropSource. Para mais discussões, consulte Implementing IDropSource.
A origem não receberá nenhuma notificação se o objeto de dados for recuperado da Área de Transferência por um destino. Quando um objeto é solto em um destino por uma operação de arrastar e soltar, a funçãoDoDragDropque foi chamada para iniciar o loop de arrastar retornará.
Como adicionar um objeto de memória global a um objeto de dados
Muitos dos formatos de dados do Shell estão na forma de um objeto de memória global. Use o procedimento a seguir para criar um formato contendo um objeto de memória global e carregá-lo no objeto de dados:
- Crie uma FORMATETC estrutura. Defina o membro cfFormat para o valor de formato apropriado da área de transferência e o vinculou membro a TYMED_HGLOBAL.
- Crie uma estrutura de STGMEDIUM. Defina o vinculado membro para TYMED_HGLOBAL.
- Crie um objeto de memória global chamando GlobalAlloc alocar um bloco de memória de tamanho adequado.
- Atribua o bloco de dados a ser transferido para o endereço retornado por GlobalAlloc.
- Atribua o endereço do objeto de memória global ao membro hGlobal da estruturaSTGMEDIUM.
- Carregue o formato no objeto de dados chamando IDataObject::SetData e passando o FORMATETC e STGMEDIUM estruturas criadas nas etapas anteriores.
A função de exemplo a seguir cria um objeto de memória global contendo um valor de DWORD e o carrega em um objeto de dados. O parâmetro pdtobj é um ponteiro para a interface IDataObject do objeto de dados, cf é o valor do formato da área de transferência e dw é o valor dos dados.
STDAPI DataObj_SetDWORD(IDataObject *pdtobj, UINT cf, DWORD dw)
{
FORMATETC fmte = {(CLIPFORMAT) cf,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL};
STGMEDIUM medium;
HRESULT hres = E_OUTOFMEMORY;
DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD));
if (pdw)
{
*pdw = dw;
medium.tymed = TYMED_HGLOBAL;
medium.hGlobal = pdw;
medium.pUnkForRelease = NULL;
hres = pdtobj->SetData(&fmte, &medium, TRUE);
if (FAILED(hres))
GlobalFree((HGLOBAL)pdw);
}
return hres;
}
Implementando IDataObject
IDataObject é a interface primária de um objeto de dados. Ele deve ser implementado por todos os objetos de dados. Ele é usado tanto pela fonte quanto pelo destino para uma variedade de propósitos, incluindo:
- Carregando dados no objeto de dados.
- Extraindo dados do objeto de dados.
- Determinar que tipos de dados estão no objeto de dados.
- Fornecer feedback ao objeto de dados sobre o resultado da transferência de dados.
IDataObject suporta vários métodos. Esta seção discute como implementar os três métodos mais importantes para objetos de dados do Shell, SetData, EnumFormatEtce GetData. Para obter uma discussão sobre os outros métodos, consulte o IDataObject referência.
Método SetData
A função principal do métodoIDataObject::SetData doé permitir que a fonte carregue dados no objeto de dados. Para cada formato a ser incluído, a fonte cria uma estrutura de FORMATETC para identificar o formato e uma estrutura STGMEDIUM para manter um ponteiro para os dados. Em seguida, a fonte chama o do objeto IDataObject::SetData método e passa no formato FORMATETC e STGMEDIUM estruturas. O método deve armazenar essas informações para que estejam disponíveis quando o destino chama IDataObject::GetData para extrair dados do objeto.
No entanto, ao transferir arquivos, o Shell geralmente coloca as informações de cada arquivo a ser transferido em um formato de CFSTR_FILECONTENTS separado. Para distinguir os diferentes arquivos, o lIndex membro da estrutura deFORMATETC de cadaarquivo é definido como um valor de índice que identifica o arquivo específico. Sua implementação IDataObject::SetData deve ser capaz de armazenar vários formatos de CFSTR_FILECONTENTS que diferem apenas por seus membros lIndex.
Enquanto o cursor estiver sobre a janela de destino, o destino pode usar o objeto auxiliar de arrastar e soltar para especificar a imagem de arrastar. O objeto auxiliar de arrastar e soltar chama IDataObject::SetData para carregar formatos privados no objeto de dados que são usados para suporte a processos cruzados. Para suportar o objeto auxiliar de arrastar e soltar, sua implementação IDataObject::SetData deve ser capaz de aceitar e armazenar formatos privados arbitrários.
Depois que os dados forem descartados, alguns tipos de transferência de dados do Shell exigem que o destino chame IDataObject::SetData para fornecer ao objeto de dados informações sobre o resultado da operação de queda. Por exemplo, ao mover arquivos com uma operação de movimentação otimizada, o destino normalmente exclui os arquivos originais, mas não é necessário fazê-lo. O destino informa ao objeto de dados se ele excluiu os arquivos chamando IDataObject::SetData com um formato CFSTR_LOGICALPERFORMEDDROPEFFECT. Existem vários outros Shell Clipboard Formats que também são usados pelo destino para passar informações para o objeto de dados. Seu IDataObject::SetData implementação deve ser capaz de reconhecer esses formatos e responder adequadamente. Para obter mais discussões, consulte Manipulando cenários de transferência de dados do Shell.
Método EnumFormatEtc
Quando o destino recebe um objeto de dados, ele geralmente chama FORMATETC para determinar quais formatos o objeto contém. O método cria um objeto de enumeração OLE e retorna um ponteiro para o IEnumFORMATETC interface do objeto. Em seguida, o destino usa a interface para enumerar os formatos disponíveis.
Um objeto de enumeração deve sempre enumerar os formatos disponíveis em ordem de qualidade, começando com o melhor. A qualidade relativa dos formatos é definida pela fonte de gota. Em geral, os formatos da mais alta qualidade contêm os dados mais ricos e completos. Por exemplo, uma imagem colorida de 24 bits normalmente seria considerada de qualidade superior a uma versão em escala de cinza dessa imagem. A razão para enumerar formatos em ordem de sua qualidade é que os destinos normalmente enumeram até chegarem a um formato que eles suportam e, em seguida, eles usam esse formato para extrair os dados. Para que este procedimento produza o melhor formato disponível que o destino pode suportar, os formatos devem ser enumerados por ordem de qualidade.
Um objeto de enumeração para dados do Shell é implementado da mesma forma que para outros tipos de transferência de dados, com uma exceção notável. Como os objetos de dados normalmente contêm apenas um item de dados por formato, eles normalmente enumeram todos os formatos passados para IDataObject::SetData. No entanto, conforme discutido na seção método SetData, os objetos de dados do Shell podem conter vários formatos CFSTR_FILECONTENTS.
Como o objetivo de IDataObject::EnumFormatEtc é permitir que o destino determine quais tipos de dados estão presentes, não há necessidade de enumerar mais de um formato CFSTR_FILECONTENTS. Se o destino precisar saber quantos desses formatos o objeto de dados contém, ele poderá recuperar essas informações do formato de CFSTR_FILEDESCRIPTOR que o acompanha. Para mais discussões sobre como implementar IDataObject::EnumFormatEtc, consulte a documentação de referência do método.
Método GetData
O destino chama IDataObject::GetData para extrair um formato de dados específico. O destino especifica o formato passando o apropriado FORMATETC estrutura. IDataObject::GetData retorna a estrutura deSTGMEDIUMdo formato.
O alvo pode definir o vinculado membro da estruturaFORMATETCa um valorTYMED_ XXX específico para especificar qual mecanismo de transferência de dados será usado para extrair os dados. No entanto, o destino também pode fazer uma solicitação mais genérica e deixar o objeto de dados decidir. Para solicitar que o objeto de dados selecione o mecanismo de transferência de dados, o destino define todos os TYMED_valores de XXX suportados. IDataObject::GetData seleciona um desses mecanismos de transferência de dados e retorna a estrutura deSTGMEDIUMapropriada. Por exemplo, subordinado é normalmente definido como TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE solicitar qualquer um dos três mecanismos de transferência de dados do Shell.
Observação
Como pode haver vários formatos CFSTR_FILECONTENTS, o cfFormat e membros vinculados da estruturaFORMATETCnão são suficientes para indicar qual estrutura STGMEDIUMIDataObject::GetData deve retornar. Para o formato CFSTR_FILECONTENTS, IDataObject::GetData também deve examinar o FORMATETC membro da estrutura lIndex para retornar a estrutura STGMEDIUM correta.
O formato CFSTR_INDRAGLOOP é colocado em objetos de dados para permitir que os destinos verifiquem o status do loop de arrastar e soltar, evitando a renderização intensiva de memória dos dados do objeto. Os dados do formato são um valor DWORD que é definido como um valor diferente de zero se o objeto de dados estiver dentro de um loop de arrastar. O valor de dados do formato é definido como zero se os dados tiverem sido descartados. Se um destino solicitar esse formato e ele não tiver sido carregado pela origem, IDataObject::GetData deverá responder como se a fonte tivesse carregado o formato com um valor zero.
Enquanto o cursor estiver sobre a janela de destino, o destino pode usar o objeto auxiliar de arrastar e soltar para especificar a imagem de arrastar. O objeto auxiliar de arrastar e soltar chama IDataObject::SetData para carregar formatos privados no objeto de dados que são usados para suporte a processos cruzados. Mais tarde, ele chama IDataObject::GetData para recuperá-los. Para dar suporte ao objeto auxiliar de arrastar e soltar, sua implementação do Shell Data Object deve ser capaz de retornar formatos privados arbitrários quando solicitados.
Implementando IDropSource
A origem deve criar um objeto que exponha um IDropSource interface. Essa interface permite que a fonte atualize o arraste a imagem que indica a posição atual do cursor e forneça feedback ao sistema sobre como encerrar uma operação de arrastar e soltar. IDropSource tem dois métodos: GiveFeedback e QueryContinueDrag.
Método GiveFeedback
Enquanto estiver no loop de arrasto, uma fonte de soltar é responsável por manter o controle da posição do cursor e exibir uma imagem de arrasto apropriada. No entanto, em alguns casos, você pode querer alterar a aparência da imagem de arrastar quando ela estiver sobre a janela do destino de soltar.
Quando o cursor entra ou sai da janela de destino e enquanto se move sobre a janela de destino, o sistema chama periodicamente a interfaceIDropTargetdo destino. O destino responde com um valor de DROPEFFECT que é encaminhado para a origem por meio do métodoGiveFeedback. Se apropriado, a fonte pode modificar a aparência do cursor com base no valor DROPEFFECT. Para obter mais detalhes, consulte o GiveFeedback e referências DoDragDrop.
Método QueryContinueDrag
Esse método é chamado se o botão do mouse ou o estado do teclado for alterado enquanto o objeto de dados estiver no loop de arraste. Ele notifica a fonte se a tecla ESC foi pressionada e fornece o estado atual das teclas modificadoras do teclado, como CTRL ou SHIFT. O valor de retorno do método QueryContinueDrag especifica uma das três ações:
- S_OK. Continuar a operação de arrastar
- DRAGDROP_S_DROP. Solte os dados. Em seguida, o sistema chama o do destino IDropTarget::D rop método.
- DRAGDROP_S_CANCEL. Encerre o loop de arrasto sem soltar os dados. Esse valor normalmente é retornado se a tecla ESCAPE foi pressionada.
Para obter mais discussão, consulte o QueryContinueDrag e DoDragDrop referências.
Como um destino lida com um objeto de dados
O destino recebe um objeto de dados quando recupera o objeto de dados da Área de Transferência ou o deixa cair na janela de destino pelo usuário. O destino pode então extrair dados do objeto de dados. Se necessário, o alvo também pode notificar o objeto de dados do resultado da operação. Antes de uma transferência de dados do Shell, um destino de queda deve se preparar para a operação:
- O destino deve chamar RegisterClipboardFormat para obter um valor de formato de área de transferência válido para todos os formatos de Shell, exceto CF_HDROP, que possam ser incluídos no objeto de dados. CF_HDROP já é um formato de área de transferência válido e não precisa ser registrado.
- Para suportar uma operação de arrastar e soltar, o destino deve implementar uma interface IDropTarget e registrar uma janela de destino. Para registrar uma janela de destino, o destino chama RegisterDragDrop e passa o identificador da janela e o ponteiro da interface IDropTarget.
Para transferências da área de transferência, o destino não recebe nenhuma notificação de que um objeto de dados foi colocado na área de transferência. Normalmente, um aplicativo é notificado de que um objeto está na Área de Transferência por uma ação do usuário, como clicar no botão Colar na barra de ferramentas do aplicativo. Em seguida, o destino recupera o ponteiro IDataObject IDataObject do objeto de dados da área de transferência chamando OleGetClipboard. Para transferências de dados de arrastar e soltar, o sistema usa a interface IDropTarget do destino para fornecer ao destino informações sobre o progresso da transferência de dados:
- O sistema chama IDropTarget::D ragEnter quando o cursor entra na janela de destino.
- O sistema chama periodicamente IDropTarget::D ragOver quando o cursor passa sobre a janela de destino, para dar ao alvo a posição atual do cursor.
- O sistema chama IDropTarget::D ragLeave quando o cursor sai da janela de destino.
- O sistema chama IDropTarget::D rop quando o usuário solta o objeto de dados na janela de destino.
Para obter uma discussão sobre como implementar esses métodos, consulte IDropTarget.
Quando os dados são descartados, IDropTarget::D rop fornece ao destino um ponteiro para a interface IDataObject do objeto de dados. Em seguida, o destino usa essa interface para extrair dados do objeto de dados.
Extraindo dados do shell de um objeto de dados
Depois que um objeto de dados é descartado ou recuperado da Área de Transferência, o destino pode extrair os dados de que precisa. A primeira etapa no processo de extração é normalmente enumerar os formatos contidos pelo objeto de dados:
- Chame IDataObject::EnumFormatEtc. O objeto de dados cria um objeto de enumeração OLE padrão e retorna um ponteiro para seu interface de IEnumFORMATETC.
- Use o IEnumFORMATETC métodos para enumerar os formatos contidos pelo objeto de dados. Esta operação geralmente recupera uma estrutura de FORMATETC para cada formato que o objeto contém. No entanto, o objeto de enumeração normalmente retorna apenas um único estrutura de FORMATETC para o formato CFSTR_FILECONTENTS, independentemente de quantos formatos estão contidos pelo objeto de dados.
- Selecione um ou mais formatos a serem extraídos e armazene seus FORMATETC estruturas.
Para recuperar um formato específico, passe a estrutura deFORMATETCassociada para IDataObject::GetData. Esse método retorna uma estrutura de STGMEDIUM que fornece acesso aos dados. Para especificar um mecanismo de transferência de dados específico, defina o valor vinculado da estrutura FORMATETC para o valorTYMED_ XXX correspondente. Para solicitar que o objeto de dados selecione um mecanismo de transferência de dados, o destino define os valores deTYMED_ XXX para cada mecanismo de transferência de dados que o destino pode manipular. O objeto de dados seleciona um desses mecanismos de transferência de dados e retorna a estrutura STGMEDIUM apropriada.
Para a maioria dos formatos, o destino pode recuperar os dados passando a FORMATETC estrutura que recebeu quando enumerou os formatos disponíveis. Uma exceção a esta regra é CFSTR_FILECONTENTS. Como um objeto de dados pode conter várias instâncias desse formato, a estrutura de FORMATETC retornada pelo enumerador pode não corresponder ao formato específico que você deseja extrair. Além de especificar o cfFormat e membros vinculados, você também deve definir o membro lIndex para o valor de índice do arquivo. Para obter mais discussões, consulte a seção Usando o formato CFSTR_FILECONTENTS para extrair dados de um arquivo de Manipulando cenários de transferência de dados do Shell
O processo de extração de dados depende do tipo de ponteiro contido pela estrutura deSTGMEDIUM deretornada. Se a estrutura contiver um ponteiro para um IStream ou interface IStorage, use os métodos de interface para extrair os dados. O processo de extração de dados de um objeto de memória global é discutido na próxima seção.
Extraindo um objeto de memória global de um objeto de dados
Muitos dos formatos de dados do Shell estão na forma de um objeto de memória global. Use o procedimento a seguir para extrair um formato que contém um objeto de memória global de um objeto de dados e atribuir seus dados a uma variável local:
Crie uma FORMATETC estrutura. Defina o membro cfFormat para o valor de formato apropriado da área de transferência e o vinculou membro a TYMED_HGLOBAL.
Crie uma estruturaSTGMEDIUMvazia.
Chame IDataObject::GetDatae passe ponteiros para o FORMATETC e estruturas de STGMEDIUM.
Quando IDataObject::GetData retorna, a estrutura STGMEDIUM conterá um ponteiro para o objeto de memória global que contém os dados.
Atribua os dados a uma variável local chamando GlobalLock e passando o hGlobal membro da estruturaSTGMEDIUM.
Chame GlobalUnlock para liberar o bloqueio no objeto de memória global.
Chame ReleaseStgMedium para liberar o objeto de memória global.
Observação
Você deve usar ReleaseStgMedium para liberar o objeto de memória global, não GlobalFree.
O exemplo a seguir mostra como extrair um valor de DWORD armazenado como um objeto de memória global de um objeto de dados. O parâmetro pdtobj é um ponteiro para a interface IDataObject do objeto de dados, cf é o formato da área de transferência que identifica os dados desejados e pdwOut é usado para retornar o valor de dados.
STDAPI DataObj_GetDWORD(IDataObject *pdtobj, UINT cf, DWORD *pdwOut)
{ STGMEDIUM medium;
FORMATETC fmte = {(CLIPFORMAT) cf, NULL, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL};
HRESULT hres = pdtobj->GetData(&fmte, &medium);
if (SUCCEEDED(hres))
{
DWORD *pdw = (DWORD *)GlobalLock(medium.hGlobal);
if (pdw)
{
*pdwOut = *pdw;
GlobalUnlock(medium.hGlobal);
}
else
{
hres = E_UNEXPECTED;
}
ReleaseStgMedium(&medium);
}
return hres;
}
Implementando IDropTarget
O sistema usa a interface IDropTarget para se comunicar com o destino enquanto o cursor está sobre a janela de destino. As respostas do destino são encaminhadas para a origem por meio de sua interfaceIDropSource. Dependendo da resposta, a fonte pode modificar o ícone que representa os dados. Se o destino de soltar precisar especificar o ícone de dados, ele poderá fazê-lo criando um objeto auxiliar de arrastar e soltar .
Com operações convencionais de arrastar e soltar, o destino informa o objeto de dados sobre o resultado da operação definindo o parâmetro pdwEffect de IDropTarget::D rop para o valor deDROPEFFECTapropriado. Com objetos de dados do Shell, o destino também pode precisar chamar IDataObject::SetData. Para obter uma discussão sobre como os destinos devem responder a diferentes cenários de transferência de dados, consulte Manipulando cenários de transferência de dados do Shell.
As seções a seguir discutem brevemente como implementar os IDropTarget::D ragEnter, IDropTarget::D ragOvere IDropTarget::D rop métodos. Para obter mais detalhes, consulte a documentação de referência.
Método DragEnter
O sistema chama o IDropTarget::D ragEnter método quando o cursor entra na janela de destino. Seus parâmetros fornecem ao destino a localização do cursor, o estado das teclas modificadoras do teclado, como a tecla CTRL, e um ponteiro para a interface IDataObject do objeto de dados. O destino é responsável por usar essa interface para determinar se pode aceitar qualquer um dos formatos contidos pelo objeto de dados. Se puder, normalmente deixa o valor de pdwEffect inalterado. Se ele não puder aceitar nenhum dado do objeto de dados, ele definirá o parâmetro pdwEffect como DROPEFFECT_NONE. O sistema passa o valor desse parâmetro para a interface de IDropSource do objeto de dados para permitir que ele exiba a imagem de arraste apropriada.
Os destinos não devem usar o método IDataObject::GetData para renderizar dados do Shell antes que eles sejam descartados. A renderização completa dos dados do objeto para cada ocorrência pode fazer com que o cursor de arraste fique parado. Para evitar esse problema, alguns objetos Shell contêm um formato CFSTR_INDRAGLOOP. Ao extrair esse formato, os destinos podem verificar o status do loop de arrasto, evitando a renderização intensiva de memória dos dados do objeto. O valor de dados do formato é um DWORD que é definido como um valor diferente de zero se o objeto de dados estiver dentro de um loop de arrasto. O valor de dados do formato é definido como zero se os dados tiverem sido descartados.
Se o destino puder aceitar dados do objeto de dados, ele deverá examinar grfKeyState para determinar se alguma tecla modificadora foi pressionada para modificar o comportamento normal de queda. Por exemplo, a operação padrão é normalmente um movimento, mas pressionar a tecla CTRL geralmente indica uma operação de cópia.
Enquanto o cursor estiver sobre a janela de destino, o destino pode usar o objeto auxiliar de arrastar e soltar para substituir a imagem de arrastar do objeto de dados pela sua própria. Em caso afirmativo, IDropTarget::D ragEnter deve chamar IDropTargetHelper::D ragEnter para passar as informações contidas nos parâmetros DragEnter para o objeto auxiliar de arrastar e soltar.
Método DragOver
À medida que o cursor se move dentro da janela de destino, o sistema chama periodicamente o IDropTarget::D ragOver método. Seus parâmetros fornecem ao alvo a localização do cursor e o estado das teclas modificadoras do teclado, como a tecla CTRL. IDropTarget::D ragOver tem as mesmas responsabilidades que IDropTarget::D ragEnter, e as implementações são geralmente muito semelhantes.
Se o destino estiver usando o objeto auxiliar de arrastar e soltar, IDropTarget::D ragOver deve chamar IDropTargetHelper::D ragOver para encaminhar as informações contidas nos parâmetros DragOver para o objeto auxiliar de arrastar e soltar.
Método de gota
O sistema chama o método IDropTarget::D rop para notificar o destino de que o usuário soltou os dados, normalmente soltando o botão do mouse. IDropTarget::D rop tem os mesmos parâmetros que IDropTarget::D ragEnter. O destino normalmente responde extraindo um ou mais formatos do objeto de dados. Quando terminar, o destino deve definir o parâmetro pdwEffect como um valor de DROPEFFECT que indica o resultado da operação. Para alguns tipos de transferência de dados do Shell, o destino também deve chamar IDataObject::SetData para passar um formato com informações adicionais sobre o resultado da operação para o objeto de dados. Para obter uma discussão detalhada, consulte Manipulando cenários de transferência de dados do Shell.
Se o destino estiver usando o objeto auxiliar de arrastar e soltar, IDropTarget::D rop deverá chamar IDropTargetHelper::D rop para encaminhar as informações contidas nos parâmetrosIDropTargetHelper::D ragOver dopara o objeto auxiliar de arrastar e soltar.
Usando o objeto auxiliar de arrastar e soltar
O objeto auxiliar de arrastar e soltar (CLSID_DragDropHelper) é exportado pelo Shell para permitir que os destinos especifiquem a imagem de arrastar enquanto ela estiver sobre a janela de destino. Para usar o objeto auxiliar de arrastar e soltar, crie um objeto de servidor em processo chamando CoCreateInstance com um identificador de classe (CLSID) de CLSID_DragDropHelper. O objeto auxiliar de arrastar e soltar expõe duas interfaces que são usadas da seguinte maneira:
- O interface IDragSourceHelper permite que o destino de soltar especifique um ícone para representar o objeto de dados.
- A interface IDropTargetHelper permite que o destino de soltar informe o objeto auxiliar de arrastar e soltar sobre o local do cursor e mostre ou oculte o ícone de dados.
Usando a interface IDragSourceHelper
A interfaceIDragSourceHelperé exposta pelo objeto auxiliar de arrastar e soltar para permitir que um destino de soltar forneça a imagem que será exibida enquanto o cursor estiver sobre a janela de destino. IDragSourceHelper fornece duas maneiras alternativas de especificar o bitmap a ser usado como uma imagem de arrasto:
- Os destinos de soltar que têm uma janela podem registrar uma mensagem de janela DI_GETDRAGIMAGE para ela inicializando o objeto auxiliar de arrastar e soltar com IDragSourceHelper::InitializeFromWindow. Quando o destino recebe uma mensagem de DI_GETDRAGIMAGE, o manipulador coloca as informações de bitmap da imagem de arraste na estrutura deSHDRAGIMAGEque é passada como o valor de lParam da mensagem.
- Os destinos de soltar sem janela especificam um bitmap quando inicializam o objeto auxiliar de arrastar e soltar com IDragSourceHelper::InitializeFromBitmap.
Usando a interface IDropTargetHelper
Essa interface permite que o destino de soltar notifique o objeto auxiliar de arrastar e soltar quando o cursor entra ou sai do destino. Enquanto o cursor estiver sobre a janela de destino, IDropTargetHelper permite que o destino forneça ao objeto auxiliar de arrastar e soltar as informações que o destino recebe por meio de sua interfaceIDropTarget.
Quatro dos métodosIDropTargetHelper—IDropTargetHelper::D ragEnter, IDropTargetHelper::D ragLeave, IDropTargetHelper::D ragOvere IDropTargetHelper::D rop— estão associados ao método IDropTarget de mesmo nome. Para usar o objeto auxiliar de arrastar e soltar, cada um dos métodos IDropTarget deve chamar o método IDropTargetHelper correspondente para encaminhar as informações para o objeto auxiliar de arrastar e soltar. O quinto método IDropTargetHelper, IDropTargetHelper::Show, notifica o objeto auxiliar de arrastar e soltar para mostrar ou ocultar a imagem arrastada. Este método é usado ao arrastar sobre uma janela de destino em um modo de vídeo de baixa profundidade de cor. Ele permite que o alvo oculte a imagem arrastada enquanto está pintando a janela.