Cursos
Ruta de aprendizaje
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization
Este explorador ya no se admite.
Actualice a Microsoft Edge para aprovechar las características y actualizaciones de seguridad más recientes, y disponer de soporte técnico.
El documento Objeto de datos de Shell explicó el enfoque general que se usa para transferir datos de Shell con arrastrar y colocar o el Portapapeles. Sin embargo, para implementar la transferencia de datos de Shell en la aplicación, también debe comprender cómo aplicar estos principios y técnicas generales a la variedad de formas en que se pueden transferir datos de Shell. En este documento se presentan escenarios comunes de transferencia de datos de Shell y se describe cómo implementar cada uno de ellos en la aplicación.
Nota
Aunque cada uno de estos escenarios describe una operación de transferencia de datos específica, muchas de ellas se aplican a una variedad de escenarios relacionados. Por ejemplo, la diferencia principal entre la mayoría del Portapapeles y las transferencias de arrastrar y colocar es en cómo llega el objeto de datos al destino. Una vez que el destino tiene un puntero a la interfaz IDataObject del objeto de datos, los procedimientos para extraer información son en gran medida los mismos para ambos tipos de transferencia de datos. Sin embargo, algunos de los escenarios se limitan a un tipo específico de operación. Consulte el escenario individual para obtener más información.
Cada una de las secciones siguientes describe un único escenario de transferencia de datos bastante específico. Sin embargo, las transferencias de datos suelen ser más complejas y pueden implicar aspectos de varios escenarios. Normalmente no sabe, con antelación, qué escenario necesitará controlar. Estas son algunas directrices generales que debe tener en cuenta.
Para orígenes de datos:
Para destinos de datos:
Escenario: un usuario selecciona uno o varios archivos en el Explorador de Windows y los copia en el Portapapeles. La aplicación extrae los nombres de archivo y los pega en el documento.
Este escenario podría usarse, por ejemplo, para permitir que un usuario cree un vínculo HTML cortando y pegando el archivo en la aplicación. A continuación, la aplicación puede extraer el nombre de archivo del objeto de datos y procesarlo para crear una etiqueta de anclaje.
Cuando un usuario selecciona un archivo en el Explorador de Windows y lo copia en el Portapapeles, shell crea un objeto de datos. A continuación, llama a OleSetClipboard para colocar un puntero a la interfaz IDataObject del objeto de datos en el Portapapeles.
Cuando el usuario selecciona el comando Pegar en el menú o la barra de herramientas de la aplicación:
Nota
Los dos últimos pasos de este procedimiento se incluyen por integridad. Normalmente no son necesarios para transferencias de archivos simples. Todos los objetos de datos usados para este tipo de transferencia de datos deben contener el formato CF_HDROP , que se puede usar para determinar los nombres de los archivos contenidos por el objeto . Sin embargo, para transferencias de datos más generales, debe enumerar los formatos y seleccionar el mejor que pueda controlar la aplicación.
El siguiente paso consiste en extraer uno o varios nombres de archivo del objeto de datos y pegarlos en la aplicación. Tenga en cuenta que el procedimiento descrito en esta sección para extraer un nombre de archivo de un objeto de datos se aplica igualmente bien a las transferencias de arrastrar y colocar.
La manera más sencilla de recuperar nombres de archivo de un objeto de datos es el formato CF_HDROP :
Llame a IDataObject::GetData. Establezca el miembro cfFormat de la estructura FORMATETC en CF_HDROP y el miembro tymed en TYMED_HGLOBAL. El miembro dwAspect se establece normalmente en DVASPECT_CONTENT. Sin embargo, si necesita tener la ruta de acceso del archivo en formato corto (8.3), establezca dwAspect en DVASPECT_SHORT.
Cuando IDataObject::GetData devuelve, el miembro hGlobal de la estructura STGMEDIUM apunta a un objeto de memoria global que contiene los datos.
Cree una variable HDROP y establézcala en el miembro hGlobal de la estructura STGMEDIUM. La variable HDROP es ahora un identificador de una estructura DROPFILES seguida de una cadena terminada en null doble que contiene las rutas de acceso de archivo completas de los archivos copiados.
Determine cuántas rutas de acceso de archivo hay en la lista llamando a DragQueryFile con el parámetro iFile establecido en 0xFFFFFFFF. La función devuelve el número de rutas de acceso de archivo de la lista. El índice de base cero de la ruta de acceso del archivo en esta lista se usa en el paso siguiente para identificar una ruta de acceso determinada.
Extraiga las rutas de acceso de archivo del objeto de memoria global llamando a DragQueryFile una vez para cada archivo, con iFile establecido en el índice del archivo.
Procese las rutas de acceso de archivo según sea necesario y péguelas en la aplicación.
Llame a ReleaseStgMedium y pase el puntero a la estructura STGMEDIUM que pasó a IDataObject::GetData en el paso 1. Una vez que haya liberado la estructura, el valor HDROP que creó en el paso 2 ya no es válido y no debe usarse.
Escenario: un usuario arrastra uno o varios archivos desde el Explorador de Windows y los coloca en la ventana de la aplicación. La aplicación extrae el contenido del archivo (s) y lo pega en la aplicación.
En este escenario se usa arrastrar y colocar para transferir los archivos desde el Explorador de Windows a la aplicación. Antes de la operación, la aplicación debe:
Una vez que el usuario inicie la operación, seleccione uno o varios archivos y empiece a arrastrarlos:
Hay varias maneras diferentes de extraer el contenido de un objeto Shell de un objeto de datos. En general, use el orden siguiente:
Si el proceso de extracción de datos será largo, es posible que desee realizar la operación de forma asincrónica en un subproceso en segundo plano. El subproceso principal puede continuar sin retrasos innecesarios. Para obtener una explicación sobre cómo controlar la extracción asincrónica de datos, consulte Arrastrar y quitar objetos de Shell de forma asincrónica.
El formato CFSTR_FILECONTENTS proporciona una manera muy flexible y eficaz de transferir el contenido de un archivo. Ni siquiera es necesario que los datos se almacenen como un único archivo. Todo lo necesario para este formato es que el objeto de datos presenta los datos al destino como si fuera un archivo. Por ejemplo, los datos reales pueden ser una sección de un documento de texto o un bloque de datos extraídos de una base de datos. El destino puede tratar los datos como un archivo y no necesita saber nada sobre el mecanismo de almacenamiento subyacente.
Normalmente, las extensiones de espacio de nombres usan CFSTR_FILECONTENTS para transferir datos porque este formato no supone ningún mecanismo de almacenamiento determinado. Una extensión de espacio de nombres puede usar cualquier mecanismo de almacenamiento conveniente y usar este formato para presentar sus objetos a las aplicaciones como si fueran archivos.
Normalmente, el mecanismo de transferencia de datos para CFSTR_FILECONTENTS es TYMED_ISTREAM. La transferencia de un puntero de interfaz IStream requiere mucha menos memoria que cargar los datos en un objeto de memoria global y IStream es una manera más sencilla de representar datos que IStorage.
Un formato CFSTR_FILECONTENTS siempre va acompañado de un formato CFSTR_FILEDESCRIPTOR . Primero debe examinar el contenido de este formato. Si se transfiere más de un archivo, el objeto de datos contendrá realmente varios formatos de CFSTR_FILECONTENTS , uno para cada archivo. El formato CFSTR_FILEDESCRIPTOR contiene el nombre y los atributos de cada archivo y proporciona un valor de índice para cada archivo necesario para extraer el formato CFSTR_FILECONTENTS de un archivo determinado.
Para extraer un formato de CFSTR_FILECONTENTS :
Escenario: un archivo se mueve del sistema de archivos a una extensión de espacio de nombres mediante un movimiento optimizado.
En una operación de movimiento convencional, el destino realiza una copia de los datos y el origen elimina el original. Este procedimiento puede ser ineficaz porque requiere dos copias de los datos. Con objetos de gran tamaño como bases de datos, es posible que una operación de movimiento convencional no sea incluso práctica.
Con un movimiento optimizado, el destino usa su comprensión de cómo se almacenan los datos para controlar toda la operación de movimiento. Nunca hay una segunda copia de los datos y no es necesario que el origen elimine los datos originales. Los datos de Shell son adecuados para los movimientos optimizados, ya que el destino puede controlar toda la operación mediante la API de Shell. Un ejemplo típico es mover archivos. Una vez que el destino tiene la ruta de acceso de un archivo que se va a mover, puede usar SHFileOperation para moverlo. No es necesario que el origen elimine el archivo original.
Nota
El shell normalmente usa un movimiento optimizado para mover archivos. Para controlar correctamente la transferencia de datos de Shell, la aplicación debe ser capaz de detectar y controlar un movimiento optimizado.
Los movimientos optimizados se controlan de la siguiente manera:
El origen llama a DoDragDrop con el parámetro dwEffect establecido en DROPEFFECT_MOVE para indicar que los objetos de origen se pueden mover.
El destino recibe el valor de DROPEFFECT_MOVE a través de uno de sus métodos IDropTarget , lo que indica que se permite un movimiento.
El destino copia el objeto (movimiento no optimizado) o mueve el objeto (movimiento optimizado).
A continuación, el destino indica al origen si necesita eliminar los datos originales.
Un movimiento optimizado es la operación predeterminada, con los datos eliminados por el destino. Para informar al origen de que se realizó un movimiento optimizado:
Si el destino hizo un movimiento no optimizado, el origen debe eliminar los datos. Para informar al origen de que se realizó un movimiento no optimizado:
El origen inspecciona los dos valores que el destino puede devolver. Si ambos se establecen en DROPEFFECT_MOVE, completa el movimiento no optimizado eliminando los datos originales. De lo contrario, el destino hizo un movimiento optimizado y se eliminaron los datos originales.
Escenario: uno o varios archivos se cortan de una carpeta en el Explorador de Windows y se pegan en una extensión de espacio de nombres. El Explorador de Windows deja los archivos resaltados hasta que recibe comentarios sobre el resultado de la operación de pegado.
Tradicionalmente, cuando un usuario corta los datos, desaparece inmediatamente de la vista. Esto puede no ser eficaz y puede provocar problemas de facilidad de uso si el usuario se preocupa por lo que ha ocurrido con los datos. Un enfoque alternativo consiste en usar una operación de eliminación al pegar.
Con una operación de eliminación al pegar, los datos seleccionados no se quitan inmediatamente de la vista. En su lugar, la aplicación de origen la marca como seleccionada, quizás cambiando la fuente o el color de fondo. Una vez que la aplicación de destino haya pegado los datos, notifica al origen el resultado de la operación. Si el destino realizó un movimiento optimizado, el origen simplemente puede actualizar su presentación. Si el destino realizó un movimiento normal, el origen también debe eliminar su copia de los datos. Si se produce un error en el pegado, la aplicación de origen restaura los datos seleccionados a su apariencia original.
Nota
El shell usa normalmente delete-on-paste cuando se usa una operación de cortar y pegar para mover archivos. Las operaciones de eliminación al pegar con objetos shell normalmente usan un movimiento optimizado para mover los archivos. Para controlar correctamente la transferencia de datos de Shell, la aplicación debe ser capaz de detectar y controlar las operaciones de eliminación al pegar.
El requisito esencial para eliminar al pegar es que el destino debe notificar el resultado de la operación al origen. Sin embargo, las técnicas estándar del Portapapeles no se pueden usar para implementar la eliminación al pegar porque no proporcionan una manera de que el destino se comunique con el origen. En su lugar, la aplicación de destino usa el método IDataObject::SetData del objeto de datos para notificar el resultado al objeto de datos. Después, el objeto de datos puede comunicarse con el origen a través de una interfaz privada.
El procedimiento básico para una operación delete-on-paste es el siguiente:
Escenario: un usuario arrastra un objeto desde o lo coloca en una carpeta virtual.
Las carpetas virtuales contienen objetos que generalmente no forman parte del sistema de archivos. Algunas carpetas virtuales, como la Papelera de reciclaje, pueden representar datos almacenados en el disco duro, pero no como objetos normales del sistema de archivos. Algunos pueden representar datos almacenados que están en un sistema remoto, como un equipo portátil o un sitio FTP. Otros, como la carpeta Impresoras, contienen objetos que no representan datos almacenados en absoluto. Aunque algunas carpetas virtuales forman parte del sistema, los desarrolladores también pueden crear e instalar carpetas virtuales personalizadas mediante la implementación de una extensión de espacio de nombres.
Independientemente del tipo de datos o de cómo se almacene, el Shell presenta los objetos de carpeta y archivo que contiene una carpeta virtual como si fueran archivos y carpetas normales. Es responsabilidad de la carpeta virtual tomar los datos que contenga y presentarlos al Shell adecuadamente. Este requisito significa que las carpetas virtuales normalmente admiten transferencias de datos de arrastrar y colocar y Portapapeles.
Por lo tanto, hay dos grupos de desarrolladores que deben preocuparse por la transferencia de datos hacia y desde carpetas virtuales:
Las carpetas virtuales pueden representar prácticamente cualquier tipo de datos y pueden almacenar esos datos de cualquier manera que elijan. Algunas carpetas virtuales pueden contener realmente archivos y carpetas normales del sistema de archivos. Otros pueden, por ejemplo, empaquetar todos sus objetos en un único documento o base de datos.
Cuando un objeto de sistema de archivos se transfiere a una aplicación, el objeto de datos normalmente contiene un formato de CF_HDROP con la ruta de acceso completa del objeto. La aplicación puede extraer esta cadena y usar las funciones normales del sistema de archivos para abrir el archivo y extraer sus datos. Sin embargo, dado que las carpetas virtuales normalmente no contienen objetos normales del sistema de archivos, por lo general no usan CF_HDROP.
En lugar de CF_HDROP, los datos se transfieren normalmente desde carpetas virtuales con los formatos de CFSTR_FILECONTENTS CFSTR_FILEDESCRIPTOR/. El formato CFSTR_FILECONTENTS tiene dos ventajas sobre CF_HDROP:
Los objetos de memoria global rara vez se usan para transferir datos a objetos virtuales o desde ellos porque los datos deben copiarse en la memoria en su totalidad. La transferencia de un puntero de interfaz requiere casi ninguna memoria y es mucho más eficaz. Con archivos muy grandes, un puntero de interfaz podría ser el único mecanismo práctico de transferencia de datos. Normalmente, los datos se representan mediante un puntero IStream, ya que esa interfaz es algo más flexible que IStorage. El destino extrae el puntero del objeto de datos y usa los métodos de interfaz para extraer los datos.
Para obtener más información sobre cómo controlar los formatos de CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS, consulte Uso del formato CFSTR_FILECONTENTS para extraer datos de un archivo.
Al implementar una extensión de espacio de nombres, normalmente querrá admitir funcionalidades de arrastrar y colocar. Siga las recomendaciones para quitar orígenes y destinos descritos en Directrices generales. En concreto, una extensión de espacio de nombres debe:
Escenario: el usuario quita un archivo en la Papelera de reciclaje. La aplicación o la extensión de espacio de nombres elimina el archivo original.
La Papelera de reciclaje es una carpeta virtual que se usa como repositorio para los archivos que ya no son necesarios. Siempre que la Papelera de reciclaje no se haya vaciado, el usuario podrá recuperar el archivo más adelante y devolverlo al sistema de archivos.
En su mayor parte, transferir objetos Shell a la Papelera de reciclaje funciona de forma muy similar a cualquier otra carpeta. Sin embargo, cuando un usuario quita un archivo en la Papelera de reciclaje, el origen debe eliminar el original, incluso si los comentarios de la carpeta indican una operación de copia. Normalmente, un origen de eliminación no tiene forma de saber en qué carpeta se ha quitado su objeto de datos. Sin embargo, para los sistemas Windows 2000 y versiones posteriores, cuando se quita un objeto de datos en la Papelera de reciclaje, shell llamará al método IDataObject::SetData del objeto de datos con un formato de CFSTR_TARGETCLSID establecido en el identificador de clase de la Papelera de reciclaje (CLSID) (CLSID_RecycleBin). Para controlar correctamente el caso de la papelera de reciclaje, el objeto de datos debe ser capaz de reconocer este formato y comunicar la información al origen a través de una interfaz privada.
Nota
Cuando se llama a IDataObject::SetData con un formato CFSTR_TARGETCLSID establecido en CLSID_RecycleBin, el origen de datos debe cerrar los identificadores abiertos a los objetos que se transfieren antes de volver del método. De lo contrario, puede crear infracciones de uso compartido.
Escenario: un usuario arrastra algunos datos desde el archivo de datos de una aplicación OLE y lo coloca en el escritorio o en el Explorador de Windows.
Windows permite a los usuarios arrastrar un objeto desde el archivo de datos de una aplicación OLE y colocarlo en el escritorio o en una carpeta del sistema de archivos. Esta operación crea un archivo de extracción, que contiene los datos o un vínculo a los datos. El nombre de archivo se toma del nombre corto registrado para el CLSID del objeto y los datos CF_TEXT . Para que shell cree un archivo de extracción que contenga datos, la interfaz IDataObject de la aplicación debe admitir el formato CF_EMBEDSOURCE Portapapeles. Para crear un archivo que contenga un vínculo, IDataObject debe admitir el formato CF_LINKSOURCE.
También hay tres características opcionales que una aplicación puede implementar para admitir archivos de extracción:
Un recorrido de ida y vuelta implica transferir un objeto de datos a otro contenedor y volver al documento original. Por ejemplo, un usuario podría transferir un grupo de celdas de una hoja de cálculo al escritorio, creando un archivo de extracción con los datos. Si el usuario vuelve a transferir la extracción a la hoja de cálculo, los datos deben integrarse en el documento tal como estaba antes de la transferencia original.
Cuando shell crea el archivo de extracción, representa los datos como un objeto de inserción. Cuando la extracción se transfiere a otro contenedor, se transfiere como un objeto de inserción, incluso si se devuelve al documento original. La aplicación es responsable de determinar el formato de datos contenido en la extracción y devolver los datos a su formato nativo si es necesario.
Para establecer el formato del objeto incrustado, determine su CLSID recuperando el formato CF_OBJECTDESCRIPTOR del objeto. Si clSID indica un formato de datos que pertenece a la aplicación, debe transferir los datos nativos en lugar de llamar a OleCreateFromData.
Cuando shell crea un archivo de extracción, comprueba el registro para ver la lista de formatos disponibles. De forma predeterminada, hay dos formatos disponibles: CF_EMBEDSOURCE y CF_LINKSOURCE. Sin embargo, hay una serie de escenarios en los que es posible que las aplicaciones necesiten tener archivos de extracción en diferentes formatos:
Las aplicaciones pueden agregar formatos a la extracción almacenando en caché en el registro. Hay dos tipos de formatos almacenados en caché:
Para agregar una caché de prioridad o un formato representado por retraso, cree una subclave DataFormat en la clave CLSID de la aplicación que es el origen de los datos. En esa subclave, cree una subclave PriorityCacheFormats o DelayRenderFormats . Para cada caché de prioridad o formato representado con retraso, cree una subclave numerada a partir de cero. Establezca el valor de esta clave en una cadena con el nombre registrado del formato o un valor de #X, donde X representa el número de formato de un formato de Portapapeles estándar.
En el ejemplo siguiente se muestran los formatos almacenados en caché para dos aplicaciones. La aplicación MyProg1 tiene el formato de texto enriquecido como formato de caché de prioridad y un formato privado "Mi formato" como formato representado con retraso. La aplicación MyProg2 tiene el formato CF_BITMAP (#8") como formato de caché de prioridad.
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
Se pueden agregar formatos adicionales mediante la creación de subclaves numeradas adicionales.
Un formato de representación retrasado permite a una aplicación crear un archivo de extracción, pero retrasar el gasto de representación de los datos hasta que un destino lo solicite. La interfaz IDataObject de una extracción ofrecerá los formatos de representación retrasados al destino junto con datos nativos y almacenados en caché. Si el destino solicita un formato de representación retrasado, shell ejecutará la aplicación y proporcionará los datos al destino desde el objeto activo.
Nota
Dado que la representación diferida es algo arriesgada, se debe usar con precaución. No funcionará si el servidor no está disponible o en las aplicaciones que no están habilitadas para OLE.
Escenario: un usuario transfiere un bloque grande de datos de origen a destino. Para evitar el bloqueo de ambas aplicaciones durante una cantidad significativa de tiempo, el destino extrae los datos de forma asincrónica.
Normalmente, arrastrar y colocar es una operación sincrónica. En resumen:
En resumen, la transferencia de datos sincrónica puede bloquear los subprocesos principales de ambas aplicaciones durante una cantidad significativa de tiempo. En concreto, ambos subprocesos deben esperar mientras el destino extrae los datos. Para pequeñas cantidades de datos, el tiempo necesario para extraer datos es pequeño y la transferencia de datos sincrónica funciona bastante bien. Sin embargo, la extracción sincrónica de grandes cantidades de datos puede provocar retrasos prolongados e interferir con la interfaz de usuario de destino y origen.
La interfaz IDataObjectAsyncCapability de IAsyncOperation/es una interfaz opcional que un objeto de datos puede implementar. Proporciona al destino de colocación la capacidad de extraer datos del objeto de datos de forma asincrónica en un subproceso en segundo plano. Una vez que la extracción de datos se entrega al subproceso en segundo plano, los subprocesos principales de ambas aplicaciones pueden continuar.
Nota
La interfaz se llamaba originalmente IAsyncOperation, pero posteriormente se cambió a IDataObjectAsyncCapability. De lo contrario, las dos interfaces son idénticas.
El propósito de IAsyncOperation/IDataObjectAsyncCapability es permitir que el origen y el destino de colocación negocien si los datos se pueden extraer de forma asincrónica. En el procedimiento siguiente se describe cómo usa la interfaz el origen de colocación:
En el procedimiento siguiente se describe cómo el destino de colocación usa la interfaz IDataObjectAsyncCapability de IAsyncOperation/para extraer datos de forma asincrónica:
Cursos
Ruta de aprendizaje
Use advance techniques in canvas apps to perform custom updates and optimization - Training
Use advance techniques in canvas apps to perform custom updates and optimization