Gestione di scenari di trasferimento dei dati shell

Il documento Oggetto dati shell ha illustrato l'approccio generale usato per trasferire i dati di Shell con trascinamento o clipboard. Tuttavia, per implementare il trasferimento dei dati shell nell'applicazione, è necessario comprendere anche come applicare questi principi generali e tecniche all'ampia gamma di modi in cui è possibile trasferire i dati di Shell. Questo documento presenta scenari comuni di trasferimento dei dati shell e illustra come implementare ognuno nell'applicazione.

Nota

Anche se ognuno di questi scenari illustra un'operazione di trasferimento dati specifica, molti di essi si applicano a diversi scenari correlati. Ad esempio, la differenza primaria tra la maggior parte degli Appunti e i trasferimenti di trascinamento è il 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 degli scenari sono limitati a un tipo specifico di operazione. Per informazioni dettagliate, vedere il singolo scenario.

 

Linee guida generali

Ognuna delle sezioni seguenti illustra uno scenario di trasferimento dati abbastanza specifico. Tuttavia, i trasferimenti di dati sono spesso più complessi e potrebbero comportare aspetti di diversi scenari. In genere non si conosce, in anticipo, quale scenario sarà effettivamente necessario gestire. Ecco alcune linee guida generali da tenere presente.

Per le origini dati:

  • I formati degli Appunti 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 dall'origine. Enumerare l'oggetto dati e selezionare il primo che è possibile usare.
  • 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 contenga un formato che la destinazione di eliminazione 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'archiviazione dati sottostante. In genere, è consigliabile presentare i dati come interfaccia IStream . Questo meccanismo di trasferimento dei dati è più flessibile di un oggetto di 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 usando SHCreateDataObject.
  • Eliminare le destinazioni che vogliono fare riferimento agli elementi trascinati usando il modello di programmazione dell'elemento della shell può convertire un IDataObject in un oggetto IShellItemArray usando SHCreateShellItemArrayFromDataObject.
  • Usare cursori di feedback standard.
  • Supportare il trascinamento sinistro e destro.
  • Usare 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 e 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 ottimizzate o di eliminazione incollare durante lo spostamento di file. L'applicazione deve essere in grado di riconoscere queste operazioni e rispondere in modo appropriato.

Per le destinazioni dei dati:

  • I formati degli Appunti 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 conosce in anticipo dove proviene un oggetto dati, non si presuppone che sia presente un determinato formato. L'oggetto dati deve enumerare i formati in ordine di qualità, a partire dal meglio. Pertanto, per ottenere il formato più disponibile, le applicazioni enumerano normalmente 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 trascinamento creando un gestore di trascinamento.
  • Se l'applicazione accetterà i file esistenti, deve essere in grado di gestire il formato di CF_HDROP .
  • In generale, le applicazioni che accettano file devono gestire anche i formati CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/. Anche se i file dal 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/. Gli esempi includono cartelle Windows CE, cartelle FTP (File Transfer Protocol), cartelle Web e cartelle CAB. L'origine implementa normalmente un'interfaccia IStream per presentare i dati dalla relativa archiviazione come file.
  • Tenere presente che Shell potrebbe usare operazioni di spostamento ottimizzate o di eliminazione incollare durante lo spostamento di 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 dei 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 all'applicazione. L'applicazione può quindi estrarre il nome del file dall'oggetto dati e 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. Usare l'interfaccia IEnumFORMATETC dell'oggetto enumeratore per enumerare i formati contenuti dall'oggetto dati.

Nota

I due passaggi finali di questa procedura sono inclusi per la completezza. In genere non sono necessari per i trasferimenti di file semplici. Tutti gli oggetti dati usati per questo tipo di trasferimento dati devono contenere il formato CF_HDROP , che può essere usato per determinare i nomi dei file contenuti dall'oggetto. Tuttavia, per i 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 file da un oggetto dati si applica altrettanto bene ai trasferimenti di trascinamento.

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 il membro tymed su TYMED_HGLOBAL. Il membro dwAspect è in genere impostato su DVASPECT_CONTENT. Tuttavia, se è necessario avere il percorso del file in breve (8.3), impostare dwAspect su DVASPECT_SHORT.

    Quando restituisce IDataObject::GetData , il membro hGlobal della struttura STGMEDIUM punta a un oggetto memoria globale contenente 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 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. Chiamare 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 iniziando a trascinarli:

  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 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 all'interfaccia IStream richiede una quantità di memoria molto inferiore rispetto al caricamento dei dati in un oggetto di 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 necessario esaminare il contenuto di questo formato. Se vengono trasferiti più file, l'oggetto dati conterrà effettivamente più formati di 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 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 associati.
  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 CFSTR_FILECONTENTS del file. Poiché le dimensioni di un blocco di memoria globale non sono precise per byte, usare 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 relativo meccanismo di trasferimento 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 ideali per gli spostamenti ottimizzati perché la destinazione può gestire l'intera operazione usando l'API shell. Un esempio tipico è lo spostamento di file. Dopo 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

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 metodi IDropTarget , a indicare che uno spostamento è consentito.

  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 che è stato eseguito uno spostamento ottimizzato:

      • La destinazione imposta il valore pdwEffect ricevuto tramite il metodo IDropTarget::D rop su un valore diverso da DROPEFFECT_MOVE. In genere è impostato su DROPEFFECT_NONE o DROPEFFECT_COPY. Il valore verrà restituito all'origine da DoDragDrop.
      • La destinazione chiama anche il metodo IDataObject::SetData dell'oggetto dati e lo passa a un identificatore di formato CFSTR_PERFORMEDDROPEFFECT impostato su DROPEFFECT_NONE. Questa chiamata al metodo è necessaria perché alcune destinazioni di rilascio potrebbero non impostare correttamente il parametro pdwEffect di DoDragDrop . Il formato CFSTR_PERFORMEDDROPEFFECT è il modo affidabile per indicare che è stato eseguito 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:

      • La destinazione imposta il valore pdwEffect ricevuto tramite il metodo IDropTarget::D rop su DROPEFFECT_MOVE. Il valore verrà restituito all'origine da DoDragDrop.
      • La destinazione chiama anche il metodo IDataObject::SetData dell'oggetto dati e lo passa a un identificatore di formato CFSTR_PERFORMEDDROPEFFECT impostato su DROPEFFECT_MOVE. Questa chiamata al metodo è necessaria perché alcune destinazioni di rilascio potrebbero non impostare correttamente il parametro pdwEffect di DoDragDrop . Il formato CFSTR_PERFORMEDDROPEFFECT è il modo affidabile per indicare 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 relativa copia dei dati. Se l'operazione incolla non riesce, l'applicazione di origine ripristina l'aspetto originale dei dati selezionati.

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 le 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 l'eliminazione su incolla 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 usando OleSetClipboard.
  4. La destinazione recupera l'oggetto dati dagli Appunti usando OleGetClipboard.
  5. La destinazione estrae i dati CFSTR_PREFERREDDROPEFFECT . Se è impostato 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 dell'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 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 sul disco rigido, ma non come oggetti del file system normali. 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 dati archiviati. Anche se 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 file e cartelle normali. È responsabilità della cartella virtuale accettare i dati che contiene e presentarlo in modo appropriato alla shell. Questo requisito significa che le cartelle virtuali supportano normalmente 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 dati trasferiti da una cartella virtuale.
  • Sviluppatori le cui estensioni dello spazio dei nomi devono supportare correttamente il trasferimento dei dati.

Accettazione dei 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 possono, ad esempio, comprimere tutti i relativi oggetti in un singolo documento o database.

Quando un oggetto file system viene trasferito a un'applicazione, l'oggetto dati contiene in genere 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 CFSTR_FILEDESCRIPTOR CFSTR_FILECONTENTS/. Il formato CFSTR_FILECONTENTS presenta due vantaggi rispetto 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 di memoria globale vengono usati raramente per trasferire i dati da o verso oggetti virtuali perché i dati devono essere copiati in memoria nel suo insieme. Il trasferimento di un puntatore di interfaccia richiede quasi nessuna memoria ed è molto più efficiente. Con file di dimensioni molto grandi, un puntatore all'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 gestirei formatiCFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/, 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 è consigliabile supportare le funzionalità di trascinamento della selezione. Seguire le indicazioni 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 CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS . Questi due formati vengono in genere usati per trasferire oggetti da e verso le 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 in genere 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 che non sono più necessari. Purché il Cestino non sia stato svuotato, l'utente potrà successivamente recuperare il file e restituirlo al file system.

Per la maggior parte, il trasferimento degli 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 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 li rilascia sul desktop o In 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 il CLSID dell'oggetto e i dati CF_TEXT . Affinché shell crei un file di scarto contenente dati, l'interfaccia IDataObject dell'applicazione deve supportare il formato degli Appunti CF_EMBEDSOURCE. 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 in un altro contenitore e quindi di nuovo al documento originale. Ad esempio, un utente può trasferire un gruppo di celle da un foglio di calcolo al desktop, creando un file di scarto con i dati. Se l'utente trasferisce 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 di determinare il formato di dati contenuto nello scarto e di reinsemere i 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. Tuttavia, esistono diversi scenari in cui le applicazioni potrebbero dover avere file di scarto in formati diversi:

  • Per consentire il trasferimento degli scarti a contenitori non OLE, che non possono accettare formati di oggetti 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 della 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 descritto in modo più dettagliato nella sezione successiva.

Per aggiungere una cache con priorità o un formato con rendering ritardato, creare una sottochiave DataFormat sotto la 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 di #X, dove X rappresenta il numero di formato di un formato standard degli Appunti.

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 scrap 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 è un po' rischioso, è consigliabile usarlo con cautela. Non funzionerà se il server non è disponibile o nelle applicazioni non abilitate per OLE.

 

Trascinamento e rilascio 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 in genere l'elaborazione dell'interfaccia utente.
  2. Dopo la chiamata al metodo IDropTarget::D rop della destinazione, la destinazione estrae i dati dall'oggetto dati nel thread primario. Questa procedura blocca in genere 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 dei dati sincrono 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 dei dati sincrono funziona in modo ottimale. 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'interfacciaIDataObjectAsyncCapabilityIAsyncOperation/ è un'interfaccia facoltativa che può essere implementata da un oggetto dati. Offre alla destinazione di rilascio la possibilità di estrarre i 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 IAsyncOperation/IDataObjectAsyncCapability.
  2. Chiamare SetAsyncMode con fDoOpAsync impostato su VARIANT_TRUE per indicare che è supportata un'operazione asincrona.
  3. Dopo la 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 qualsiasi pulizia necessaria e continuare.
    • 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'interfacciaIDataObjectAsyncCapabilityIAsyncOperation/ per estrarre i dati in modo asincrono:

  1. Quando il sistema chiama IDropTarget::D rop, chiamare IDataObject::QueryInterface e richiedere un'interfacciaIDataObjectAsyncCapability IAsyncOperation/ (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 una normale operazione di trasferimento dei dati. DoDragDrop restituirà e sbloccherà l'origine di rilascio. Non chiamare IDataObject::SetData per indicare il risultato di un'operazione di spostamento o eliminazione ottimizzata. 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 è stato 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.