Condividi tramite


Gestione di scenari di trasferimento dei dati shell

Il documento Oggetto dati shell ha illustrato l'approccio generale usato per trasferire i dati della shell con trascinamento della selezione o appunti. Tuttavia, per implementare il trasferimento dei dati shell nell'applicazione, è necessario comprendere anche come applicare questi principi e tecniche generali alla varietà di modi in cui è possibile trasferire i dati shell. Questo documento presenta scenari comuni di trasferimento dei dati shell e illustra come implementare ogni scenario nell'applicazione.

Nota

Anche se ognuno di questi scenari illustra un'operazione di trasferimento dati specifica, molti di essi si applicano a un'ampia gamma di scenari correlati. Ad esempio, la differenza principale tra la maggior parte degli Appunti e i trasferimenti di trascinamento della selezione consiste nel modo in cui l'oggetto dati arriva alla destinazione. Una volta che la destinazione ha un puntatore all'interfaccia IDataObject dell'oggetto dati, le procedure per l'estrazione delle informazioni sono in gran parte uguali per entrambi i tipi di trasferimento dei dati. Tuttavia, alcuni scenari sono limitati a un tipo specifico di operazione. Per informazioni dettagliate, vedere il singolo scenario.

 

Linee guida generali

Ognuna delle sezioni seguenti illustra un singolo scenario di trasferimento dei dati piuttosto specifico. Tuttavia, i trasferimenti di dati sono spesso più complessi e possono comportare aspetti di diversi scenari. In genere non si sa, in anticipo, quale scenario sarà effettivamente necessario gestire. Ecco alcune linee guida generali da tenere presenti.

Per le origini dati:

  • I formati degli Appunti della shell, ad eccezione di CF_HDROP, non sono predefiniti. Ogni formato da usare deve essere registrato chiamando RegisterClipboardFormat.
  • I formati negli oggetti dati vengono forniti nell'ordine di preferenza dell'origine. Enumerare l'oggetto dati e selezionare il primo che è possibile utilizzare.
  • Includere tutti i formati che è possibile supportare. In genere non si sa dove verrà eliminato l'oggetto dati. Questa procedura migliora le probabilità che l'oggetto dati conterrà un formato che la destinazione di rilascio può accettare.
  • I file esistenti devono essere offerti con il formato CF_HDROP .
  • Offrire dati simili a file con formati di CFSTR_FILEDESCRIPTOR CFSTR_FILECONTENTS/. Questo approccio consente alla destinazione di creare un file da un oggetto dati senza dover conoscere nulla sull'archivio dati sottostante. Normalmente è consigliabile presentare i dati come interfaccia IStream. Questo meccanismo di trasferimento dei dati è più flessibile rispetto a un oggetto memoria globale e usa molto meno memoria.
  • Le origini di trascinamento devono offrire il formato CFSTR_SHELLIDLIST durante il trascinamento degli elementi della shell. Gli oggetti dati per gli elementi possono essere acquisiti tramite i metodi IShellFolder::GetUIObjectOf o IShellItem::BindToHandler. Le origini dati possono creare un'implementazione standard dell'oggetto dati che supporta il formato CFSTR_SHELLIDLIST tramite SHCreateDataObject.
  • Eliminare le destinazioni che desiderano ragionare sugli elementi trascinati usando il modello di programmazione degli elementi della shell può convertire un IDataObject in un oggetto IShellItemArray usando SHCreateShellItemArrayFromDataObject.
  • Usare cursori di feedback standard.
  • Supportare il trascinamento sinistro e destro.
  • Utilizzare l'oggetto dati stesso da un oggetto incorporato. Questo approccio consente all'applicazione di recuperare eventuali formati aggiuntivi che l'oggetto dati deve offrire ed evitare di creare un livello aggiuntivo di contenimento. Ad esempio, un oggetto incorporato dal server A viene trascinato dal server/contenitore B ed eliminato nel contenitore C. C deve creare un oggetto incorporato del server A, non un oggetto incorporato del server B contenente un oggetto incorporato del server A.
  • Tenere presente che shell potrebbe usare operazioni di spostamento o eliminazione ottimizzate durante lo spostamento dei file. L'applicazione deve essere in grado di riconoscere queste operazioni e rispondere in modo appropriato.

Per le destinazioni dati:

  • I formati degli Appunti della shell, ad eccezione di CF_HDROP, non sono predefiniti. Ogni formato da usare deve essere registrato chiamando RegisterClipboardFormat.
  • Implementare e registrare una destinazione ole drop. Evitare di usare destinazioni Windows 3.1 o il messaggio di WM_DROPFILES , se possibile.
  • I formati contenuti da un oggetto dati variano a seconda della provenienza dell'oggetto. Poiché in genere non si sa in anticipo da dove proviene un oggetto dati, non presupporre che sia presente un particolare formato. L'oggetto dati deve enumerare i formati in ordine di qualità, a partire dal modo migliore. Pertanto, per ottenere il formato migliore disponibile, le applicazioni in genere enumerano i formati disponibili e usano il primo formato nell'enumerazione che possono supportare.
  • Supportare il trascinamento destro del mouse. È possibile personalizzare il menu di scelta rapida del trascinamento creando un gestore di trascinamento della selezione.
  • Se l'applicazione accetterà file esistenti, deve essere in grado di gestire il formato CF_HDROP .
  • In generale, le applicazioni che accettano file devono gestire anche i formati CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR. Mentre i file del file system hanno il formato CF_HDROP , i file provenienti da provider come le estensioni dello spazio dei nomi usano in genere CFSTR_FILECONTENTS/CFSTR_FILEDESCRIPTOR. Alcuni esempi includono cartelle di Windows CE, cartelle FTP (File Transfer Protocol), cartelle Web e cartelle CAB. L'origine implementa in genere un'interfaccia IStream per presentare i dati dalla risorsa di archiviazione come file.
  • Tenere presente che shell potrebbe usare operazioni di spostamento o eliminazione ottimizzate durante lo spostamento dei file. L'applicazione deve essere in grado di riconoscere queste operazioni e rispondere in modo appropriato.

Copia di nomi di file dagli Appunti in un'applicazione

Scenario: un utente seleziona uno o più file in Esplora risorse e li copia negli Appunti. L'applicazione estrae i nomi di file e li incolla nel documento.

Questo scenario può essere usato, ad esempio, per consentire a un utente di creare un collegamento HTML tagliando e incollando il file nell'applicazione. L'applicazione può quindi estrarre il nome del file dall'oggetto dati ed elaborarlo per creare un tag di ancoraggio.

Quando un utente seleziona un file in Esplora risorse e lo copia negli Appunti, shell crea un oggetto dati. Chiama quindi OleSetClipboard per posizionare un puntatore all'interfaccia IDataObject dell'oggetto dati negli Appunti.

Quando l'utente seleziona il comando Incolla dal menu o dalla barra degli strumenti dell'applicazione:

  1. Chiamare OleGetClipboard per recuperare l'interfaccia IDataObject dell'oggetto dati.
  2. Chiamare IDataObject::EnumFormatEtc per richiedere un oggetto enumeratore.
  3. Utilizzare l'interfaccia IEnumFORMATETC dell'oggetto enumeratore per enumerare i formati contenuti nell'oggetto dati.

Nota

I due passaggi finali di questa procedura sono inclusi per completezza. In genere non sono necessari per i trasferimenti di file semplici. Tutti gli oggetti dati utilizzati per questo tipo di trasferimento dati devono contenere il formato CF_HDROP , che può essere utilizzato per determinare i nomi dei file contenuti dall'oggetto . Tuttavia, per trasferimenti di dati più generali, è necessario enumerare i formati e selezionare quello migliore che l'applicazione può gestire.

 

Estrazione dei nomi di file dall'oggetto dati

Il passaggio successivo consiste nell'estrarre uno o più nomi di file dall'oggetto dati e incollarli nell'applicazione. Si noti che la procedura descritta in questa sezione per estrarre un nome di file da un oggetto dati si applica altrettanto bene ai trasferimenti di trascinamento della selezione.

Il modo più semplice per recuperare i nomi di file da un oggetto dati è il formato CF_HDROP :

  1. Chiamare IDataObject::GetData. Impostare il membro cfFormat della struttura FORMATETC su CF_HDROP e sul membro tymed su TYMED_HGLOBAL. Il membro dwAspect viene in genere impostato su DVASPECT_CONTENT. Tuttavia, se è necessario avere il percorso del file in formato breve (8.3), impostare dwAspect su DVASPECT_SHORT.

    Quando restituisce IDataObject::GetData , il membro hGlobal della struttura STGMEDIUM punta a un oggetto memoria globale che contiene i dati.

  2. Creare una variabile HDROP e impostarla sul membro hGlobal della struttura STGMEDIUM . La variabile HDROP è ora un handle per una struttura DROPFILES seguita da una stringa con terminazione Null doppia contenente i percorsi di file completi dei file copiati.

  3. Determinare il numero di percorsi di file presenti nell'elenco chiamando DragQueryFile con il parametro iFile impostato su 0xFFFFFFFF. La funzione restituisce il numero di percorsi di file nell'elenco. L'indice in base zero del percorso del file in questo elenco viene usato nel passaggio successivo per identificare un percorso specifico.

  4. Estrarre i percorsi di file dall'oggetto memoria globale chiamando DragQueryFile una volta per ogni file, con iFile impostato sull'indice del file.

  5. Elaborare i percorsi dei file in base alle esigenze e incollarli nell'applicazione.

  6. Chiamare ReleaseStgMedium e passare il puntatore alla struttura STGMEDIUM passata a IDataObject::GetData nel passaggio 1. Dopo aver rilasciato la struttura, il valore HDROP creato nel passaggio 2 non è più valido e non deve essere usato.

Copia del contenuto di un file eliminato in un'applicazione

Scenario: un utente trascina uno o più file da Esplora risorse e li rilascia nella finestra dell'applicazione. L'applicazione estrae il contenuto del file (s) e lo incolla nell'applicazione.

Questo scenario usa il trascinamento della selezione per trasferire i file da Esplora risorse all'applicazione. Prima dell'operazione, l'applicazione deve:

  1. Chiama RegisterClipboardFormat per registrare i formati degli Appunti della shell necessari.
  2. Chiama RegisterDragDrop per registrare una finestra di destinazione e l'interfaccia IDropTarget dell'applicazione.

Dopo che l'utente avvia l'operazione selezionando uno o più file e avviando il trascinamento:

  1. Esplora risorse crea un oggetto dati e carica i formati supportati.
  2. Esplora risorse chiama DoDragDrop per avviare il ciclo di trascinamento.
  3. Quando l'immagine di trascinamento raggiunge la finestra di destinazione, il sistema invia una notifica chiamando IDropTarget::D ragEnter.
  4. Per determinare il contenuto dell'oggetto dati, chiamare il metodo IDataObject::EnumFormatEtc dell'oggetto dati. Utilizzare l'oggetto enumeratore restituito dal metodo per enumerare i formati contenuti nell'oggetto dati. Se l'applicazione non vuole accettare uno di questi formati, restituire DROPEFFECT_NONE. Ai fini di questo scenario, l'applicazione deve ignorare tutti gli oggetti dati che non contengono formati usati per trasferire file, ad esempio CF_HDROP.
  5. Quando l'utente elimina i dati, il sistema chiama IDropTarget::D rop.
  6. Usare l'interfaccia IDataObject per estrarre il contenuto dei file.

Esistono diversi modi per estrarre il contenuto di un oggetto Shell da un oggetto dati. In generale, usare l'ordine seguente:

  • Se il file contiene un formato CF_TEXT , i dati sono testo ANSI. È possibile usare il formato CF_TEXT per estrarre i dati anziché aprire il file stesso.
  • Se il file contiene un oggetto OLE collegato o incorporato, l'oggetto dati contiene un formato CF_EMBEDDEDOBJECT. Usare tecniche OLE standard per estrarre i dati. I file scrap contengono sempre un formato CF_EMBEDDEDOBJECT.
  • Se l'oggetto Shell proviene dal file system, l'oggetto dati contiene un formato CF_HDROP con i nomi dei file. Estrarre il nome del file da CF_HDROP e chiamare OleCreateFromFile per creare un nuovo oggetto collegato o incorporato. Per informazioni su come recuperare un nome di file da un formato CF_HDROP , vedere Copia di nomi di file dagli Appunti in un'applicazione.
  • Se l'oggetto dati contiene un formato CFSTR_FILEDESCRIPTOR, è possibile estrarre il contenuto di un file dal formato CFSTR_FILECONTENTS del file. Per una descrizione di questa procedura, vedere Uso del formato CFSTR_FILECONTENTS per estrarre dati da un file.
  • Prima di Shell versione 4.71, un'applicazione indica che stava trasferendo un tipo di file di collegamento impostando FD_LINKUI nel membro dwFlags della struttura FILEDESCRIPTOR . Per le versioni successive della shell, il modo preferito per indicare che i collegamenti vengono trasferiti consiste nell'usare il formato CFSTR_PREFERREDDROPEFFECT impostato su DROPEFFECT_LINK. Questo approccio è molto più efficiente rispetto all'estrazione della struttura FILEDESCRIPTOR solo per controllare un flag.

Se il processo di estrazione dei dati sarà lungo, è possibile eseguire l'operazione in modo asincrono in un thread in background. Il thread primario può quindi procedere senza ritardi non necessari. Per informazioni su come gestire l'estrazione asincrona dei dati, vedere Trascinamento e eliminazione di oggetti shell in modo asincrono.

Utilizzo del formato CFSTR_FILECONTENTS per estrarre dati da un file

Il formato CFSTR_FILECONTENTS offre un modo molto flessibile e potente per trasferire il contenuto di un file. Non è nemmeno necessario che i dati vengano archiviati come un singolo file. Tutto ciò che è necessario per questo formato è che l'oggetto dati presenta i dati alla destinazione come se fosse un file. Ad esempio, i dati effettivi potrebbero essere una sezione di un documento di testo o un blocco di dati estratti da un database. La destinazione può trattare i dati come file e non deve conoscere nulla sul meccanismo di archiviazione sottostante.

Le estensioni dello spazio dei nomi usano in genere CFSTR_FILECONTENTS per trasferire i dati perché questo formato non presuppone alcun meccanismo di archiviazione specifico. Un'estensione dello spazio dei nomi può usare qualsiasi meccanismo di archiviazione utile e usare questo formato per presentare gli oggetti alle applicazioni come se fossero file.

Il meccanismo di trasferimento dei dati per CFSTR_FILECONTENTS è in genere TYMED_ISTREAM. Il trasferimento di un puntatore di interfaccia IStream richiede una quantità di memoria molto inferiore rispetto al caricamento dei dati in un oggetto memoria globale e IStream è un modo più semplice per rappresentare i dati rispetto a IStorage.

Un formato CFSTR_FILECONTENTS è sempre accompagnato da un formato CFSTR_FILEDESCRIPTOR . Prima di tutto è necessario esaminare il contenuto di questo formato. Se vengono trasferiti più file, l'oggetto dati conterrà effettivamente più formati CFSTR_FILECONTENTS , uno per ogni file. Il formato CFSTR_FILEDESCRIPTOR contiene il nome e gli attributi di ogni file e fornisce un valore di indice per ogni file necessario per estrarre il formato di CFSTR_FILECONTENTS di un determinato file.

Per estrarre un formato CFSTR_FILECONTENTS :

  1. Estrarre il formato CFSTR_FILEDESCRIPTOR come valore di TYMED_HGLOBAL .
  2. Il membro hGlobal della struttura STGMEDIUM restituita punta a un oggetto memoria globale. Bloccare l'oggetto passando il valore hGlobal a GlobalLock.
  3. Eseguire il cast del puntatore restituito da GlobalLock a un puntatore FILEGROUPDESCRIPTOR. Punta a una struttura FILEGROUPDESCRIPTOR seguita da una o più strutture FILEDESCRIPTOR. Ogni struttura FILEDESCRIPTOR contiene una descrizione di un file contenuto in uno dei formati di CFSTR_FILECONTENTS adiacente.
  4. Esaminare le strutture FILEDESCRIPTOR per determinare quale corrisponde al file da estrarre. L'indice in base zero della struttura FILEDESCRIPTOR viene usato per identificare il formato di CFSTR_FILECONTENTS del file. Poiché le dimensioni di un blocco di memoria globale non sono precise per byte, utilizzare i membri nFileSizeLow e nFileSizeHigh della struttura per determinare il numero di byte che rappresentano il file nell'oggetto memoria globale.
  5. Chiamare IDataObject::GetData con il membro cfFormat della struttura FORMATETC impostato sul valore CFSTR_FILECONTENTS e sul membro lIndex impostato sull'indice determinato nel passaggio precedente. Il membro tymed è in genere impostato su TYMED_HGLOBAL | TYMED_ISTREAM | TYMED_ISTORAGE. L'oggetto dati può quindi scegliere il meccanismo di trasferimento dei dati preferito.
  6. La struttura STGMEDIUM restituita da IDataObject::GetData conterrà un puntatore ai dati del file. Esaminare il membro tymed della struttura per determinare il meccanismo di trasferimento dei dati.
  7. Se tymed è impostato su TYMED_ISTREAM o TYMED_ISTORAGE, usare l'interfaccia per estrarre i dati. Se tymed è impostato su TYMED_HGLOBAL, i dati sono contenuti in un oggetto memoria globale. Per informazioni su come estrarre dati da un oggetto memoria globale, vedere la sezione Estrazione di un oggetto memoria globale da un oggetto dati di Shell Data Object.
  8. Chiamare GlobalLock per sbloccare l'oggetto memoria globale bloccato nel passaggio 2.

Gestione delle operazioni di spostamento ottimizzate

Scenario: un file viene spostato dal file system a un'estensione dello spazio dei nomi usando uno spostamento ottimizzato.

In un'operazione di spostamento convenzionale, la destinazione crea una copia dei dati e l'origine elimina l'originale. Questa procedura può risultare inefficiente perché richiede due copie dei dati. Con oggetti di grandi dimensioni, ad esempio i database, un'operazione di spostamento convenzionale potrebbe anche non essere pratica.

Con uno spostamento ottimizzato, la destinazione usa la comprensione della modalità di archiviazione dei dati per gestire l'intera operazione di spostamento. Non è mai presente una seconda copia dei dati e non è necessario che l'origine elimini i dati originali. I dati della shell sono particolarmente adatti agli spostamenti ottimizzati perché la destinazione può gestire l'intera operazione usando l'API Shell. Un esempio tipico è lo spostamento di file. Una volta che la destinazione ha il percorso di un file da spostare, può usare SHFileOperation per spostarlo. Non è necessario che l'origine elimini il file originale.

Nota

La shell usa in genere uno spostamento ottimizzato per spostare i file. Per gestire correttamente il trasferimento dei dati della shell, l'applicazione deve essere in grado di rilevare e gestire uno spostamento ottimizzato.

 

Gli spostamenti ottimizzati vengono gestiti nel modo seguente:

  1. L'origine chiama DoDragDrop con il parametro dwEffect impostato su DROPEFFECT_MOVE per indicare che gli oggetti di origine possono essere spostati.

  2. La destinazione riceve il valore DROPEFFECT_MOVE tramite uno dei relativi metodi IDropTarget , a indicare che è consentito uno spostamento.

  3. La destinazione copia l'oggetto (spostamento non ottimizzato) o sposta l'oggetto (spostamento ottimizzato).

  4. La destinazione indica quindi all'origine se deve eliminare i dati originali.

    Uno spostamento ottimizzato è l'operazione predefinita, con i dati eliminati dalla destinazione. Per informare l'origine dell'esecuzione di uno spostamento ottimizzato:

    Se la destinazione ha eseguito uno spostamento non ottimizzato, i dati devono essere eliminati dall'origine. Per informare l'origine che è stato eseguito uno spostamento non ottimizzato:

  5. L'origine esamina i due valori che possono essere restituiti dalla destinazione. Se entrambi sono impostati su DROPEFFECT_MOVE, completa lo spostamento non ottimizzato eliminando i dati originali. In caso contrario, la destinazione ha eseguito uno spostamento ottimizzato e i dati originali sono stati eliminati.

Gestione delle operazioni di eliminazione su incolla

Scenario: uno o più file vengono tagliati da una cartella in Esplora risorse e incollati in un'estensione dello spazio dei nomi. Esplora risorse lascia i file evidenziati fino a quando non riceve commenti e suggerimenti sul risultato dell'operazione incolla.

Tradizionalmente, quando un utente taglia i dati scompare immediatamente dalla visualizzazione. Questo potrebbe non essere efficiente e può causare problemi di usabilità se l'utente si preoccupa di ciò che è successo ai dati. Un approccio alternativo consiste nell'usare un'operazione delete-on-paste.

Con un'operazione di eliminazione su incolla, i dati selezionati non vengono rimossi immediatamente dalla visualizzazione. Al contrario, l'applicazione di origine lo contrassegna come selezionato, ad esempio modificando il tipo di carattere o il colore di sfondo. Dopo che l'applicazione di destinazione ha incollato i dati, notifica all'origine il risultato dell'operazione. Se la destinazione ha eseguito uno spostamento ottimizzato, l'origine può semplicemente aggiornarne la visualizzazione. Se la destinazione ha eseguito uno spostamento normale, l'origine deve anche eliminare la copia dei dati. Se l'operazione incolla ha esito negativo, l'applicazione di origine ripristina i dati selezionati nell'aspetto originale.

Nota

La shell usa in genere delete-on-paste quando viene usata un'operazione taglia/incolla per spostare i file. Le operazioni delete-on-paste con oggetti Shell usano in genere uno spostamento ottimizzato per spostare i file. Per gestire correttamente il trasferimento dei dati della shell, l'applicazione deve essere in grado di rilevare e gestire operazioni di eliminazione su incolla.

 

Il requisito essenziale per l'eliminazione su incolla è che la destinazione deve segnalare il risultato dell'operazione all'origine. Tuttavia, le tecniche standard degli Appunti non possono essere usate per implementare delete-on-paste perché non consentono alla destinazione di comunicare con l'origine. L'applicazione di destinazione usa invece il metodo IDataObject::SetData dell'oggetto dati per segnalare il risultato all'oggetto dati. L'oggetto dati può quindi comunicare con l'origine tramite un'interfaccia privata.

La procedura di base per un'operazione delete-on-paste è la seguente:

  1. L'origine contrassegna la visualizzazione dello schermo dei dati selezionati.
  2. L'origine crea un oggetto dati. Indica un'operazione di taglio aggiungendo il formato CFSTR_PREFERREDDROPEFFECT con un valore di dati di DROPEFFECT_MOVE.
  3. L'origine inserisce l'oggetto dati negli Appunti utilizzando OleSetClipboard.
  4. La destinazione recupera l'oggetto dati dagli Appunti usando OleGetClipboard.
  5. La destinazione estrae i dati CFSTR_PREFERREDDROPEFFECT . Se è impostata solo su DROPEFFECT_MOVE, la destinazione può eseguire uno spostamento ottimizzato o semplicemente copiare i dati.
  6. Se la destinazione non esegue uno spostamento ottimizzato, chiama il metodo IDataObject::SetData con il formato CFSTR_PERFORMEDDROPEFFECT impostato su DROPEFFECT_MOVE.
  7. Al termine dell'operazione incolla, la destinazione chiama il metodo IDataObject::SetData con il formato CFSTR_PASTESUCCEEDED impostato su DROPEFFECT_MOVE.
  8. Quando il metodo IDataObject::SetData di origine viene chiamato con il formato CFSTR_PASTESUCCEEDED impostato su DROPEFFECT_MOVE, deve verificare se ha ricevuto anche il formato CFSTR_PERFORMEDDROPEFFECT impostato su DROPEFFECT_MOVE. Se entrambi i formati vengono inviati dalla destinazione, l'origine dovrà eliminare i dati. Se viene ricevuto solo il formato CFSTR_PASTESUCCEEDED , l'origine può semplicemente rimuovere i dati dalla relativa visualizzazione. Se il trasferimento non riesce, l'origine aggiorna la visualizzazione all'aspetto originale.

Trasferimento di dati da e verso cartelle virtuali

Scenario: un utente trascina un oggetto da o lo rilascia in una cartella virtuale.

Le cartelle virtuali contengono oggetti che in genere non fanno parte del file system. Alcune cartelle virtuali, ad esempio il Cestino, possono rappresentare i dati archiviati nel disco rigido, ma non come oggetti normali del file system. Alcuni possono rappresentare dati archiviati in un sistema remoto, ad esempio un PC palmare o un sito FTP. Altri, ad esempio la cartella Stampanti, contengono oggetti che non rappresentano affatto i dati archiviati. Mentre alcune cartelle virtuali fanno parte del sistema, gli sviluppatori possono anche creare e installare cartelle virtuali personalizzate implementando un'estensione dello spazio dei nomi.

Indipendentemente dal tipo di dati o dalla modalità di archiviazione, la cartella e gli oggetti file contenuti in una cartella virtuale vengono presentati dalla shell come se fossero normali file e cartelle. È responsabilità della cartella virtuale accettare i dati che contiene e presentarli in modo appropriato alla shell. Questo requisito significa che le cartelle virtuali supportano in genere trasferimenti di dati di trascinamento della selezione e appunti.

Esistono quindi due gruppi di sviluppatori che devono preoccuparsi del trasferimento dei dati da e verso cartelle virtuali:

  • Sviluppatori le cui applicazioni devono accettare i dati trasferiti da una cartella virtuale.
  • Sviluppatori le cui estensioni dello spazio dei nomi devono supportare correttamente il trasferimento dei dati.

Accettazione di dati da una cartella virtuale

Le cartelle virtuali possono rappresentare praticamente qualsiasi tipo di dati e possono archiviare tali dati in qualsiasi modo scelto. Alcune cartelle virtuali potrebbero effettivamente contenere file e cartelle normali del file system. Altri potrebbero, ad esempio, comprimere tutti gli oggetti in un singolo documento o database.

Quando un oggetto file system viene trasferito a un'applicazione, l'oggetto dati normalmente contiene un formato CF_HDROP con il percorso completo dell'oggetto. L'applicazione può estrarre questa stringa e usare le normali funzioni del file system per aprire il file ed estrarre i dati. Tuttavia, poiché le cartelle virtuali in genere non contengono oggetti normali del file system, in genere non usano CF_HDROP.

Invece di CF_HDROP, i dati vengono in genere trasferiti da cartelle virtuali con i formati di CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/. Il formato CFSTR_FILECONTENTS presenta due vantaggi rispetto a CF_HDROP:

  • Non si presuppone alcun metodo specifico di archiviazione dei dati.
  • Il formato è più flessibile. Supporta tre meccanismi di trasferimento dei dati: un oggetto memoria globale, un'interfaccia IStream o un'interfaccia IStorage.

Gli oggetti memoria globale vengono usati raramente per trasferire dati da o verso oggetti virtuali perché i dati devono essere copiati in memoria nell'intero oggetto. Il trasferimento di un puntatore di interfaccia richiede quasi nessuna memoria ed è molto più efficiente. Con file molto grandi, un puntatore di interfaccia potrebbe essere l'unico meccanismo pratico di trasferimento dei dati. In genere, i dati sono rappresentati da un puntatore IStream, perché tale interfaccia è leggermente più flessibile di IStorage. La destinazione estrae il puntatore dall'oggetto dati e usa i metodi di interfaccia per estrarre i dati.

Per altre informazioni su come gestire i formati CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS, vedere Uso del formato CFSTR_FILECONTENTS per estrarre dati da un file.

Trasferimento di dati da e verso un'estensione NameSpace

Quando si implementa un'estensione dello spazio dei nomi, in genere si desidera supportare le funzionalità di trascinamento della selezione. Seguire le raccomandazioni per eliminare origini e destinazioni descritte in Linee guida generali. In particolare, un'estensione dello spazio dei nomi deve:

  • Essere in grado di gestire i formati di CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/. Questi due formati vengono in genere usati per trasferire oggetti da e verso estensioni dello spazio dei nomi.
  • Essere in grado di gestire spostamenti ottimizzati. Shell prevede che gli oggetti Shell vengano spostati con uno spostamento ottimizzato.
  • Essere in grado di gestire un'operazione delete-on-paste . Shell usa delete-on-paste quando gli oggetti vengono spostati dalla shell con un'operazione taglia/incolla.
  • Essere in grado di gestire il trasferimento dei dati tramite un'interfaccia IStream o IStorage. Il trasferimento dei dati da o verso una cartella virtuale viene normalmente gestito trasferendo uno di questi due puntatori di interfaccia, in genere un puntatore IStream . La destinazione chiama quindi i metodi di interfaccia per estrarre i dati:
      • Come origine di rilascio, l'estensione dello spazio dei nomi deve estrarre i dati dall'archiviazione e passarli attraverso questa interfaccia alla destinazione.
      • Come destinazione di rilascio, un'estensione dello spazio dei nomi deve accettare dati da un'origine tramite questa interfaccia e archiviarla correttamente.

Eliminazione di file nel Cestino

Scenario: l'utente elimina un file nel Cestino. L'estensione dell'applicazione o dello spazio dei nomi elimina il file originale.

Il Cestino è una cartella virtuale usata come repository per i file non più necessari. Finché il Cestino non è stato svuotato, l'utente può successivamente recuperare il file e restituirlo al file system.

Per la maggior parte, il trasferimento di oggetti Shell nel Cestino funziona in modo analogo a qualsiasi altra cartella. Tuttavia, quando un utente elimina un file nel Cestino, l'origine deve eliminare l'originale, anche se il feedback dalla cartella indica un'operazione di copia. In genere, un'origine di rilascio non ha modo di conoscere la cartella in cui è stato eliminato l'oggetto dati. Tuttavia, per i sistemi Windows 2000 e versioni successive, quando un oggetto dati viene eliminato nel Cestino, shell chiamerà il metodo IDataObject::SetData dell'oggetto dati con un formato CFSTR_TARGETCLSID impostato sull'identificatore di classe del Cestino (CLSID) (CLSID_RecycleBin). Per gestire correttamente il caso del Cestino, l'oggetto dati deve essere in grado di riconoscere questo formato e comunicare le informazioni all'origine tramite un'interfaccia privata.

Nota

Quando viene chiamato IDataObject::SetData con un formato CFSTR_TARGETCLSID impostato su CLSID_RecycleBin, l'origine dati deve chiudere tutti gli handle aperti agli oggetti trasferiti prima di restituire dal metodo . In caso contrario, è possibile creare violazioni di condivisione.

 

Creazione e importazione di file di scarto

Scenario: un utente trascina alcuni dati dal file di dati di un'applicazione OLE e lo rilascia sul desktop o Esplora risorse.

Windows consente agli utenti di trascinare un oggetto dal file di dati di un'applicazione OLE e rilasciarlo sul desktop o su una cartella del file system. Questa operazione crea un file di scarto che contiene i dati o un collegamento ai dati. Il nome del file viene ricavato dal nome breve registrato per CLSID dell'oggetto e dai dati CF_TEXT . Affinché shell crei un file di scarto contenente dati, l'interfaccia IDataObject dell'applicazione deve supportare il formato CF_EMBEDSOURCE Appunti. Per creare un file contenente un collegamento, IDataObject deve supportare il formato CF_LINKSOURCE.

Esistono anche tre funzionalità facoltative che un'applicazione può implementare per supportare i file di scarto:

  • Supporto round trip
  • Formati di dati memorizzati nella cache
  • Rendering ritardato

Supporto round trip

Un round trip comporta il trasferimento di un oggetto dati a un altro contenitore e quindi al documento originale. Ad esempio, un utente potrebbe trasferire un gruppo di celle da un foglio di calcolo al desktop, creando un file di scarto con i dati. Se l'utente trasferisce quindi lo scarto al foglio di calcolo, i dati devono essere integrati nel documento come prima del trasferimento originale.

Quando shell crea il file di scarto, rappresenta i dati come oggetto di incorporamento. Quando lo scarto viene trasferito in un altro contenitore, viene trasferito come oggetto di incorporamento, anche se viene restituito al documento originale. L'applicazione è responsabile della determinazione del formato di dati contenuto nello scarto e del reinsezione dei dati nel formato nativo, se necessario.

Per stabilire il formato dell'oggetto incorporato, determinare il relativo CLSID recuperando il formato CF_OBJECTDESCRIPTOR dell'oggetto. Se CLSID indica un formato di dati appartenente all'applicazione, deve trasferire i dati nativi anziché chiamare OleCreateFromData.

Formati di dati memorizzati nella cache

Quando shell crea un file di scarto, controlla il Registro di sistema per l'elenco dei formati disponibili. Per impostazione predefinita, sono disponibili due formati: CF_EMBEDSOURCE e CF_LINKSOURCE. Esistono tuttavia diversi scenari in cui le applicazioni potrebbero dover disporre di file di scarto in formati diversi:

  • Per consentire il trasferimento degli scarti a contenitori non OLE, che non possono accettare formati di oggetto incorporati.
  • Per consentire alle suite di applicazioni di comunicare con un formato privato.
  • Per semplificare la gestione dei round trip.

Le applicazioni possono aggiungere formati allo scarto memorizzandoli nella cache nel Registro di sistema. Esistono due tipi di formati memorizzati nella cache:

  • Formati di cache con priorità. Per questi formati, i dati vengono copiati interamente nello scarto dall'oggetto dati.
  • Formati sottoposti a rendering ritardato. Per questi formati, l'oggetto dati non viene copiato nello scarto. Il rendering viene invece ritardato fino a quando una destinazione richiede i dati. Il rendering ritardato viene illustrato in modo più dettagliato nella sezione successiva.

Per aggiungere una cache con priorità o un formato con rendering ritardato, creare una sottochiave DataFormat nella chiave CLSID dell'applicazione che rappresenta l'origine dei dati. In tale sottochiave creare una sottochiave PriorityCacheFormats o DelayRenderFormats . Per ogni formato di cache con priorità o con rendering ritardato, creare una sottochiave numerata a partire da zero. Impostare il valore di questa chiave su una stringa con il nome registrato del formato o un valore #X, dove X rappresenta il numero di formato di un formato degli Appunti standard.

L'esempio seguente mostra i formati memorizzati nella cache per due applicazioni. L'applicazione MyProg1 ha il formato RTF come formato di cache prioritario e un formato privato "My Format" come formato con rendering ritardato. L'applicazione MyProg2 ha il formato CF_BITMAP (#8") come formato di cache con priorità.

HKEY_CLASSES_ROOT
   CLSID
      {GUID}
         (Default) = MyProg1
         DataFormats
            PriorityCacheFormats
               0
                  (Default) = Rich Text Format
            DelayRenderFormats
               0
                  (Default) = My Format
      {GUID}
         (Default) = MyProg2
         DataFormats
            PriorityCacheFormats
               0
                  (Default) = #8

È possibile aggiungere altri formati creando sottochiavi numerati aggiuntivi.

Rendering ritardato

Un formato di rendering ritardato consente a un'applicazione di creare un file di scarto, ma ritardare il rendering dei dati fino a quando non viene richiesto da una destinazione. L'interfaccia IDataObject di uno scarto offrirà i formati di rendering ritardati alla destinazione insieme ai dati nativi e memorizzati nella cache. Se la destinazione richiede un formato di rendering ritardato, shell eseguirà l'applicazione e fornirà i dati alla destinazione dall'oggetto attivo.

Nota

Poiché il rendering ritardato è piuttosto rischioso, è consigliabile usarlo con cautela. Non funzionerà se il server non è disponibile o nelle applicazioni non abilitate per OLE.

 

Trascinamento e eliminazione di oggetti shell in modo asincrono

Scenario: un utente trasferisce un blocco elevato di dati dall'origine alla destinazione. Per evitare di bloccare entrambe le applicazioni per un periodo di tempo significativo, la destinazione estrae i dati in modo asincrono.

In genere, il trascinamento della selezione è un'operazione sincrona. In breve:

  1. L'origine di rilascio chiama DoDragDrop e blocca il thread primario fino a quando la funzione non viene restituita. Il blocco del thread primario blocca normalmente l'elaborazione dell'interfaccia utente.
  2. Dopo aver chiamato il metodo IDropTarget::D rop della destinazione, la destinazione estrae i dati dall'oggetto dati nel thread primario. Questa procedura blocca normalmente l'elaborazione dell'interfaccia utente della destinazione per la durata del processo di estrazione.
  3. Dopo aver estratto i dati, la destinazione restituisce la chiamata IDropTarget::D rop, il sistema restituisce DoDragDrop e entrambi i thread possono continuare.

In breve, il trasferimento sincrono dei dati può bloccare i thread primari di entrambe le applicazioni per un periodo di tempo significativo. In particolare, entrambi i thread devono attendere mentre la destinazione estrae i dati. Per piccole quantità di dati, il tempo necessario per estrarre i dati è ridotto e il trasferimento sincrono dei dati funziona molto bene. Tuttavia, l'estrazione sincrona di grandi quantità di dati può causare ritardi lunghi e interferire con l'interfaccia utente di destinazione e di origine.

L'interfaccia IDataObjectAsyncCapability IAsyncOperation/è un'interfaccia facoltativa che può essere implementata da un oggetto dati. Offre alla destinazione di rilascio la possibilità di estrarre dati dall'oggetto dati in modo asincrono in un thread in background. Dopo che l'estrazione dei dati viene passata al thread in background, i thread primari di entrambe le applicazioni sono liberi di procedere.

Uso di IASyncOperation/IDataObjectAsyncCapability

Nota

L'interfaccia è stata originariamente denominata IAsyncOperation, ma in seguito è stata modificata in IDataObjectAsyncCapability. In caso contrario, le due interfacce sono identiche.

 

Lo scopo di IAsyncOperation/IDataObjectAsyncCapability è consentire all'origine di rilascio e alla destinazione di rilascio di negoziare se i dati possono essere estratti in modo asincrono. La procedura seguente illustra come l'origine di rilascio usa l'interfaccia :

  1. Creare un oggetto dati che espone IDataObjectAsyncCapability IDataObjectAsyncOperation/.
  2. Chiamare SetAsyncMode con fDoOpAsync impostato su VARIANT_TRUE per indicare che è supportata un'operazione asincrona.
  3. Al termine della restituzione di DoDragDrop, chiamare InOperation:
    • Se InOperation ha esito negativo o restituisce VARIANT_FALSE, è stato eseguito un normale trasferimento dei dati sincrono e il processo di estrazione dei dati è terminato. L'origine deve eseguire tutte le operazioni di pulizia necessarie e procedere.
    • Se InOperation restituisce VARIANT_TRUE, i dati vengono estratti in modo asincrono. Le operazioni di pulizia devono essere gestite da EndOperation.
  4. Rilasciare l'oggetto dati.
  5. Al termine del trasferimento asincrono dei dati, l'oggetto dati in genere invia una notifica all'origine tramite un'interfaccia privata.

La procedura seguente illustra come la destinazione di rilascio usa l'interfaccia IDataObjectAsyncCapability IAsyncOperation/per estrarre i dati in modo asincrono:

  1. Quando il sistema chiama IDropTarget::D rop, chiama IDataObject::QueryInterface e richiedi un'interfaccia IDataObjectAsyncCapability IDataObjectAsyncCapability/ (IID_IAsyncOperation/IID_IDataObjectAsyncCapability) dall'oggetto dati.
  2. Chiamare GetAsyncMode. Se il metodo restituisce VARIANT_TRUE, l'oggetto dati supporta l'estrazione asincrona dei dati.
  3. Creare un thread separato per gestire l'estrazione dei dati e chiamare StartOperation.
  4. Restituire la chiamata IDropTarget::D rop , come si farebbe per un'operazione di trasferimento dei dati normale. DoDragDrop restituirà e sbloccherà l'origine di rilascio. Non chiamare IDataObject::SetData per indicare il risultato di un'operazione di spostamento o eliminazione ottimizzata su incolla. Attendere il completamento dell'operazione.
  5. Estrarre i dati nel thread in background. Il thread primario della destinazione viene sbloccato e libero di procedere.
  6. Se il trasferimento dei dati è un'operazione di spostamento o eliminazione ottimizzata, chiamare IDataObject::SetData per indicare il risultato.
  7. Notificare all'oggetto dati che l'estrazione è stata completata chiamando EndOperation.