Share via


Transferencia de una imagen o un archivo de Música al dispositivo

Una de las operaciones más comunes realizadas por una aplicación es la transferencia de contenido a un dispositivo conectado.

Las transferencias de contenido se realizan mediante las interfaces descritas en la tabla siguiente.

Interfaz Descripción
IPortableDeviceContent (Interfaz) Proporciona acceso a los métodos específicos del contenido.
IPortableDeviceDataStream (Interfaz) Se usa al escribir el contenido en el dispositivo.
IPortableDeviceValues (Interfaz) Se usa para recuperar propiedades que describen el contenido.
IStream (interfaz) Se usa para simplificar la lectura del contenido y la escritura en el dispositivo.

 

La TransferContentToDevice función del módulo ContentTransfer.cpp de la aplicación de ejemplo muestra cómo una aplicación podría transferir contenido de un equipo a un dispositivo conectado. En este ejemplo concreto, el contenido transferido puede ser un archivo que contiene una imagen, música o información de contacto.

La primera tarea realizada por la TransferContentToDevice función es pedir al usuario que escriba un identificador de objeto, que identifica el objeto que se va a transferir.

HRESULT                             hr = S_OK;
WCHAR                               szSelection[81]        = {0};
WCHAR                               szFilePath[MAX_PATH]   = {0};
DWORD                               cbOptimalTransferSize   = 0;
CComPtr<IStream>                    pFileStream;
CComPtr<IPortableDeviceDataStream>  pFinalObjectDataStream;
CComPtr<IPortableDeviceValues>      pFinalObjectProperties;
CComPtr<IPortableDeviceContent>     pContent;
CComPtr<IStream>                    pTempStream;  // Temporary IStream which we use to QI for IPortableDeviceDataStream

// Prompt user to enter an object identifier for the parent object on the device to transfer.
printf("Enter the identifer of the parent object which the file will be transferred under.\n>");
hr = StringCbGetsW(szSelection,sizeof(szSelection));
if (FAILED(hr))
{
    printf("An invalid object identifier was specified, aborting content transfer\n");
}

La segunda tarea realizada por la TransferContentToDevice función es crear un objeto IPortableDeviceContent llamando al método IPortableDevice::Content .

if (SUCCEEDED(hr))
{
    hr = pDevice->Content(&pContent);
    if (FAILED(hr))
    {
        printf("! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n",hr);
    }
}

La siguiente tarea realizada por la TransferContentToDevice función es la creación de un cuadro de diálogo FileOpen con el que el usuario puede especificar la ubicación y el nombre del archivo que se va a transferir.

if (SUCCEEDED(hr))
{
    OPENFILENAME OpenFileNameInfo   = {0};

    OpenFileNameInfo.lStructSize    = sizeof(OPENFILENAME);
    OpenFileNameInfo.hwndOwner      = NULL;
    OpenFileNameInfo.lpstrFile      = szFilePath;
    OpenFileNameInfo.nMaxFile       = ARRAYSIZE(szFilePath);
    OpenFileNameInfo.lpstrFilter    = pszFileTypeFilter;
    OpenFileNameInfo.nFilterIndex   = 1;
    OpenFileNameInfo.Flags          = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
    OpenFileNameInfo.lpstrDefExt    = pszDefaultFileExtension;

    if (GetOpenFileName(&OpenFileNameInfo) == FALSE)
    {
        printf("The transfer operation was canceled.\n");
        hr = E_ABORT;
    }
}

La TransferContentToDevice función pasa una cadena de filtro (wszFileTypeFilter) al método GetOpenFileName, que determina el tipo de archivos que el usuario puede elegir. Consulte la DoMenu función del módulo WpdApiSample.cpp para ver ejemplos de los tres filtros diferentes permitidos por el ejemplo.

Una vez que el usuario identifica un archivo determinado para la transferencia al dispositivo, la TransferContentToDevice función abre ese archivo como un objeto IStream y recupera las propiedades necesarias para completar la transferencia.

if (SUCCEEDED(hr))
{
    // Open the selected file as an IStream.  This will simplify reading the
    // data and writing to the device.
    hr = SHCreateStreamOnFile(szFilePath, STGM_READ, &pFileStream);
    if (SUCCEEDED(hr))
    {
        // Get the required properties needed to properly describe the data being
        // transferred to the device.
        hr = GetRequiredPropertiesForContentType(guidContentType,           // Content type of the data
                                                 szSelection,              // Parent to transfer the data under
                                                 szFilePath,               // Full file path to the data file
                                                 pFileStream,               // Open IStream that contains the data
                                                 &pFinalObjectProperties);  // Returned properties describing the data
        if (FAILED(hr))
        {
            printf("! Failed to get required properties needed to transfer a file to the device, hr = 0x%lx\n", hr);
        }
    }

    if (FAILED(hr))
    {
        printf("! Failed to open file named (%ws) to transfer to device, hr = 0x%lx\n",szFilePath, hr);
    }
}

Las propiedades necesarias se recuperan mediante una llamada a laGetRequiredPropertiesForContentType función auxiliar, que funciona en el objeto IStream. La GetRequiredPropertiesForContentType función auxiliar crea un objeto IPortableDeviceValues , recupera las propiedades de la lista siguiente y las agrega a este objeto.

  • Identificador de objeto primario
  • Tamaño de la secuencia en bytes
  • Nombre del archivo de contenido
  • Nombre de contenido (el nombre de archivo sin la extensión)
  • Tipo de contenido (imagen, audio o contacto)
  • Formato de contenido (JFIF, WMA o vCard2)

La aplicación de ejemplo usa las propiedades recuperadas para crear el nuevo contenido en el dispositivo. Esto se hace en tres fases:

  1. La aplicación llama al método IPortableDeviceContent::CreateObjectWithPropertiesAndData para crear un nuevo objeto IStream en el dispositivo.
  2. La aplicación usa este objeto para obtener un objeto IPortableDeviceDataStream del controlador WPD.
  3. La aplicación usa el nuevo objeto IPortableDeviceDataStream para escribir el contenido en el dispositivo (mediante la función auxiliar StreamCopy). La función auxiliar escribe los datos del archivo de origen en la secuencia devuelta por IPortableDeviceContent::CreateObjectWithPropertiesAndData.
  4. La aplicación completa la operación llamando al método Commit en la secuencia de destino.
// 4) Transfer for the content to the device
if (SUCCEEDED(hr))
{
    hr = pContent->CreateObjectWithPropertiesAndData(pFinalObjectProperties,    // Properties describing the object data
                                                     &pTempStream,              // Returned object data stream (to transfer the data to)
                                                     &cbOptimalTransferSize,    // Returned optimal buffer size to use during transfer
                                                     NULL);

    // Once we have a the IStream returned from CreateObjectWithPropertiesAndData,
    // QI for IPortableDeviceDataStream so we can use the additional methods
    // to get more information about the object (i.e. The newly created object
    // identifier on the device)
    if (SUCCEEDED(hr))
    {
        hr = pTempStream->QueryInterface(IID_PPV_ARGS(&pFinalObjectDataStream));
        if (FAILED(hr))
        {
            printf("! Failed to QueryInterface for IPortableDeviceDataStream, hr = 0x%lx\n",hr);
        }
    }

    // Since we have IStream-compatible interfaces, call our helper function
    // that copies the contents of a source stream into a destination stream.
    if (SUCCEEDED(hr))
    {
        DWORD cbTotalBytesWritten = 0;

        hr = StreamCopy(pFinalObjectDataStream, // Destination (The Object to transfer to)
                        pFileStream,            // Source (The File data to transfer from)
                        cbOptimalTransferSize,  // The driver specified optimal transfer buffer size
                        &cbTotalBytesWritten);  // The total number of bytes transferred from file to the device
        if (FAILED(hr))
        {
            printf("! Failed to transfer object to device, hr = 0x%lx\n",hr);
        }
    }
    else
    {
        printf("! Failed to get IStream (representing destination object data on the device) from IPortableDeviceContent, hr = 0x%lx\n",hr);
    }

    // After transferring content to the device, the client is responsible for letting the
    // driver know that the transfer is complete by calling the Commit() method
    // on the IPortableDeviceDataStream interface.
    if (SUCCEEDED(hr))
    {
        hr = pFinalObjectDataStream->Commit(0);
        if (FAILED(hr))
        {
            printf("! Failed to commit object to device, hr = 0x%lx\n",hr);
        }
    }

    // Some clients may want to know the object identifier of the newly created
    // object.  This is done by calling GetObjectID() method on the
    // IPortableDeviceDataStream interface.
    if (SUCCEEDED(hr))
    {
        PWSTR pszNewlyCreatedObject = NULL;
        hr = pFinalObjectDataStream->GetObjectID(&pszNewlyCreatedObject);
        if (SUCCEEDED(hr))
        {
            printf("The file '%ws' was transferred to the device.\nThe newly created object's ID is '%ws'\n",szFilePath ,pszNewlyCreatedObject);
        }

        if (FAILED(hr))
        {
            printf("! Failed to get the newly transferred object's identifier from the device, hr = 0x%lx\n",hr);
        }

        // Free the object identifier string returned from the GetObjectID() method.
        CoTaskMemFree(pszNewlyCreatedObject);
        pszNewlyCreatedObject = NULL;
    }
}

IPortableDevice (Interfaz)

IPortableDeviceContent (Interfaz)

IPortableDeviceDataStream (Interfaz)

IPortableDeviceValues (Interfaz)

Guía de programación