Oggetto dati shell

L'oggetto dati è fondamentale per tutti i trasferimenti di dati shell. Si tratta principalmente di un contenitore per contenere i dati trasferiti. Tuttavia, la destinazione può anche comunicare con l'oggetto dati per facilitare alcuni tipi specializzati di trasferimento dei dati della shell, ad esempio spostamenti ottimizzati. In questo argomento viene fornita una descrizione generale del funzionamento degli oggetti dati shell, del modo in cui vengono costruiti da un'origine e di come vengono gestiti da una destinazione. Per una descrizione dettagliata dell'uso di oggetti dati per trasferire diversi tipi di dati della shell, vedere Gestione degli scenari di trasferimento dei dati della shell.

Funzionamento degli oggetti dati

Gli oggetti dati sono oggetti COM (Component Object Model), creati dall'origine dati per trasferire i dati a una destinazione. In genere contengono più di un elemento di dati. Esistono due motivi per questa pratica:

  • Anche se quasi qualsiasi tipo di dati può essere trasferito con un oggetto dati, l'origine in genere non conosce il tipo di dati che la destinazione può accettare. Ad esempio, i dati potrebbero essere una parte di un documento di testo formattato. Anche se la destinazione potrebbe essere in grado di gestire informazioni di formattazione complesse, potrebbe anche essere in grado di accettare solo testo ANSI. Per questo motivo, gli oggetti dati spesso includono gli stessi dati in diversi formati. La destinazione può quindi estrarre i dati in un formato che può gestire.
  • Gli oggetti dati possono anche contenere elementi di dati ausiliari che non sono versioni dei dati di origine. Questo tipo di elemento dati fornisce in genere informazioni aggiuntive sull'operazione di trasferimento dei dati. Ad esempio, Shell usa elementi di dati ausiliari per indicare se un file deve essere copiato o spostato.

Formati degli Appunti

Ogni elemento di dati in un oggetto dati ha un formato associato, in genere denominato formato degli Appunti. Esistono diversi formati standard degli Appunti, dichiarati in Winuser.h, che corrispondono ai tipi di dati di uso comune. I formati degli Appunti sono numeri interi, ma in genere vengono definiti dal nome equivalente, che ha il formato CF_XXX. Ad esempio, il formato degli Appunti per il testo ANSI è CF_TEXT.

Le applicazioni possono estendere l'intervallo di formati disponibili negli Appunti definendo formati privati. Per definire un formato privato, un'applicazione chiama RegisterClipboardFormat con una stringa che identifica il formato. L'intero senza segno restituito dalla funzione è un valore di formato valido che può essere usato esattamente come un formato standard degli Appunti. Tuttavia, sia l'origine che la destinazione devono registrare il formato per usarlo. Con un'eccezione, CF_HDROP, i formati degli Appunti usati per trasferire i dati della shell sono definiti come formati privati. Devono essere registrati dall'origine e dalla destinazione prima di poterli usare. Per una descrizione dei formati degli Appunti della shell disponibili, vedere Formati degli Appunti della shell.

Anche se esistono alcune eccezioni, gli oggetti dati in genere contengono solo un elemento di dati per ogni formato degli Appunti supportato. Questa correlazione uno-a-uno tra formato e dati consente di usare il valore di formato come identificatore per l'elemento di dati associato. Infatti, quando si discute del contenuto di un oggetto dati, un particolare elemento di dati viene in genere chiamato "formato" e viene fatto riferimento al relativo nome di formato. Ad esempio, frasi come "Estrai il formato CF_TEXT..." vengono in genere utilizzati quando si discute dell'elemento di dati di testo ANSI di un oggetto dati.

Quando la destinazione di rilascio riceve il puntatore all'oggetto dati, la destinazione di rilascio enumera i formati disponibili per determinare quali tipi di dati sono disponibili. Richiede quindi uno o più formati disponibili ed estrae i dati. Il modo specifico in cui la destinazione estrae i dati shell da un oggetto dati varia in base al formato; questo argomento viene descritto in dettaglio in Come una destinazione gestisce un oggetto dati.

Con semplici trasferimenti di dati degli Appunti, i dati vengono inseriti in un oggetto memoria globale. L'indirizzo di tale oggetto viene posizionato negli Appunti, insieme al relativo formato. Il formato degli Appunti indica alla destinazione il tipo di dati che troverà nell'indirizzo associato. Anche se i trasferimenti semplici degli Appunti sono facili da implementare:

  • Gli oggetti dati offrono un modo molto più flessibile per trasferire i dati.
  • Gli oggetti dati sono più adatti per il trasferimento di grandi quantità di dati.
  • Gli oggetti dati devono essere usati per trasferire i dati con un'operazione di trascinamento della selezione.

Per questi motivi, tutti i trasferimenti di dati shell usano oggetti dati. Con gli oggetti dati, i formati degli Appunti non vengono usati direttamente. Gli elementi di dati vengono invece identificati con una generalizzazione del formato degli Appunti, una struttura FORMATETC .

Struttura FORMATETC

La struttura FORMATETC è una versione estesa di un formato degli Appunti. Come usato per i trasferimenti di dati shell, la struttura FORMATETC presenta le caratteristiche seguenti:

  • Un elemento di dati è ancora identificato dal formato degli Appunti, nel membro cfFormat .

  • Il trasferimento dei dati non è limitato agli oggetti di memoria globale. Il membro tymed viene utilizzato per indicare il meccanismo di trasferimento dei dati contenuto nella struttura STGMEDIUM associata. È impostato su uno dei valori TYMED_XXX .

  • Shell usa il membro lIndex con il formato CFSTR_FILECONTENTS per consentire a un oggetto dati di contenere più elementi di dati per formato. Per informazioni su come usare questo formato, vedere la sezione Uso del formato CFSTR_FILECONTENTS per estrarre dati da un file di Gestione degli scenari di trasferimento dati shell.

  • Il membro dwAspect viene in genere impostato su DVASPECT_CONTENT. Esistono tuttavia tre valori definiti in Shlobj.h che possono essere usati per il trasferimento dei dati shell.

    Valore Descrizione
    DVASPECT_COPY Utilizzato per indicare che il formato rappresenta una copia dei dati.
    DVASPECT_LINK Utilizzato per indicare che il formato rappresenta un collegamento ai dati.
    DVASPECT_SHORTNAME Usato con il formato CF_HDROP per richiedere un percorso di file con i nomi abbreviati nel formato 8.3.

     

  • Il membro ptd non viene usato per i trasferimenti di dati shell ed è in genere impostato su NULL.

Struttura STGMEDIUM

La struttura STGMEDIUM fornisce l'accesso ai dati trasferiti. Per i dati shell sono supportati tre meccanismi di trasferimento dei dati:

Il membro tymed della struttura STGMEDIUM è un valore TYMED_XXX che identifica il meccanismo di trasferimento dei dati. Il secondo membro è un puntatore utilizzato dalla destinazione per estrarre i dati. Il puntatore può essere uno dei diversi tipi, a seconda del valore tymed . I tre valori tymed usati per i trasferimenti di dati shell sono riepilogati nella tabella seguente, insieme al nome del membro STGMEDIUM corrispondente.

Valore tymed Nome del membro Descrizione
TYMED_HGLOBAL Hglobal Puntatore a un oggetto memoria globale. Questo tipo di puntatore viene in genere usato per il trasferimento di piccole quantità di dati. Ad esempio, Shell usa oggetti di memoria globali per trasferire stringhe di testo brevi, ad esempio nomi di file o URL.
TYMED_ISTREAM pstm Puntatore a un'interfaccia IStream . Questo tipo di puntatore è preferito per la maggior parte dei trasferimenti di dati shell perché richiede memoria relativamente piccola rispetto alla TYMED_HGLOBAL. Inoltre, il meccanismo di trasferimento dei dati TYMED_ISTREAM non richiede all'origine di archiviare i dati in alcun modo specifico.
TYMED_ISTORAGE pstg Puntatore a un'interfaccia IStorage . La destinazione chiama i metodi di interfaccia per estrarre i dati. Come TYMED_ISTREAM, questo tipo di puntatore richiede una memoria relativamente piccola. Tuttavia, poiché TYMED_ISTORAGE è meno flessibile di TYMED_ISTREAM, non è come comunemente usato.

 

Come un'origine crea un oggetto dati

Quando un utente avvia un trasferimento dati shell, l'origine è responsabile della creazione di un oggetto dati e del caricamento con i dati. La procedura seguente riepiloga il processo:

  1. Chiamare RegisterClipboardFormat per ottenere un valore di formato degli Appunti valido per ogni formato shell che verrà incluso nell'oggetto dati. Tenere presente che CF_HDROP è già un formato valido negli Appunti e non deve essere registrato.
  2. Per ogni formato da trasferire, inserire i dati associati in un oggetto memoria globale o creare un oggetto che fornisce l'accesso a tali dati tramite un'interfaccia IStream o IStorage . Le interfacce IStream e IStorage vengono create usando tecniche COM standard. Per una discussione su come gestire gli oggetti di memoria globale, vedere Come aggiungere un oggetto memoria globale a un oggetto dati.
  3. Creare strutture FORMATETC e STGMEDIUM per ogni formato.
  4. Creare un'istanza di un oggetto dati.
  5. Caricare i dati nell'oggetto dati chiamando il metodo IDataObject::SetData per ogni formato supportato e passando le strutture FORMATETC e STGMEDIUM del formato.
  6. Con i trasferimenti di dati degli Appunti, chiamare OleSetClipboard per posizionare un puntatore all'interfaccia IDataObject dell'oggetto dati negli Appunti. Per i trasferimenti di trascinamento, avviare un ciclo di trascinamento chiamando DoDragDrop. Il puntatore IDataObject verrà passato alla destinazione di rilascio quando i dati vengono eliminati, terminando il ciclo di trascinamento.

L'oggetto dati è ora pronto per essere trasferito alla destinazione. Per i trasferimenti di dati negli Appunti, l'oggetto viene semplicemente mantenuto fino a quando non viene richiesto dalla destinazione chiamando OleGetClipboard. Per i trasferimenti di dati trascinati, l'oggetto dati è responsabile della creazione di un'icona per rappresentare i dati e spostarli mentre l'utente sposta il cursore. Mentre l'oggetto si trova nel ciclo di trascinamento, l'origine riceve le informazioni sullo stato tramite l'interfaccia IDropSource . Per altre discussioni, vedere Implementazione di IDropSource.

L'origine non riceve alcuna notifica se l'oggetto dati viene recuperato dagli Appunti da una destinazione. Quando un oggetto viene eliminato in una destinazione da un'operazione di trascinamento della selezione, la funzione DoDragDrop chiamata per avviare il ciclo di trascinamento restituirà.

Come aggiungere un oggetto memoria globale a un oggetto dati

Molti dei formati di dati shell sono sotto forma di un oggetto memoria globale. Usare la procedura seguente per creare un formato contenente un oggetto memoria globale e caricarlo nell'oggetto dati:

  1. Creare una struttura FORMATETC . Impostare il membro cfFormat sul valore di formato degli Appunti appropriato e sul membro tymed su TYMED_HGLOBAL.
  2. Creare una struttura STGMEDIUM . Impostare il membro tymed su TYMED_HGLOBAL.
  3. Creare un oggetto di memoria globale chiamando GlobalAlloc per allocare un blocco di memoria di dimensioni appropriate.
  4. Assegnare il blocco di dati da trasferire all'indirizzo restituito da GlobalAlloc.
  5. Assegnare l'indirizzo dell'oggetto memoria globale al membro hGlobal della struttura STGMEDIUM .
  6. Caricare il formato nell'oggetto dati chiamando IDataObject::SetData e passando le strutture FORMATETC e STGMEDIUM create nei passaggi precedenti.

La funzione di esempio seguente crea un oggetto memoria globale contenente un valore DWORD e lo carica in un oggetto dati. Il parametro pdtobj è un puntatore all'interfaccia IDataObject dell'oggetto dati, cf è il valore del formato degli Appunti e dw è il valore dei dati.

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;
}

Implementazione di IDataObject

IDataObject è un'interfaccia primaria di un oggetto dati. Deve essere implementato da tutti gli oggetti dati. Viene usato sia dall'origine che dalla destinazione per un'ampia gamma di scopi, tra cui:

  • Caricamento dei dati nell'oggetto dati.
  • Estrazione di dati dall'oggetto dati.
  • Determinazione dei tipi di dati nell'oggetto dati.
  • Fornire commenti e suggerimenti all'oggetto dati sul risultato del trasferimento dei dati.

IDataObject supporta diversi metodi. Questa sezione illustra come implementare i tre metodi più importanti per gli oggetti dati shell, SetData, EnumFormatEtc e GetData. Per una discussione sugli altri metodi, vedere il riferimento IDataObject .

SetData (metodo)

La funzione primaria del metodo IDataObject::SetData consiste nel consentire all'origine di caricare i dati nell'oggetto dati. Per includere ogni formato, l'origine crea una struttura FORMATETC per identificare il formato e una struttura STGMEDIUM per contenere un puntatore ai dati. L'origine chiama quindi il metodo IDataObject::SetData dell'oggetto e passa nelle strutture FORMATETC e STGMEDIUM del formato. Il metodo deve archiviare queste informazioni in modo che sia disponibile quando la destinazione chiama IDataObject::GetData per estrarre i dati dall'oggetto.

Tuttavia, quando si trasferiscono file, Shell inserisce spesso le informazioni per ogni file da trasferire in un formato CFSTR_FILECONTENTS separato. Per distinguere i diversi file, il membro lIndex della struttura FORMATETC di ogni file è impostato su un valore di indice che identifica il file specifico. L'implementazione di IDataObject::SetData deve essere in grado di archiviare più formati di CFSTR_FILECONTENTS che differiscono solo dai membri lIndex .

Mentre il cursore si trova sulla finestra di destinazione, la destinazione può usare l'oggetto helper trascinamento per specificare l'immagine di trascinamento. L'oggetto helper drag-and-drop chiama IDataObject::SetData per caricare i formati privati nell'oggetto dati usato per il supporto tra processi. Per supportare l'oggetto helper drag-and-drop, l'implementazione IDataObject::SetData deve essere in grado di accettare e archiviare formati privati arbitrari.

Dopo aver eliminato i dati, alcuni tipi di trasferimento dei dati shell richiedono la destinazione per chiamare IDataObject::SetData per fornire all'oggetto dati informazioni sul risultato dell'operazione di rilascio. Ad esempio, quando si spostano file con un'operazione di spostamento ottimizzata, la destinazione elimina normalmente i file originali, ma non è necessario farlo. La destinazione informa l'oggetto dati se ha eliminato i file chiamando IDataObject::SetData con un formato CFSTR_LOGICALPERFORMEDDROPEFFECT . Esistono diversi altri formati degli Appunti della shell usati anche dalla destinazione per passare informazioni all'oggetto dati. L'implementazione di IDataObject::SetData deve essere in grado di riconoscere questi formati e rispondere in modo appropriato. Per altre discussioni, vedere Gestione degli scenari di trasferimento dei dati di Shell.

Metodo EnumFormatEtc

Quando la destinazione riceve un oggetto dati, in genere chiama FORMATETC per determinare quali formati contiene l'oggetto. Il metodo crea un oggetto enumerazione OLE e restituisce un puntatore all'interfaccia IEnumFORMATETC dell'oggetto. La destinazione usa quindi l'interfaccia per enumerare i formati disponibili.

Un oggetto enumerazione deve sempre enumerare i formati disponibili in ordine di qualità, a partire dal meglio. La qualità relativa dei formati è definita dall'origine di eliminazione. In generale, i formati di alta qualità contengono i dati più ricchi e più completi. Ad esempio, un'immagine a colori a 24 bit viene normalmente considerata una qualità superiore rispetto a una versione in scala grigia di tale immagine. Il motivo per l'enumerazione dei formati in ordine di qualità è che le destinazioni in genere enumera fino a quando non ottengono un formato supportato e quindi usano tale formato per estrarre i dati. Per questa procedura per produrre il formato più disponibile che la destinazione può supportare, i formati devono essere enumerati in ordine di qualità.

Un oggetto di enumerazione per i dati shell viene implementato in modo analogo a quello di altri tipi di trasferimento dati, con un'eccezione notevole. Poiché gli oggetti dati in genere contengono un solo elemento di dati per formato, in genere enumera ogni formato passato a IDataObject::SetData. Tuttavia, come illustrato nella sezione Metodo SetData , gli oggetti dati shell possono contenere più formati di CFSTR_FILECONTENTS .

Poiché lo scopo di IDataObject::EnumFormatEtc consiste nel consentire alla destinazione di determinare quali tipi di dati sono presenti, non è necessario enumerare più CFSTR_FILECONTENTS formato. Se la destinazione deve conoscere il numero di questi formati contenuti dall'oggetto dati, la destinazione può recuperare tali informazioni dal formato CFSTR_FILEDESCRIPTOR adiacente. Per altre informazioni su come implementare IDataObject::EnumFormatEtc, vedere la documentazione di riferimento del metodo.

Metodo GetData

La destinazione chiama IDataObject::GetData per estrarre un formato di dati specifico. La destinazione specifica il formato passando la struttura FORMATETC appropriata. IDataObject::GetData restituisce la struttura STGMEDIUM del formato.

La destinazione può impostare il membro tymed della struttura FORMATETC su un valore specifico TYMED_XXX per specificare quale meccanismo di trasferimento dati userà per estrarre i dati. Tuttavia, la destinazione può anche effettuare una richiesta più generica e consentire all'oggetto dati di decidere. Per chiedere all'oggetto dati di selezionare il meccanismo di trasferimento dati, la destinazione imposta tutti i valori TYMED_ XXX supportati. IDataObject::GetData seleziona uno di questi meccanismi di trasferimento dati e restituisce la struttura STGMEDIUM appropriata. Ad esempio, tymed è comunemente impostato su TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE per richiedere uno dei tre meccanismi di trasferimento dei dati shell.

Nota

Poiché possono essere presenti più formati CFSTR_FILECONTENTS , i membri cfFormat e tymed della struttura FORMATETC non sono sufficienti per indicare quale struttura STGMEDIUMIDataObject::GetData deve restituire. Per il formato CFSTR_FILECONTENTS, IDataObject::GetData deve anche esaminare il membro lIndex della struttura FORMATETC per restituire la struttura STGMEDIUM corretta.

 

Il formato CFSTR_INDRAGLOOP viene inserito negli oggetti dati per consentire alle destinazioni di controllare lo stato del ciclo di trascinamento e rilascio, evitando il rendering intensivo della memoria dei dati dell'oggetto. I dati del formato sono un valore DWORD impostato su un valore diverso da zero se l'oggetto dati si trova all'interno di un ciclo di trascinamento. Il valore dei dati del formato è impostato su zero se i dati sono stati eliminati. Se una destinazione richiede questo formato e non è stata caricata dall'origine, IDataObject::GetData deve rispondere come se l'origine avesse caricato il formato con un valore zero.

Mentre il cursore si trova sulla finestra di destinazione, la destinazione può usare l'oggetto helper trascinamento per specificare l'immagine di trascinamento. L'oggetto helper drag-and-drop chiama IDataObject::SetData per caricare i formati privati nell'oggetto dati usato per il supporto tra processi. In seguito chiama IDataObject::GetData per recuperarli. Per supportare l'oggetto helper drag-and-drop, l'implementazione dell'oggetto dati shell deve essere in grado di restituire formati privati arbitrari quando vengono richiesti.

Implementazione di IDropSource

L'origine deve creare un oggetto che espone un'interfaccia IDropSource . Questa interfaccia consente all'origine di aggiornare l'immagine di trascinamento che indica la posizione corrente del cursore e di fornire commenti e suggerimenti al sistema su come terminare un'operazione di trascinamento. IDropSource include due metodi: GiveFeedback e QueryContinueDrag.

GiveFeedback (metodo)

Durante il ciclo di trascinamento, un'origine di rilascio è responsabile di tenere traccia della posizione del cursore e visualizzare un'immagine di trascinamento appropriata. Tuttavia, in alcuni casi è possibile modificare l'aspetto dell'immagine di trascinamento quando si trova nella finestra della destinazione di rilascio.

Quando il cursore entra o lascia la finestra di destinazione e mentre si sposta sulla finestra di destinazione, il sistema chiama periodicamente l'interfaccia IDropTarget della destinazione. La destinazione risponde con un valore DROPEFFECT inoltrato all'origine tramite il metodo GiveFeedback . Se appropriato, l'origine può modificare l'aspetto del cursore in base al valore DROPEFFECT . Per ulteriori dettagli, vedere i riferimenti GiveFeedback e DoDragDrop .

QueryContinueDrag (metodo)

Questo metodo viene chiamato se il pulsante del mouse o lo stato della tastiera cambia mentre l'oggetto dati si trova nel ciclo di trascinamento. Notifica all'origine se il tasto ESC è stato premuto e fornisce lo stato corrente dei tasti di modifica della tastiera, ad esempio CTRL o MAIUSC. Il valore restituito del metodo QueryContinueDrag specifica una delle tre azioni:

  • S_OK. Continuare l'operazione di trascinamento
  • DRAGDROP_S_DROP. Eliminare i dati. Il sistema chiama quindi il metodo IDropTarget::D rop della destinazione.
  • DRAGDROP_S_CANCEL. Terminare il ciclo di trascinamento senza eliminare i dati. Questo valore viene in genere restituito se il tasto ESCAPE è stato premuto.

Per altre discussioni, vedere i riferimenti QueryContinueDrag e DoDragDrop .

Modalità di gestione di un oggetto dati da parte di una destinazione

La destinazione riceve un oggetto dati quando recupera l'oggetto dati dagli Appunti o lo ha eliminato nella finestra di destinazione dall'utente. La destinazione può quindi estrarre dati dall'oggetto dati. Se necessario, la destinazione può anche notificare all'oggetto dati il risultato dell'operazione. Prima di un trasferimento dei dati shell, una destinazione di rilascio deve prepararsi per l'operazione:

  1. La destinazione deve chiamare RegisterClipboardFormat per ottenere un valore di formato appunti valido per tutti i formati shell, diverso da CF_HDROP, che potrebbe essere incluso nell'oggetto dati. CF_HDROP è già un formato degli Appunti valido e non deve essere registrato.
  2. Per supportare un'operazione di trascinamento della selezione, la destinazione deve implementare un'interfaccia IDropTarget e registrare una finestra di destinazione. Per registrare una finestra di destinazione, la destinazione chiama RegisterDragDrop e passa nell'handle della finestra e nel puntatore dell'interfaccia IDropTarget .

Per i trasferimenti negli Appunti, la destinazione non riceve alcuna notifica che un oggetto dati è stato inserito negli Appunti. In genere, un'applicazione riceve una notifica che un oggetto si trova negli Appunti da un'azione dell'utente, ad esempio facendo clic sul pulsante Incolla sulla barra degli strumenti dell'applicazione. La destinazione recupera quindi il puntatore IDataObject dell'oggetto dati dagli Appunti chiamando OleGetClipboard. Per i trasferimenti di dati di trascinamento della selezione, il sistema usa l'interfaccia IDropTarget della destinazione per fornire informazioni sullo stato di avanzamento del trasferimento dei dati:

Per una discussione su come implementare questi metodi, vedere IDropTarget.

Quando i dati vengono eliminati, IDropTarget::D rop fornisce la destinazione con un puntatore all'interfaccia IDataObject dell'oggetto dati. La destinazione usa quindi questa interfaccia per estrarre i dati dall'oggetto dati.

Estrazione dei dati di Shell da un oggetto dati

Dopo aver eliminato o recuperato un oggetto dati dagli Appunti, la destinazione può estrarre i dati necessari. Il primo passaggio del processo di estrazione è in genere per enumerare i formati contenuti dall'oggetto dati:

  • Chiamare IDataObject::EnumFormatEtc. L'oggetto dati crea un oggetto di enumerazione OLE standard e restituisce un puntatore all'interfaccia IEnumFORMATETC .
  • Usare i metodi IEnumFORMATETC per enumerare i formati contenuti dall'oggetto dati. Questa operazione recupera in genere una struttura FORMATETC per ogni formato che l'oggetto contiene. Tuttavia, l'oggetto enumerazione restituisce normalmente solo una singola struttura FORMATETC per il formato CFSTR_FILECONTENTS , indipendentemente dal numero di formati contenuti dall'oggetto dati.
  • Selezionare uno o più formati da estrarre e archiviare le strutture FORMATETC .

Per recuperare un formato specifico, passare la struttura FORMATETC associata a IDataObject::GetData. Questo metodo restituisce una struttura STGMEDIUM che fornisce l'accesso ai dati. Per specificare un meccanismo di trasferimento dati specifico, impostare il valoretymed della struttura FORMATETC sul valore TYMED_XXX corrispondente. Per chiedere all'oggetto dati di selezionare un meccanismo di trasferimento dati, la destinazione imposta i valori TYMED_ XXX per ogni meccanismo di trasferimento dati che la destinazione può gestire. L'oggetto dati seleziona uno di questi meccanismi di trasferimento dati e restituisce la struttura STGMEDIUM appropriata.

Per la maggior parte dei formati, la destinazione può recuperare i dati passando la struttura FORMATETC ricevuta quando enumera i formati disponibili. Un'eccezione a questa regola è CFSTR_FILECONTENTS. Poiché un oggetto dati può contenere più istanze di questo formato, la struttura FORMATETC restituita dall'enumeratore potrebbe non corrispondere al formato specifico da estrarre. Oltre a specificare i membri cfFormat e tymed , è necessario impostare anche il membro lIndex sul valore dell'indice del file. Per altre informazioni, vedere la sezione Uso del formato CFSTR_FILECONTENTS per estrarre i dati da un file di gestione degli scenari di trasferimento dei dati shell

Il processo di estrazione dei dati dipende dal tipo di puntatore contenuto dalla struttura STGMEDIUM restituita. Se la struttura contiene un puntatore a un'interfaccia IStream o IStorage , usare i metodi di interfaccia per estrarre i dati. Il processo di estrazione dei dati da un oggetto memoria globale viene illustrato nella sezione successiva.

Estrazione di un oggetto memoria globale da un oggetto dati

Molti dei formati di dati shell sono sotto forma di un oggetto memoria globale. Usare la procedura seguente per estrarre un formato contenente un oggetto memoria globale da un oggetto dati e assegnarne i dati a una variabile locale:

  1. Creare una struttura FORMATETC . Impostare il membro cfFormat sul valore di formato degli Appunti appropriato e sul membro tymed su TYMED_HGLOBAL.

  2. Creare una struttura STGMEDIUM vuota.

  3. Chiamare IDataObject::GetData e passare puntatori alle strutture FORMATETC e STGMEDIUM .

    Quando IDataObject::GetData restituisce, la struttura STGMEDIUM conterrà un puntatore all'oggetto memoria globale che contiene i dati.

  4. Assegnare i dati a una variabile locale chiamando GlobalLock e passando il membro hGlobal della struttura STGMEDIUM .

  5. Chiamare GlobalUnlock per rilasciare il blocco nell'oggetto memoria globale.

  6. Chiamare ReleaseStgMedium per rilasciare l'oggetto memoria globale.

Nota

È necessario usare ReleaseStgMedium per rilasciare l'oggetto memoria globale, non GlobalFree.

 

Nell'esempio seguente viene illustrato come estrarre un valore DWORD archiviato come oggetto memoria globale da un oggetto dati. Il parametro pdtobj è un puntatore all'interfaccia IDataObject dell'oggetto dati, cf è il formato degli Appunti che identifica i dati desiderati e pdwOut viene usato per restituire il valore dei dati.

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;
}

Implementazione di IDropTarget

Il sistema usa l'interfaccia IDropTarget per comunicare con la destinazione mentre il cursore si trova sulla finestra di destinazione. Le risposte di destinazione vengono inoltrate all'origine tramite l'interfaccia IDropSource . A seconda della risposta, l'origine può modificare l'icona che rappresenta i dati. Se la destinazione di rilascio deve specificare l'icona dei dati, può farlo creando un oggetto helper trascinante.

Con le operazioni di trascinamento convenzionale, la destinazione informa l'oggetto dati dell'operazione impostando il parametro pdwEffect di IDropTarget::D rop al valore DROPEFFECT appropriato. Con gli oggetti dati shell, la destinazione potrebbe anche dover chiamare IDataObject::SetData. Per una discussione sul modo in cui le destinazioni devono rispondere per diversi scenari di trasferimento dei dati, vedere Gestione degli scenari di trasferimento dei dati di Shell.

Le sezioni seguenti illustrano brevemente come implementare i metodi IDropTarget::D ragEnter, IDropTarget::DragOver e IDropTarget::D rop . Per altre informazioni, vedere la documentazione di riferimento.

Metodo DragEnter

Il sistema chiama il metodo IDropTarget::D ragEnter quando il cursore entra nella finestra di destinazione. I relativi parametri forniscono la destinazione con la posizione del cursore, lo stato dei tasti di modifica della tastiera, ad esempio il tasto CTRL e un puntatore all'interfaccia IDataObject dell'oggetto dati. La destinazione è responsabile dell'uso di tale interfaccia per determinare se può accettare uno dei formati contenuti dall'oggetto dati. Se può, in genere lascia invariato il valore di pdwEffect . Se non può accettare dati dall'oggetto dati, imposta il parametro pdwEffect su DROPEFFECT_NONE. Il sistema passa il valore di questo parametro all'interfaccia IDropSource dell'oggetto dati per consentire la visualizzazione dell'immagine di trascinamento appropriata.

Le destinazioni non devono usare il metodo IDataObject::GetData per eseguire il rendering dei dati di Shell prima dell'eliminazione. Il rendering completo dei dati dell'oggetto per ogni occorrenza potrebbe causare lo stallo del cursore di trascinamento. Per evitare questo problema, alcuni oggetti Shell contengono un formato CFSTR_INDRAGLOOP . Estrazione di questo formato, le destinazioni possono controllare lo stato del ciclo di trascinamento evitando il rendering intensivo della memoria dei dati dell'oggetto. Il valore dei dati del formato è un DWORD impostato su un valore diverso da zero se l'oggetto dati si trova all'interno di un ciclo di trascinamento. Il valore dei dati del formato è impostato su zero se i dati sono stati eliminati.

Se la destinazione può accettare dati dall'oggetto dati, deve esaminare grfKeyState per determinare se sono stati premuti i tasti di modifica per modificare il comportamento di rilascio normale. Ad esempio, l'operazione predefinita è in genere uno spostamento, ma il tasto CTRL in genere indica un'operazione di copia.

Mentre il cursore si trova sulla finestra di destinazione, la destinazione può usare l'oggetto helper trascinamento per sostituire l'immagine di trascinamento dell'oggetto dati con il proprio. In tal caso, IDropTarget::D ragEnter deve chiamare IDropTargetHelper::D ragEnter per passare le informazioni contenute nei parametri DragEnter all'oggetto helper drag-and-drop.

Metodo DragOver

Quando il cursore si sposta all'interno della finestra di destinazione, il sistema chiama periodicamente il metodo IDropTarget::D ragOver . I relativi parametri forniscono la destinazione con la posizione del cursore e lo stato dei tasti di modifica della tastiera, ad esempio il tasto CTRL. IDropTarget::D ragOver ha molte stesse responsabilità di IDropTarget::D ragEnter e le implementazioni sono in genere molto simili.

Se la destinazione usa l'oggetto helper drag-and-drop, IDropTarget::D ragOver deve chiamare IDropTargetHelper::D ragOver per inoltrare le informazioni contenute nei parametri DragOver all'oggetto helper drag-and-drop.

Drop, metodo

Il sistema chiama il metodo IDropTarget::D rop per notificare alla destinazione che l'utente ha eliminato i dati, in genere rilasciando il pulsante del mouse. IDropTarget::D rop ha gli stessi parametri di IDropTarget::D ragEnter. La destinazione risponde normalmente estraendo uno o più formati dall'oggetto dati. Al termine, la destinazione deve impostare il parametro pdwEffect su un valore DROPEFFECT che indica il risultato dell'operazione. Per alcuni tipi di trasferimento dei dati shell, la destinazione deve anche chiamare IDataObject::SetData per passare un formato con informazioni aggiuntive sul risultato dell'operazione all'oggetto dati. Per una discussione dettagliata, vedere Gestione degli scenari di trasferimento dei dati shell.

Se la destinazione usa l'oggetto helper drag-and-drop, IDropTarget::D rop deve chiamare IDropTargetHelper::D rop per inoltrare le informazioni contenute nei parametri IDropTargetHelper::D ragOver all'oggetto helper drag-and-drop.

Uso dell'oggetto Helper Drag-and-Drop

L'oggetto helper trascinamento (CLSID_DragDropHelper) viene esportato da Shell per consentire alle destinazioni di specificare l'immagine di trascinamento mentre si trova nella finestra di destinazione. Per usare l'oggetto helper drag-and-drop, creare un oggetto server in-process chiamando CoCreateInstance con un identificatore di classe (CLSID) di CLSID_DragDropHelper. L'oggetto helper trascinamento espone due interfacce usate nel modo seguente:

  • L'interfaccia IDragSourceHelper consente alla destinazione di rilascio di specificare un'icona per rappresentare l'oggetto dati.
  • L'interfaccia IDropTargetHelper consente alla destinazione di rilascio di informare l'oggetto helper trascinante della posizione del cursore e di visualizzare o nascondere l'icona dei dati.

Uso dell'interfaccia IDragSourceHelper

L'interfaccia IDragSourceHelper viene esposta dall'oggetto helper drag-and-drop per consentire a una destinazione di rilascio di fornire l'immagine visualizzata mentre il cursore si trova sulla finestra di destinazione. IDragSourceHelper offre due modi alternativi per specificare la bitmap da usare come immagine di trascinamento:

  • Eliminare le destinazioni che dispongono di una finestra può registrare un messaggio della finestra di DI_GETDRAGIMAGE inizializzando l'oggetto helper drag-and-drop con IDragSourceHelper::InitializeFromWindow. Quando la destinazione riceve un messaggio di DI_GETDRAGIMAGE, il gestore inserisce le informazioni bitmap dell'immagine di trascinamento nella struttura SHDRAGIMAGE passata come valore lParam del messaggio.
  • Le destinazioni di rilascio senza finestra specificano una bitmap quando inizializzano l'oggetto helper trascinamento con IDragSourceHelper::InitializeFromBitmap.

Uso dell'interfaccia IDropTargetHelper

Questa interfaccia consente alla destinazione di rilascio di inviare una notifica all'oggetto helper trascinamento quando il cursore entra o lascia la destinazione. Mentre il cursore si trova sulla finestra di destinazione, IDropTargetHelper consente alla destinazione di assegnare l'oggetto helper di trascinamento e rilascio le informazioni ricevute dalla destinazione tramite l'interfaccia IDropTarget .

Quattro dei metodi IDropTargetHelper : IDropTargetHelper::D ragEnter, IDropTargetHelper::D ragLeave, IDropTargetHelper: :D ragOver e IDropTargetHelper::D rop, sono associati al metodo IDropTargetHelper dello stesso nome. Per usare l'oggetto helper drag-and-drop, ognuno dei metodi IDropTarget deve chiamare il metodo IDropTargetHelper corrispondente per inoltrare le informazioni all'oggetto helper drag-and-drop. Il quinto metodo IDropTargetHelper, IDropTargetHelper::Show, notifica l'oggetto helper trascinante per visualizzare o nascondere l'immagine di trascinamento. Questo metodo viene usato durante il trascinamento su una finestra di destinazione in modalità video a profondità colore bassa. Consente alla destinazione di nascondere l'immagine di trascinamento durante la pittura della finestra.