Share via


Reading Files from the Device

banner art

When you have found a file you would like to copy from the device, you can then copy the file from the device to the computer in a single call, or use a callback to have the file bytes read directly to your application, which can then process or store the data as it sees fits.

The following steps show the basic way to copy a file from a device in a single call:

  1. Get a handle to the file on the device. You might obtain the handle by using a recursive file search or, if you know the persistent ID of the storage, by calling IWMDMDevice3::FindStorage. In either case, you need the IWMDMStorage interface of the object.
  2. Determine whether the storage is a file or a folder. Only files can be copied from the device. Call IWMDMStorage::GetAttributes to get storage attributes, which will tell you whether the storage is a file or a folder.
  3. Query IWMDMStorage for IWMDMStorageControl, and call IWMDMStorageControl::Read to read the file from the device and save it to a specified location.

If, instead, you want to read the file block by block from the device, you must implement the IWMDMOperation callback interface. Pass this interface into the IWMDMStorageControl::Read call, and Windows Media Device Manager will send chunks of file data sequentially to your callback. The following steps show how to read a device file block by block:

  1. Get the IWMDMStorage interface for the storage and determine whether it is a file, as described previously.
  2. Prepare any file handles or other handles you need to hold the received data.
  3. Query for the storage's IWMDMStorageControl interface
  4. Call IWMDMStorageControl::Read to begin the read operation, passing in the IWMDMOperation interface you have implemented.
  5. Windows Media Device Manager will send the data block by block to your device as described in Handling File Transfers Manually.

The following C++ example function reads a storage object from a device. The function accepts an optional IWMDMOperation interface pointer; if submitted, the function will create a file explicitly and handle writing the data to file on its implementation of IWMDMOperation::TransferObjectData; if not, it will read the file and save to the destination specified by pwszDestName.

HANDLE m_File = NULL;

HRESULT myFileRead(IWMDMStorage pStorage, LPWSTR pwszDestName, IWMDMOperation* pOperation)
{
    HRESULT hr = S_OK;
    if ((pStorage == NULL) || (pwszDestName == NULL)) 
    {
        return E_INVALIDPARAM;
    }

    // Check that the storage is readable.
    DWORD attributes = 0;
    UINT flags = 0;
    hr = pStorage->GetAttributes(&attributes, NULL); 
    if (FAILED(hr))
    {
        return hr;
    }

    // Check that content is readable.
    if ((attributes & WMDM_FILE_ATTR_CANREAD) == 0)
    {
        return E_FAIL;
    }
    // Check that it is not abstract (such as an abstract playlist).
    else if (attributes & WMDM_STORAGE_ATTR_VIRTUAL)
    {
        return E_FAIL;
    }

    // Set some flag values for the read operation.
    flags |= WMDM_MODE_BLOCK;
    if (attributes & WMDM_FILE_ATTR_FOLDER)
    {
        flags |= WMDM_CONTENT_FOLDER;
    }
    if (attributes & WMDM_FILE_ATTR_FILE)
    {
        flags |= WMDM_CONTENT_FILE;
    }

    // Get the IWMDMStorageControl interface.
    CComQIPtr<IWMDMStorageControl> pStgControl(pStorage);
    
    // Extra steps if we want to read the file ourselves using IWMDMOperation3.
    if (pOperation != NULL)
    {
        // Create a new file and get the handle. m_File is a global variable
        // that we will use in IWMDMOperation::TransferObjectData.
        // This can also be done when IWMDMOperation::BeginRead is called.
        m_File = CreateFile(
            pwszDestName,   // Destination file name.
            GENERIC_WRITE,  // Write and append writes
            NULL,           // File can't be shared while using, and must be closed.
            NULL,           // Handle can't be inherited.
            CREATE_ALWAYS,  // Overwrite existing files.
            FILE_ATTRIBUTE_NORMAL, // No special attributes.
            NULL            // No template file supplied.
           );
        if (m_File == INVALID_HANDLE_VALUE) return E_FAIL;
        // Modify the Read() method flag. WMDM_CONTENT_FILE and WMDM_CONTENT_FOLDER 
        // are not valid flags when pOperation != NULL.
        flags |= WMDM_CONTENT_OPERATIONINTERFACE;
    }

    // Read the file.
    hr = pStgControl->Read(
             flags,        // Synchronous call specified.
             pwszDestName, // Ignored if pOperation is not NULL.
             NULL,         // No progress callback sent.
             pOperation);  // IWMDMOperation interface, if provided.
    return hr;
}

See Also