基本信息
源码名称:如何实现MTP协议的读取
源码大小:0.06M
文件格式:.zip
开发语言:C/C++
更新时间:2013-11-20
友情提示:(无需注册或充值,赞助后即可获取资源下载链接)
嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):813200300
本次赞助数额为: 2 元×
微信扫码支付:2 元
×
请留下您的邮箱,我们将在2小时内将文件发到您的邮箱
源码介绍
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. #include "stdafx.h" // Reads a string property from the IPortableDeviceProperties // interface and returns it HRESULT GetStringValue( _In_ IPortableDeviceProperties* properties, _In_ PCWSTR objectID, _In_ REFPROPERTYKEY key, _Out_ PWSTR* value) { ComPtr<IPortableDeviceValues> objectProperties; ComPtr<IPortableDeviceKeyCollection> propertiesToRead; // 1) CoCreate an IPortableDeviceKeyCollection interface to hold the the property key // we wish to read. HRESULT hr = CoCreateInstance(CLSID_PortableDeviceKeyCollection, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&propertiesToRead)); // 2) Populate the IPortableDeviceKeyCollection with the keys we wish to read. // NOTE: We are not handling any special error cases here so we can proceed with // adding as many of the target properties as we can. if (SUCCEEDED(hr)) { HRESULT tempHr = S_OK; tempHr = propertiesToRead->Add(key); if (FAILED(tempHr)) { wprintf(L"! Failed to add PROPERTYKEY to IPortableDeviceKeyCollection, hr= 0x%lx\n", tempHr); } } // 3) Call GetValues() passing the collection of specified PROPERTYKEYs. if (SUCCEEDED(hr)) { hr = properties->GetValues(objectID, // The object whose properties we are reading propertiesToRead.Get(), // The properties we want to read &objectProperties); // Driver supplied property values for the specified object // The error is handled by the caller, which also displays an error message to the user. } // 4) Extract the string value from the returned property collection if (SUCCEEDED(hr)) { PWSTR stringValue = nullptr; hr = objectProperties->GetStringValue(key, &stringValue); if (SUCCEEDED(hr)) { // Assign the newly read string to the result *value = stringValue; stringValue = nullptr; } else { wprintf(L"! Failed to find property in IPortableDeviceValues, hr = 0x%lx\n", hr); } CoTaskMemFree(stringValue); stringValue = nullptr; } return hr; } // Copies data from a source stream to a destination stream using the // specified transferSizeBytes as the temporary buffer size. HRESULT StreamCopy( _In_ IStream* destStream, _In_ IStream* sourceStream, DWORD transferSizeBytes, _Out_ DWORD* bytesWrittenOut) { *bytesWrittenOut = 0; HRESULT hr = S_OK; // Allocate a temporary buffer (of Optimal transfer size) for the read results to // be written to. BYTE* objectData = new (std::nothrow) BYTE[transferSizeBytes]; if (objectData != nullptr) { DWORD totalBytesRead = 0; DWORD totalBytesWritten = 0; DWORD bytesRead = 0; DWORD bytesWritten = 0; // Read until the number of bytes returned from the source stream is 0, or // an error occured during transfer. do { // Read object data from the source stream hr = sourceStream->Read(objectData, transferSizeBytes, &bytesRead); if (FAILED(hr)) { wprintf(L"! Failed to read %u bytes from the source stream, hr = 0x%lx\n", transferSizeBytes, hr); } // Write object data to the destination stream if (SUCCEEDED(hr)) { totalBytesRead = bytesRead; // Calculating total bytes read from device for debugging purposes only hr = destStream->Write(objectData, bytesRead, &bytesWritten); if (FAILED(hr)) { wprintf(L"! Failed to write %u bytes of object data to the destination stream, hr = 0x%lx\n", bytesRead, hr); } if (SUCCEEDED(hr)) { totalBytesWritten = bytesWritten; // Calculating total bytes written to the file for debugging purposes only } } // Output Read/Write operation information only if we have received data and if no error has occured so far. if (SUCCEEDED(hr) && (bytesRead > 0)) { wprintf(L"Read %u bytes from the source stream...Wrote %u bytes to the destination stream...\n", bytesRead, bytesWritten); } } while (SUCCEEDED(hr) && (bytesRead > 0)); // If we are successful, set bytesWrittenOut before exiting. if (SUCCEEDED(hr)) { *bytesWrittenOut = totalBytesWritten; } // Remember to delete the temporary transfer buffer delete [] objectData; objectData = nullptr; } else { wprintf(L"! Failed to allocate %u bytes for the temporary transfer buffer.\n", transferSizeBytes); } return hr; } // Transfers a selected object's data (WPD_RESOURCE_DEFAULT) to a temporary // file. void TransferContentFromDevice( _In_ IPortableDevice* device) { //<SnippetTransferFrom1> HRESULT hr = S_OK; DWORD optimalTransferSizeBytes = 0; PWSTR originalFileName = nullptr; WCHAR selection[SELECTION_BUFFER_SIZE] = {0}; ComPtr<IPortableDeviceContent> content; ComPtr<IPortableDeviceResources> resources; ComPtr<IPortableDeviceProperties> properties; ComPtr<IStream> objectDataStream; ComPtr<IStream> finalFileStream; // Prompt user to enter an object identifier on the device to transfer. wprintf(L"Enter the identifer of the object you wish to transfer.\n>"); hr = StringCchGetsW(selection, ARRAYSIZE(selection)); if (FAILED(hr)) { wprintf(L"An invalid object identifier was specified, aborting content transfer\n"); } //</SnippetTransferFrom1> // 1) get an IPortableDeviceContent interface from the IPortableDevice interface to // access the content-specific methods. //<SnippetTransferFrom2> if (SUCCEEDED(hr)) { hr = device->Content(&content); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n", hr); } } //</SnippetTransferFrom2> // 2) Get an IPortableDeviceResources interface from the IPortableDeviceContent interface to // access the resource-specific methods. //<SnippetTransferFrom3> if (SUCCEEDED(hr)) { hr = content->Transfer(&resources); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceResources from IPortableDeviceContent, hr = 0x%lx\n", hr); } } //</SnippetTransferFrom3> // 3) Get the IStream (with READ access) and the optimal transfer buffer size // to begin the transfer. //<SnippetTransferFrom4> if (SUCCEEDED(hr)) { hr = resources->GetStream(selection, // Identifier of the object we want to transfer WPD_RESOURCE_DEFAULT, // We are transferring the default resource (which is the entire object's data) STGM_READ, // Opening a stream in READ mode, because we are reading data from the device. &optimalTransferSizeBytes, // Driver supplied optimal transfer size &objectDataStream); if (FAILED(hr)) { wprintf(L"! Failed to get IStream (representing object data on the device) from IPortableDeviceResources, hr = 0x%lx\n", hr); } } //</SnippetTransferFrom4> // 4) Read the WPD_OBJECT_ORIGINAL_FILE_NAME property so we can properly name the // transferred object. Some content objects may not have this property, so a // fall-back case has been provided below. (i.e. Creating a file named <objectID>.data ) //<SnippetTransferFrom5> if (SUCCEEDED(hr)) { hr = content->Properties(&properties); if (SUCCEEDED(hr)) { hr = GetStringValue(properties.Get(), selection, WPD_OBJECT_ORIGINAL_FILE_NAME, &originalFileName); if (FAILED(hr)) { wprintf(L"! Failed to read WPD_OBJECT_ORIGINAL_FILE_NAME on object '%ws', hr = 0x%lx\n", selection, hr); // Create a temporary file name originalFileName = reinterpret_cast<PWSTR>(CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR))); if (originalFileName) { hr = StringCchPrintfW(originalFileName, MAX_PATH, L"%ws.data", selection); if (SUCCEEDED(hr)) { wprintf(L"* Creating a filename '%ws' as a default.\n", originalFileName); } } else { hr = E_OUTOFMEMORY; } } } else { wprintf(L"! Failed to get IPortableDeviceProperties from IPortableDeviceContent, hr = 0x%lx\n", hr); } } //</SnippetTransferFrom5> // 5) Create a destination for the data to be written to. In this example we are // creating a temporary file which is named the same as the object identifier string. //<SnippetTransferFrom6> if (SUCCEEDED(hr)) { hr = SHCreateStreamOnFileEx(originalFileName, STGM_CREATE|STGM_WRITE, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &finalFileStream); if (FAILED(hr)) { wprintf(L"! Failed to create a temporary file named (%ws) to transfer object (%ws), hr = 0x%lx\n", originalFileName, selection, hr); } } //</SnippetTransferFrom6> // 6) Read on the object's data stream and write to the final file's data stream using the // driver supplied optimal transfer buffer size. //<SnippetTransferFrom7> if (SUCCEEDED(hr)) { DWORD totalBytesWritten = 0; // Since we have IStream-compatible interfaces, call our helper function // that copies the contents of a source stream into a destination stream. hr = StreamCopy(finalFileStream.Get(), // Destination (The Final File to transfer to) objectDataStream.Get(), // Source (The Object's data to transfer from) optimalTransferSizeBytes, // The driver specified optimal transfer buffer size &totalBytesWritten); // The total number of bytes transferred from device to the finished file if (FAILED(hr)) { wprintf(L"! Failed to transfer object from device, hr = 0x%lx\n", hr); } else { wprintf(L"* Transferred object '%ws' to '%ws'.\n", selection, originalFileName); } } CoTaskMemFree(originalFileName); originalFileName = nullptr; //</SnippetTransferFrom7> } // Deletes a selected object from the device. //<SnippetDeleteContent1> void DeleteContentFromDevice( _In_ IPortableDevice* device) { HRESULT hr = S_OK; WCHAR selection[SELECTION_BUFFER_SIZE] = {0}; ComPtr<IPortableDeviceContent> content; ComPtr<IPortableDevicePropVariantCollection> objectsToDelete; ComPtr<IPortableDevicePropVariantCollection> objectsFailedToDelete; // Prompt user to enter an object identifier on the device to delete. wprintf(L"Enter the identifer of the object you wish to delete.\n>"); hr = StringCchGetsW(selection, ARRAYSIZE(selection)); if (FAILED(hr)) { wprintf(L"An invalid object identifier was specified, aborting content deletion\n"); } // 1) get an IPortableDeviceContent interface from the IPortableDevice interface to // access the content-specific methods. if (SUCCEEDED(hr)) { hr = device->Content(&content); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n", hr); } } // 2) CoCreate an IPortableDevicePropVariantCollection interface to hold the the object identifiers // to delete. // // NOTE: This is a collection interface so more than 1 object can be deleted at a time. // This sample only deletes a single object. if (SUCCEEDED(hr)) { hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&objectsToDelete)); if (SUCCEEDED(hr)) { // Initialize a PROPVARIANT structure with the object identifier string // that the user selected above. Notice we are allocating memory for the // PWSTR value. This memory will be freed when PropVariantClear() is // called below. PROPVARIANT pv = {0}; hr = InitPropVariantFromString(selection, &pv); if (SUCCEEDED(hr)) { // Add the object identifier to the objects-to-delete list // (We are only deleting 1 in this example) hr = objectsToDelete->Add(&pv); if (SUCCEEDED(hr)) { // Attempt to delete the object from the device hr = content->Delete(PORTABLE_DEVICE_DELETE_NO_RECURSION, // Deleting with no recursion objectsToDelete.Get(), // Object(s) to delete nullptr); // Object(s) that failed to delete (we are only deleting 1, so we can pass nullptr here) if (SUCCEEDED(hr)) { // An S_OK return lets the caller know that the deletion was successful if (hr == S_OK) { wprintf(L"The object '%ws' was deleted from the device.\n", selection); } // An S_FALSE return lets the caller know that the deletion failed. // The caller should check the returned IPortableDevicePropVariantCollection // for a list of object identifiers that failed to be deleted. else { wprintf(L"The object '%ws' failed to be deleted from the device.\n", selection); } } else { wprintf(L"! Failed to delete an object from the device, hr = 0x%lx\n", hr); } } else { wprintf(L"! Failed to delete an object from the device because we could no add the object identifier string to the IPortableDevicePropVariantCollection, hr = 0x%lx\n", hr); } } else { hr = E_OUTOFMEMORY; wprintf(L"! Failed to delete an object from the device because we could no allocate memory for the object identifier string, hr = 0x%lx\n", hr); } // Free any allocated values in the PROPVARIANT before exiting PropVariantClear(&pv); } else { wprintf(L"! Failed to delete an object from the device because we were returned a nullptr IPortableDevicePropVariantCollection interface pointer, hr = 0x%lx\n", hr); } } else { wprintf(L"! Failed to CoCreateInstance CLSID_PortableDevicePropVariantCollection, hr = 0x%lx\n", hr); } } //</SnippetDeleteContent1> // Moves a selected object (which is already on the device) to another location on the device. void MoveContentAlreadyOnDevice( _In_ IPortableDevice* device) { HRESULT hr = S_OK; WCHAR selection[SELECTION_BUFFER_SIZE] = {0}; WCHAR destinationFolderObjectID[SELECTION_BUFFER_SIZE] = {0}; ComPtr<IPortableDeviceContent> content; ComPtr<IPortableDevicePropVariantCollection> objectsToMove; ComPtr<IPortableDevicePropVariantCollection> objectsFailedToMove; // Check if the device supports the move command needed to perform this operation if (SupportsCommand(device, WPD_COMMAND_OBJECT_MANAGEMENT_MOVE_OBJECTS) == FALSE) { wprintf(L"! This device does not support the move operation (i.e. The WPD_COMMAND_OBJECT_MANAGEMENT_MOVE_OBJECTS command)\n"); return; } // Prompt user to enter an object identifier on the device to move. wprintf(L"Enter the identifer of the object you wish to move.\n>"); hr = StringCchGetsW(selection, ARRAYSIZE(selection)); if (FAILED(hr)) { wprintf(L"An invalid object identifier was specified, aborting content moving\n"); } // Prompt user to enter an object identifier on the device to move. wprintf(L"Enter the identifer of the object you wish to move '%ws' to.\n>", selection); hr = StringCchGetsW(destinationFolderObjectID, ARRAYSIZE(destinationFolderObjectID)); if (FAILED(hr)) { wprintf(L"An invalid object identifier was specified, aborting content moving\n"); } // 1) get an IPortableDeviceContent interface from the IPortableDevice interface to // access the content-specific methods. if (SUCCEEDED(hr)) { hr = device->Content(&content); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n", hr); } } // 2) CoCreate an IPortableDevicePropVariantCollection interface to hold the the object identifiers // to move. // // NOTE: This is a collection interface so more than 1 object can be moved at a time. // This sample only moves a single object. if (SUCCEEDED(hr)) { hr = CoCreateInstance(CLSID_PortableDevicePropVariantCollection, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&objectsToMove)); if (SUCCEEDED(hr)) { // Initialize a PROPVARIANT structure with the object identifier string // that the user selected above. Notice we are allocating memory for the // PWSTR value. This memory will be freed when PropVariantClear() is // called below. PROPVARIANT pv = {0}; hr = InitPropVariantFromString(selection, &pv); if (SUCCEEDED(hr)) { // Add the object identifier to the objects-to-move list // (We are only moving 1 in this example) hr = objectsToMove->Add(&pv); if (SUCCEEDED(hr)) { // Attempt to move the object on the device hr = content->Move(objectsToMove.Get(), // Object(s) to move destinationFolderObjectID, // Folder to move to nullptr); // Object(s) that failed to delete (we are only moving 1, so we can pass nullptr here) if (SUCCEEDED(hr)) { // An S_OK return lets the caller know that the deletion was successful if (hr == S_OK) { wprintf(L"The object '%ws' was moved on the device.\n", selection); } // An S_FALSE return lets the caller know that the move failed. // The caller should check the returned IPortableDevicePropVariantCollection // for a list of object identifiers that failed to be moved. else { wprintf(L"The object '%ws' failed to be moved on the device.\n", selection); } } else { wprintf(L"! Failed to move an object on the device, hr = 0x%lx\n", hr); } } else { wprintf(L"! Failed to move an object on the device because we could no add the object identifier string to the IPortableDevicePropVariantCollection, hr = 0x%lx\n", hr); } } else { hr = E_OUTOFMEMORY; wprintf(L"! Failed to move an object on the device because we could no allocate memory for the object identifier string, hr = 0x%lx\n", hr); } // Free any allocated values in the PROPVARIANT before exiting PropVariantClear(&pv); } else { wprintf(L"! Failed to move an object from the device because we were returned a nullptr IPortableDevicePropVariantCollection interface pointer, hr = 0x%lx\n", hr); } } else { wprintf(L"! Failed to CoCreateInstance CLSID_PortableDevicePropVariantCollection, hr = 0x%lx\n", hr); } } // Fills out the required properties for ALL content types... HRESULT GetRequiredPropertiesForAllContentTypes( _In_ IPortableDeviceValues* objectProperties, _In_ PCWSTR parentObjectID, _In_ PCWSTR filePath, _In_ IStream* fileStream) { // Set the WPD_OBJECT_PARENT_ID HRESULT hr = objectProperties->SetStringValue(WPD_OBJECT_PARENT_ID, parentObjectID); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_PARENT_ID, hr = 0x%lx\n", hr); } // Set the WPD_OBJECT_SIZE by requesting the total size of the // data stream. if (SUCCEEDED(hr)) { STATSTG statstg = {0}; hr = fileStream->Stat(&statstg, STATFLAG_NONAME); if (SUCCEEDED(hr)) { hr = objectProperties->SetUnsignedLargeIntegerValue(WPD_OBJECT_SIZE, statstg.cbSize.QuadPart); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_SIZE, hr = 0x%lx\n", hr); } } else { wprintf(L"! Failed to get file's total size, hr = 0x%lx\n", hr); } } if (SUCCEEDED(hr)) { // Set the WPD_OBJECT_ORIGINAL_FILE_NAME by splitting the file path // into a separate filename. WCHAR fileName[MAX_PATH] = {0}; WCHAR fileExt[MAX_PATH] = {0}; if (_wsplitpath_s(filePath, nullptr, 0, nullptr, 0, fileName,ARRAYSIZE(fileName), fileExt, ARRAYSIZE(fileExt))) { hr = E_INVALIDARG; wprintf(L"! Failed to split the file path, hr = 0x%lx\n", hr); } if (SUCCEEDED(hr)) { WCHAR originalFileName[MAX_PATH] = {0}; hr = StringCchPrintfW(originalFileName, ARRAYSIZE(originalFileName), L"%ws%ws", fileName, fileExt); if (SUCCEEDED(hr)) { hr = objectProperties->SetStringValue(WPD_OBJECT_ORIGINAL_FILE_NAME, originalFileName); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_ORIGINAL_FILE_NAME, hr = 0x%lx\n", hr); } } } // Set the WPD_OBJECT_NAME. We are using the file name without its file extension in this // example for the object's name. The object name could be a more friendly name like // "This Cool Song" or "That Cool Picture". if (SUCCEEDED(hr)) { hr = objectProperties->SetStringValue(WPD_OBJECT_NAME, fileName); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_NAME, hr = 0x%lx\n", hr); } } } return hr; } // Fills out the required properties for WPD_CONTENT_TYPE_IMAGE HRESULT GetRequiredPropertiesForImageContentTypes( _In_ IPortableDeviceValues* pObjectProperties) { // Set the WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_IMAGE because we are // creating/transferring image content to the device. HRESULT hr = pObjectProperties->SetGuidValue(WPD_OBJECT_CONTENT_TYPE, WPD_CONTENT_TYPE_IMAGE); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_IMAGE, hr = 0x%lx\n", hr); } // Set the WPD_OBJECT_FORMAT to WPD_OBJECT_FORMAT_EXIF because we are // creating/transferring image content to the device. if (SUCCEEDED(hr)) { hr = pObjectProperties->SetGuidValue(WPD_OBJECT_FORMAT, WPD_OBJECT_FORMAT_EXIF); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_FORMAT to WPD_OBJECT_FORMAT_EXIF, hr = 0x%lx\n", hr); } } return hr; } // Fills out the required properties for WPD_CONTENT_TYPE_AUDIO HRESULT GetRequiredPropertiesForMusicContentTypes( _In_ IPortableDeviceValues* objectProperties) { // Set the WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_AUDIO because we are // creating/transferring music content to the device. HRESULT hr = objectProperties->SetGuidValue(WPD_OBJECT_CONTENT_TYPE, WPD_CONTENT_TYPE_AUDIO); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_AUDIO, hr = 0x%lx\n", hr); } // Set the WPD_OBJECT_FORMAT to WPD_OBJECT_FORMAT_MP3 because we are // creating/transferring music content to the device. if (SUCCEEDED(hr)) { hr = objectProperties->SetGuidValue(WPD_OBJECT_FORMAT, WPD_OBJECT_FORMAT_MP3); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_FORMAT to WPD_OBJECT_FORMAT_MP3, hr = 0x%lx\n", hr); } } return hr; } // Fills out the required properties for WPD_CONTENT_TYPE_CONTACT HRESULT GetRequiredPropertiesForContactContentTypes( _In_ IPortableDeviceValues* objectProperties) { // Set the WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_CONTACT because we are // creating/transferring contact content to the device. HRESULT hr = objectProperties->SetGuidValue(WPD_OBJECT_CONTENT_TYPE, WPD_CONTENT_TYPE_CONTACT); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_CONTACT, hr = 0x%lx\n", hr); } // Set the WPD_OBJECT_FORMAT to WPD_OBJECT_FORMAT_VCARD2 because we are // creating/transferring contact content to the device. (This is Version 2 of // the VCARD file. If you have Version 3, use WPD_OBJECT_FORMAT_VCARD3 as the // format) if (SUCCEEDED(hr)) { hr = objectProperties->SetGuidValue(WPD_OBJECT_FORMAT, WPD_OBJECT_FORMAT_VCARD2); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_FORMAT to WPD_OBJECT_FORMAT_VCARD2, hr = 0x%lx\n", hr); } } return hr; } // Fills out the required properties for specific WPD content types. HRESULT GetRequiredPropertiesForContentType( _In_ REFGUID contentType, _In_ PCWSTR parentObjectID, _In_ PCWSTR filePath, _In_ IStream* fileStream, _COM_Outptr_ IPortableDeviceValues** objectProperties) { *objectProperties = nullptr; ComPtr<IPortableDeviceValues> objectPropertiesTemp; // CoCreate an IPortableDeviceValues interface to hold the the object information HRESULT hr = CoCreateInstance(CLSID_PortableDeviceValues, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&objectPropertiesTemp)); if (SUCCEEDED(hr)) { if (objectPropertiesTemp != nullptr) { // Fill out required properties for ALL content types hr = GetRequiredPropertiesForAllContentTypes(objectPropertiesTemp.Get(), parentObjectID, filePath, fileStream); if (SUCCEEDED(hr)) { // Fill out required properties for specific content types. // NOTE: If the content type is unknown to this function then // only the required properties will be written. This is enough // for transferring most generic content types. if (IsEqualGUID(contentType, WPD_CONTENT_TYPE_IMAGE)) { hr = GetRequiredPropertiesForImageContentTypes(objectPropertiesTemp.Get()); } else if (IsEqualGUID(contentType, WPD_CONTENT_TYPE_AUDIO)) { hr = GetRequiredPropertiesForMusicContentTypes(objectPropertiesTemp.Get()); } else if (IsEqualGUID(contentType, WPD_CONTENT_TYPE_CONTACT)) { hr = GetRequiredPropertiesForContactContentTypes(objectPropertiesTemp.Get()); } } else { wprintf(L"! Failed to get required properties common to ALL content types, hr = 0x%lx\n", hr); } if (SUCCEEDED(hr)) { *objectProperties = objectPropertiesTemp.Detach(); } } else { hr = E_UNEXPECTED; wprintf(L"! Failed to create property information because we were returned a nullptr IPortableDeviceValues interface pointer, hr = 0x%lx\n", hr); } } return hr; } // Transfers a user selected file to the device void TransferContentToDevice( _In_ IPortableDevice* device, _In_ REFGUID contentType, _In_ PCWSTR fileTypeFilter, _In_ PCWSTR defaultFileExtension) { //<SnippetContentTransfer1> HRESULT hr = S_OK; WCHAR filePath[MAX_PATH] = {0}; DWORD optimalTransferSizeBytes = 0; WCHAR selection[SELECTION_BUFFER_SIZE] = {0}; ComPtr<IStream> fileStream; ComPtr<IPortableDeviceDataStream> finalObjectDataStream; ComPtr<IPortableDeviceValues> finalObjectProperties; ComPtr<IPortableDeviceContent> content; ComPtr<IStream> tempStream; // 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. wprintf(L"Enter the identifer of the parent object which the file will be transferred under.\n>"); hr = StringCchGetsW(selection, ARRAYSIZE(selection)); if (FAILED(hr)) { wprintf(L"An invalid object identifier was specified, aborting content transfer\n"); } //</SnippetContentTransfer1> // 1) Get an IPortableDeviceContent interface from the IPortableDevice interface to // access the content-specific methods. //<SnippetContentTransfer2> if (SUCCEEDED(hr)) { hr = device->Content(&content); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n", hr); } } //</SnippetContentTransfer2> // 2) Present the user with a File Open dialog. Our sample is // restricting the types to user-specified forms. //<SnippetContentTransfer3> if (SUCCEEDED(hr)) { OPENFILENAME openFileNameInfo = {0}; openFileNameInfo.lStructSize = sizeof(OPENFILENAME); openFileNameInfo.hwndOwner = nullptr; openFileNameInfo.lpstrFile = filePath; openFileNameInfo.nMaxFile = ARRAYSIZE(filePath); openFileNameInfo.lpstrFilter = fileTypeFilter; openFileNameInfo.nFilterIndex = 1; openFileNameInfo.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; openFileNameInfo.lpstrDefExt = defaultFileExtension; if (GetOpenFileName(&openFileNameInfo) == FALSE) { wprintf(L"The transfer operation was cancelled.\n"); hr = E_ABORT; } } //</SnippetContentTransfer3> // 3) Open the image file and add required properties about the file being transferred //<SnippetContentTransfer4> if (SUCCEEDED(hr)) { // Open the selected file as an IStream. This will simplify reading the // data and writing to the device. hr = SHCreateStreamOnFileEx(filePath, STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &fileStream); if (SUCCEEDED(hr)) { // Get the required properties needed to properly describe the data being // transferred to the device. hr = GetRequiredPropertiesForContentType(contentType, // Content type of the data selection, // Parent to transfer the data under filePath, // Full file path to the data file fileStream.Get(), // Open IStream that contains the data &finalObjectProperties); // Returned properties describing the data if (FAILED(hr)) { wprintf(L"! Failed to get required properties needed to transfer a file to the device, hr = 0x%lx\n", hr); } } if (FAILED(hr)) { wprintf(L"! Failed to open file named (%ws) to transfer to device, hr = 0x%lx\n", filePath, hr); } } //</SnippetContentTransfer4> //<SnippetContentTransfer5> // 4) Transfer for the content to the device if (SUCCEEDED(hr)) { hr = content->CreateObjectWithPropertiesAndData(finalObjectProperties.Get(), // Properties describing the object data &tempStream, // Returned object data stream (to transfer the data to) &optimalTransferSizeBytes, // Returned optimal buffer size to use during transfer nullptr); // 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 = tempStream.As(&finalObjectDataStream); if (FAILED(hr)) { wprintf(L"! 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 totalBytesWritten = 0; hr = StreamCopy(finalObjectDataStream.Get(), // Destination (The Object to transfer to) fileStream.Get(), // Source (The File data to transfer from) optimalTransferSizeBytes, // The driver specified optimal transfer buffer size &totalBytesWritten); // The total number of bytes transferred from file to the device if (FAILED(hr)) { wprintf(L"! Failed to transfer object to device, hr = 0x%lx\n", hr); } } else { wprintf(L"! 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 = finalObjectDataStream->Commit(STGC_DEFAULT); if (FAILED(hr)) { wprintf(L"! 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 newlyCreatedObject = nullptr; hr = finalObjectDataStream->GetObjectID(&newlyCreatedObject); if (SUCCEEDED(hr)) { wprintf(L"The file '%ws' was transferred to the device.\nThe newly created object's ID is '%ws'\n", filePath, newlyCreatedObject); } else { wprintf(L"! 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(newlyCreatedObject); newlyCreatedObject = nullptr; } } //</SnippetContentTransfer5> } // Transfers a user selected file to the device as a new WPD_RESOURCE_CONTACT_PHOTO resource void CreateContactPhotoResourceOnDevice( _In_ IPortableDevice* device) { HRESULT hr = S_OK; DWORD optimalTransferSizeBytes = 0; WCHAR filePath[MAX_PATH] = {0}; WCHAR selection[SELECTION_BUFFER_SIZE] = {0}; ComPtr<IStream> fileStream; ComPtr<IStream> resourceStream; ComPtr<IPortableDeviceValues> resourceAttributes; ComPtr<IPortableDeviceContent> content; ComPtr<IPortableDeviceResources> resources; // Prompt user to enter an object identifier for the object to which we will add a Resource. wprintf(L"Enter the identifer of the object to which we will add a photograph.\n>"); hr = StringCchGetsW(selection, ARRAYSIZE(selection)); if (FAILED(hr)) { wprintf(L"An invalid object identifier was specified, aborting resource creation\n"); } // 1) Get an IPortableDeviceContent interface from the IPortableDevice interface to // access the content-specific methods. if (SUCCEEDED(hr)) { hr = device->Content(&content); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n", hr); } } // 2) Get an IPortableDeviceResources interface from the IPortableDeviceContent to // access the resource-specific methods. if (SUCCEEDED(hr)) { hr = content->Transfer(&resources); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceResources from IPortableDeviceContent, hr = 0x%lx\n", hr); } } // 3) Present the user with a File Open dialog. Our sample is // restricting the types to user-specified forms. if (SUCCEEDED(hr)) { OPENFILENAME openFileNameInfo = {0}; openFileNameInfo.lStructSize = sizeof(OPENFILENAME); openFileNameInfo.hwndOwner = nullptr; openFileNameInfo.lpstrFile = filePath; openFileNameInfo.nMaxFile = ARRAYSIZE(filePath); openFileNameInfo.lpstrFilter = L"JPEG (*.JPG)\0*.JPG\0JPEG (*.JPEG)\0*.JPEG\0JPG (*.JPE)\0*.JPE\0JPG (*.JFIF)\0*.JFIF\0\0";; openFileNameInfo.nFilterIndex = 1; openFileNameInfo.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; openFileNameInfo.lpstrDefExt = L"JPG"; if (GetOpenFileName(&openFileNameInfo) == FALSE) { wprintf(L"The transfer operation was cancelled.\n"); hr = E_ABORT; } } // 4) Open the file and add required properties about the resource being transferred if (SUCCEEDED(hr)) { // Open the selected file as an IStream. This will simplify reading the // data and writing to the device. hr = SHCreateStreamOnFileEx(filePath, STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &fileStream); if (SUCCEEDED(hr)) { // CoCreate the IPortableDeviceValues to hold the resource attributes hr = CoCreateInstance(CLSID_PortableDeviceValues, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&resourceAttributes)); if (SUCCEEDED(hr)) { // Fill in the necessary information regarding this resource // Set the WPD_OBJECT_ID. This informs the driver which object this request is intended for. hr = resourceAttributes->SetStringValue(WPD_OBJECT_ID, selection); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_ID when creating a resource, hr = 0x%lx\n", hr); } // Set the WPD_RESOURCE_ATTRIBUTE_RESOURCE_KEY to WPD_RESOURCE_CONTACT_PHOTO if (SUCCEEDED(hr)) { hr = resourceAttributes->SetKeyValue(WPD_RESOURCE_ATTRIBUTE_RESOURCE_KEY, WPD_RESOURCE_CONTACT_PHOTO); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_RESOURCE_ATTRIBUTE_RESOURCE_KEY to WPD_RESOURCE_CONTACT_PHOTO, hr = 0x%lx\n", hr); } } // Set the WPD_RESOURCE_ATTRIBUTE_TOTAL_SIZE by requesting the total size of the // data stream. if (SUCCEEDED(hr)) { STATSTG statstg = {0}; hr = fileStream->Stat(&statstg, STATFLAG_NONAME); if (SUCCEEDED(hr)) { hr = resourceAttributes->SetUnsignedLargeIntegerValue(WPD_RESOURCE_ATTRIBUTE_TOTAL_SIZE, statstg.cbSize.QuadPart); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_RESOURCE_ATTRIBUTE_TOTAL_SIZE, hr = 0x%lx\n", hr); } } else { wprintf(L"! Failed to get file's total size, hr = 0x%lx\n", hr); } } // Set the WPD_RESOURCE_ATTRIBUTE_FORMAT to WPD_OBJECT_FORMAT_EXIF because we are // creating a contact photo resource with JPG image data. if (SUCCEEDED(hr)) { hr = resourceAttributes->SetGuidValue(WPD_RESOURCE_ATTRIBUTE_FORMAT, WPD_OBJECT_FORMAT_EXIF); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_RESOURCE_ATTRIBUTE_FORMAT to WPD_OBJECT_FORMAT_EXIF, hr = 0x%lx\n", hr); } } } } if (FAILED(hr)) { wprintf(L"! Failed to open file named (%ws) to transfer to device, hr = 0x%lx\n", filePath, hr); } } // 5) Transfer for the content to the device if (SUCCEEDED(hr)) { hr = resources->CreateResource(resourceAttributes.Get(), // Properties describing this resource &resourceStream, // Returned resource data stream (to transfer the data to) &optimalTransferSizeBytes, // Returned optimal buffer size to use during transfer nullptr); // 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 totalBytesWritten = 0; hr = StreamCopy(resourceStream.Get(), // Destination (The resource to transfer to) fileStream.Get(), // Source (The File data to transfer from) optimalTransferSizeBytes, // The driver specified optimal transfer buffer size &totalBytesWritten); // The total number of bytes transferred from file to the device if (FAILED(hr)) { wprintf(L"! Failed to transfer object to device, hr = 0x%lx\n", hr); } } else { wprintf(L"! 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 = resourceStream->Commit(STGC_DEFAULT); if (FAILED(hr)) { wprintf(L"! Failed to commit resource to device, hr = 0x%lx\n", hr); } } } } // Fills out the required properties for a properties-only // contact named "John Kane". This is a hard-coded // contact. HRESULT GetRequiredPropertiesForPropertiesOnlyContact( _In_ PCWSTR parentObjectID, _COM_Outptr_ IPortableDeviceValues** objectProperties) { *objectProperties = nullptr; ComPtr<IPortableDeviceValues> objectPropertiesTemp; // CoCreate an IPortableDeviceValues interface to hold the the object information HRESULT hr = CoCreateInstance(CLSID_PortableDeviceValues, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&objectPropertiesTemp)); if (SUCCEEDED(hr)) { // Set the WPD_OBJECT_PARENT_ID if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetStringValue(WPD_OBJECT_PARENT_ID, parentObjectID); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_PARENT_ID, hr = 0x%lx\n", hr); } } // Set the WPD_OBJECT_NAME. if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetStringValue(WPD_OBJECT_NAME, L"John Kane"); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_NAME, hr = 0x%lx\n", hr); } } // Set the WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_CONTACT because we are // creating contact content on the device. if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetGuidValue(WPD_OBJECT_CONTENT_TYPE, WPD_CONTENT_TYPE_CONTACT); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_CONTACT, hr = 0x%lx\n", hr); } } // Set the WPD_CONTACT_DISPLAY_NAME to "John Kane" if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetStringValue(WPD_CONTACT_DISPLAY_NAME, L"John Kane"); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_CONTACT_DISPLAY_NAME, hr = 0x%lx\n", hr); } } // Set the WPD_CONTACT_PRIMARY_PHONE to "425-555-0123" if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetStringValue(WPD_CONTACT_PRIMARY_PHONE, L"425-555-0123"); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_CONTACT_PRIMARY_PHONE, hr = 0x%lx\n", hr); } } if (SUCCEEDED(hr)) { *objectProperties = objectPropertiesTemp.Detach(); } } else { hr = E_UNEXPECTED; wprintf(L"! Failed to create property information because we were returned a nullptr IPortableDeviceValues interface pointer, hr = 0x%lx\n", hr); } return hr; } HRESULT GetRequiredPropertiesForFolder( _In_ PCWSTR parentObjectID, _In_ PCWSTR folderName, _COM_Outptr_ IPortableDeviceValues** objectProperties) { *objectProperties = nullptr; ComPtr<IPortableDeviceValues> objectPropertiesTemp; // CoCreate an IPortableDeviceValues interface to hold the the object information HRESULT hr = CoCreateInstance(CLSID_PortableDeviceValues, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&objectPropertiesTemp)); if (SUCCEEDED(hr)) { // Set the WPD_OBJECT_PARENT_ID if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetStringValue(WPD_OBJECT_PARENT_ID, parentObjectID); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_PARENT_ID, hr = 0x%lx\n", hr); } } // Set the WPD_OBJECT_NAME. if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetStringValue(WPD_OBJECT_NAME, folderName); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_NAME, hr = 0x%lx\n", hr); } } // Set the WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_FOLDER because we are // creating contact content on the device. if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetGuidValue(WPD_OBJECT_CONTENT_TYPE, WPD_CONTENT_TYPE_FOLDER); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_CONTENT_TYPE to WPD_CONTENT_TYPE_FOLDER, hr = 0x%lx\n", hr); } } if (SUCCEEDED(hr)) { *objectProperties = objectPropertiesTemp.Detach(); } } else { hr = E_UNEXPECTED; wprintf(L"! Failed to create property information because we were returned a nullptr IPortableDeviceValues interface pointer, hr = 0x%lx\n", hr); } return hr; } // Creates a properties-only object on the device which is // WPD_CONTENT_TYPE_CONTACT specific. // NOTE: This function creates a hard-coded contact for // "John Kane" always. void TransferContactToDevice( _In_ IPortableDevice* device) { //<SnippetTransfer1> HRESULT hr = S_OK; WCHAR selection[SELECTION_BUFFER_SIZE] = {0}; ComPtr<IPortableDeviceValues> finalObjectProperties; ComPtr<IPortableDeviceContent> content; // Prompt user to enter an object identifier for the parent object on the device to transfer. wprintf(L"Enter the identifer of the parent object which the contact will be transferred under.\n>"); hr = StringCchGetsW(selection, ARRAYSIZE(selection)); if (FAILED(hr)) { wprintf(L"An invalid object identifier was specified, aborting content transfer\n"); } //</SnippetTransfer1> // 1) Get an IPortableDeviceContent interface from the IPortableDevice interface to // access the content-specific methods. if (SUCCEEDED(hr)) { hr = device->Content(&content); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n", hr); } } //<SnippetTransfer2> // 2) Get the properties that describe the object being created on the device if (SUCCEEDED(hr)) { hr = GetRequiredPropertiesForPropertiesOnlyContact(selection, // Parent to transfer the data under &finalObjectProperties); // Returned properties describing the data if (FAILED(hr)) { wprintf(L"! Failed to get required properties needed to transfer an image file to the device, hr = 0x%lx\n", hr); } } //</SnippetTransfer2> // 3) Transfer the content to the device by creating a properties-only object //<SnippetTransfer3> if (SUCCEEDED(hr)) { PWSTR newlyCreatedObject = nullptr; hr = content->CreateObjectWithPropertiesOnly(finalObjectProperties.Get(), // Properties describing the object data &newlyCreatedObject); if (SUCCEEDED(hr)) { wprintf(L"The contact was transferred to the device.\nThe newly created object's ID is '%ws'\n", newlyCreatedObject); } else { wprintf(L"! Failed to transfer contact object to the device, hr = 0x%lx\n", hr); } // Free the object identifier string returned from CreateObjectWithPropertiesOnly CoTaskMemFree(newlyCreatedObject); newlyCreatedObject = nullptr; } //</SnippetTransfer3> } // Creates a properties-only object on the device which is // WPD_CONTENT_TYPE_FOLDER specific. void CreateFolderOnDevice( _In_ IPortableDevice* device) { HRESULT hr = S_OK; WCHAR selection[SELECTION_BUFFER_SIZE] = {0}; WCHAR folderName[SELECTION_BUFFER_SIZE] = {0}; ComPtr<IPortableDeviceValues> finalObjectProperties; ComPtr<IPortableDeviceContent> content; // Prompt user to enter an object identifier for the parent object on the device to transfer. wprintf(L"Enter the identifer of the parent object which the folder will be created under.\n>"); hr = StringCchGetsW(selection, ARRAYSIZE(selection)); if (FAILED(hr)) { wprintf(L"An invalid object identifier was specified, aborting folder creation\n"); } // Prompt user to enter an object identifier for the parent object on the device to transfer. wprintf(L"Enter the name of the the folder to create.\n>"); hr = StringCchGetsW(folderName, ARRAYSIZE(folderName)); if (FAILED(hr)) { wprintf(L"An invalid folder name was specified, aborting folder creation\n"); } // 1) Get an IPortableDeviceContent interface from the IPortableDevice interface to // access the content-specific methods. if (SUCCEEDED(hr)) { hr = device->Content(&content); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n", hr); } } // 2) Get the properties that describe the object being created on the device if (SUCCEEDED(hr)) { hr = GetRequiredPropertiesForFolder(selection, // Parent to create the folder under folderName, // Folder Name &finalObjectProperties); // Returned properties describing the folder if (FAILED(hr)) { wprintf(L"! Failed to get required properties needed to transfer an image file to the device, hr = 0x%lx\n", hr); } } // 3) Transfer the content to the device by creating a properties-only object if (SUCCEEDED(hr)) { PWSTR newlyCreatedObject = nullptr; hr = content->CreateObjectWithPropertiesOnly(finalObjectProperties.Get(), // Properties describing the object data &newlyCreatedObject); if (SUCCEEDED(hr)) { wprintf(L"The folder was created on the device.\nThe newly created object's ID is '%ws'\n", newlyCreatedObject); } else { wprintf(L"! Failed to create a new folder on the device, hr = 0x%lx\n", hr); } // Free the object identifier string returned from CreateObjectWithPropertiesOnly CoTaskMemFree(newlyCreatedObject); newlyCreatedObject = nullptr; } } // Fills out properties that accompany updating an object's data... HRESULT GetPropertiesForUpdateData( _In_ PCWSTR filePath, _In_ IStream* fileStream, _COM_Outptr_ IPortableDeviceValues** objectProperties) { *objectProperties = nullptr; ComPtr<IPortableDeviceValues> objectPropertiesTemp; // CoCreate an IPortableDeviceValues interface to hold the the object information HRESULT hr = CoCreateInstance(CLSID_PortableDeviceValues, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&objectPropertiesTemp)); if (SUCCEEDED(hr)) { // Set the WPD_OBJECT_SIZE by requesting the total size of the // data stream. STATSTG statstg = {0}; hr = fileStream->Stat(&statstg, STATFLAG_NONAME); if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetUnsignedLargeIntegerValue(WPD_OBJECT_SIZE, statstg.cbSize.QuadPart); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_SIZE, hr = 0x%lx\n", hr); } } else { wprintf(L"! Failed to get file's total size, hr = 0x%lx\n", hr); } // Set the WPD_OBJECT_ORIGINAL_FILE_NAME by splitting the file path // into a separate filename. WCHAR fileName[MAX_PATH] = {0}; WCHAR fileExt[MAX_PATH] = {0}; if (_wsplitpath_s(filePath, nullptr, 0, nullptr, 0, fileName,ARRAYSIZE(fileName), fileExt, ARRAYSIZE(fileExt))) { hr = E_INVALIDARG; wprintf(L"! Failed to split the file path, hr = 0x%lx\n", hr); } if (SUCCEEDED(hr)) { WCHAR originalFileName[MAX_PATH] = {0}; hr = StringCchPrintfW(originalFileName, ARRAYSIZE(originalFileName), L"%ws%ws", fileName, fileExt); if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetStringValue(WPD_OBJECT_ORIGINAL_FILE_NAME, originalFileName); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_ORIGINAL_FILE_NAME, hr = 0x%lx\n", hr); } } } // Set the WPD_OBJECT_NAME. We are using the file name without its file extension in this // example for the object's name. The object name could be a more friendly name like // "This Cool Song" or "That Cool Picture". if (SUCCEEDED(hr)) { hr = objectPropertiesTemp->SetStringValue(WPD_OBJECT_NAME, fileName); if (FAILED(hr)) { wprintf(L"! Failed to set WPD_OBJECT_NAME, hr = 0x%lx\n", hr); } } if (SUCCEEDED(hr)) { *objectProperties = objectPropertiesTemp.Detach(); } } return hr; } // Updates a selected object's properties and data (WPD_RESOURCE_DEFAULT). void UpdateContentOnDevice( _In_ IPortableDevice* device, _In_ REFGUID contentType, _In_ PCWSTR fileTypeFilter, _In_ PCWSTR defaultFileExtension) { HRESULT hr = S_OK; DWORD optimalTransferSizeBytes = 0; WCHAR filePath[MAX_PATH] = {0}; WCHAR selection[SELECTION_BUFFER_SIZE] = {0}; ComPtr<IStream> fileStream; ComPtr<IPortableDeviceDataStream> finalObjectDataStream; ComPtr<IPortableDeviceValues> finalObjectProperties; ComPtr<IPortableDeviceContent2> content2; ComPtr<IStream> tempStream; // Temporary IStream which we use to QI for IPortableDeviceDataStream // Prompt user to enter an object identifier for the object on the device to update. wprintf(L"Enter the identifer of the object to update.\n>"); hr = StringCchGetsW(selection, ARRAYSIZE(selection)); if (FAILED(hr)) { wprintf(L"An invalid object identifier was specified, aborting content update\n"); } // 1) Get an IPortableDeviceContent2 interface from the IPortableDevice interface to // access the UpdateObjectWithPropertiesAndData method. if (SUCCEEDED(hr)) { ComPtr<IPortableDeviceContent> content; hr = device->Content(&content); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n", hr); } else { hr = content.As(&content2); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceContent2 from IPortableDeviceContent, hr = 0x%lx\n", hr); } } } // 2) (Optional) Check if the object is of the correct content type. This also ensures the user-specified object ID is valid. if (SUCCEEDED(hr)) { ComPtr<IPortableDeviceProperties> properties; hr = content2->Properties(&properties); if (FAILED(hr)) { wprintf(L"! Failed to get IPortableDeviceProperties from IPortableDeviceContent2, hr = 0x%lx\n", hr); } else { ComPtr<IPortableDeviceValues> objectProperties; hr = properties->GetValues(selection, nullptr, &objectProperties); if (FAILED(hr)) { wprintf(L"! Failed to get all properties for object (%ws), hr = 0x%lx\n", selection, hr); } else { GUID objectContentType; hr = objectProperties->GetGuidValue(WPD_OBJECT_CONTENT_TYPE, &objectContentType); if (FAILED(hr)) { wprintf(L"! Failed to get WPD_OBJECT_CONTENT_TYPE for object (%ws), hr = 0x%lx\n", selection, hr); } else if (objectContentType != contentType) { hr = E_INVALIDARG; wprintf(L"! Object (%ws) is not of the correct content type, hr = 0x%lx\n", selection, hr); } } } } // 3) Present the user with a File Open dialog. Our sample is // restricting the types to user-specified forms. if (SUCCEEDED(hr)) { OPENFILENAME openFileNameInfo = {0}; openFileNameInfo.lStructSize = sizeof(OPENFILENAME); openFileNameInfo.hwndOwner = nullptr; openFileNameInfo.lpstrFile = filePath; openFileNameInfo.nMaxFile = ARRAYSIZE(filePath); openFileNameInfo.lpstrFilter = fileTypeFilter; openFileNameInfo.nFilterIndex = 1; openFileNameInfo.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; openFileNameInfo.lpstrDefExt = defaultFileExtension; if (GetOpenFileName(&openFileNameInfo) == FALSE) { hr = E_ABORT; } } // 4) Open the file and add required properties about the file being transferred if (SUCCEEDED(hr)) { // Open the selected file as an IStream. This will simplify reading the // data and writing to the device. hr = SHCreateStreamOnFileEx(filePath, STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &fileStream); if (SUCCEEDED(hr)) { // Get the required properties needed to properly describe the data being // transferred to the device. hr = GetPropertiesForUpdateData(filePath, // Full file path to the data file fileStream.Get(), // Open IStream that contains the data &finalObjectProperties); // Returned properties describing the data if (FAILED(hr)) { wprintf(L"! Failed to get properties needed to transfer a file to the device, hr = 0x%lx\n", hr); } } if (FAILED(hr)) { wprintf(L"! Failed to open file named (%ws) to transfer to device, hr = 0x%lx\n", filePath, hr); } } // 5) Transfer for the content to the device if (SUCCEEDED(hr)) { hr = content2->UpdateObjectWithPropertiesAndData(selection, finalObjectProperties.Get(), // Properties describing the object data &tempStream, // Returned object data stream (to transfer the data to) &optimalTransferSizeBytes); // Returned optimal buffer size to use during transfer // Once we have a the IStream returned from UpdateObjectWithPropertiesAndData, // 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 = tempStream.As(&finalObjectDataStream); if (FAILED(hr)) { wprintf(L"! 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 totalBytesWritten = 0; hr = StreamCopy(finalObjectDataStream.Get(), // Destination (The Object to transfer to) fileStream.Get(), // Source (The File data to transfer from) optimalTransferSizeBytes, // The driver specified optimal transfer buffer size &totalBytesWritten); // The total number of bytes transferred from file to the device if (FAILED(hr)) { wprintf(L"! Failed to transfer object data to device, hr = 0x%lx\n", hr); } } else { wprintf(L"! Failed to get IStream (representing destination object data on the device) from UpdateObjectWithPropertiesAndData, 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 = finalObjectDataStream->Commit(STGC_DEFAULT); if (SUCCEEDED(hr)) { wprintf(L"The file '%ws' was transferred to the device to object '%ws'\n", filePath, selection); } else { wprintf(L"! Failed to commit new object data to device, hr = 0x%lx\n", hr); } } } }