从设备读取文件

找到要从设备复制的文件后,可以通过一次调用将文件从设备复制到计算机,或使用回调将文件字节直接读取到应用程序,然后应用程序可以根据需要处理或存储数据。

以下步骤演示了在单个调用中从设备复制文件的基本方法:

  1. 获取设备上文件的句柄。 可以使用递归文件搜索或调用 IWMDMDevice3::FindStorage(如果知道存储的持久性 ID)来获取句柄。 在任一情况下,都需要对象的 IWMDMStorage 接口。
  2. 确定存储是文件还是文件夹。 只能从设备复制文件。 调用 IWMDMStorage::GetAttributes 以获取存储属性,这会告知存储是文件还是文件夹。
  3. 查询 IWMDMStorageControl的 IWMDMStorage,并调用 IWMDMStorageControl::Read 从设备读取文件并将其保存到指定位置。

如果想要逐个块从设备读取文件,则必须实现 IWMDMOperation 回调接口。 将此接口传递到 IWMDMStorageControl::Read 调用中,Windows Media 设备管理器将按顺序将文件数据块发送到回调。 以下步骤演示如何逐个块读取设备文件:

  1. 获取存储的 IWMDMStorage 接口,并确定它是否为文件,如前所述。
  2. 准备保存接收的数据所需的任何文件句柄或其他句柄。
  3. 查询存储的 IWMDMStorageControl 接口
  4. 调用 IWMDMStorageControl::Read 以开始读取操作,传入已实现的 IWMDMOperation 接口。
  5. Windows Media 设备管理器将逐个将数据块发送到设备,如手动处理文件传输中所述。

以下 C++ 示例函数从设备读取存储对象。 函数接受可选的 IWMDMOperation 接口指针;如果提交,函数将显式创建一个文件,并在其 实现 IWMDMOperation::TransferObjectData 时处理将数据写入文件;如果没有,它将读取文件并保存到 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;
}

创建 Windows Media 设备管理器 应用程序