개체에 리소스 추가
개체를 디바이스로 전송하는 것 외에도 개체에 리소스를 추가할 수도 있습니다. 예를 들어 애플리케이션은 지정된 연락처의 기존 정보에 사진을 추가할 수 있습니다.
리소스는 다음 표에 설명된 인터페이스를 사용하여 추가됩니다.
인터페이스 | Description |
---|---|
IPortableDeviceContent 인터페이스 | 콘텐츠별 메서드에 대한 액세스를 제공합니다. |
IPortableDeviceResources 인터페이스 | 디바이스에 리소스 속성 및 데이터를 쓸 때 사용됩니다. |
IPortableDeviceValues 인터페이스 | 리소스를 설명하는 속성을 작성하는 데 사용됩니다. |
IStream 인터페이스 | 디바이스에 리소스 작성을 간소화하는 데 사용됩니다. |
샘플 애플리케이션의 ContentTransfer.cpp 모듈에 있는 CreateContactPhotoResourceOnDevice 함수는 애플리케이션이 연락처 개체에 사진 리소스를 추가하는 방법을 보여 줍니다. 이 함수는 사용자에게 사진 리소스가 추가될 디바이스의 연락처 개체 식별자를 묻는 메시지를 표시합니다. 그런 다음 사용자가 추가할 이미지를 선택할 수 있도록 FileOpen 대화 상자를 표시합니다. 이 데이터가 수집되면 애플리케이션은 리소스를 디바이스에 씁니다.
CreateContactPhotoResourceOnDevice 함수에서 수행한 첫 번째 작업은 사용자에게 사진이 추가될 연락처의 개체 식별자를 입력하라는 메시지를 표시하는 것입니다.
HRESULT hr = S_OK;
WCHAR wszSelection[81] = {0};
WCHAR wszFilePath[MAX_PATH] = {0};
DWORD cbOptimalTransferSize = 0;
CComPtr<IStream> pFileStream;
CComPtr<IStream> pResourceStream;
CComPtr<IPortableDeviceValues> pResourceAttributes;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceResources> pResources;
printf("Enter the identifer of the object to which we will add an Audio annotation.\n>");
hr = StringCbGetsW(wszSelection,sizeof(wszSelection));
if (FAILED(hr))
{
printf("An invalid object identifier was specified, aborting resource creation\n");
}do
다음 단계는 IPortableDeviceContent 개체를 검색하는 것입니다. 이 개체는 IPortableDeviceResources 개체를 가져오는 데 사용됩니다. (애플리케이션은 이 후자의 개체를 사용하여 새 리소스를 만들고 작성합니다.)
HRESULT hr = S_OK;
WCHAR wszSelection[81] = {0};
WCHAR wszFilePath[MAX_PATH] = {0};
DWORD cbOptimalTransferSize = 0;
CComPtr<IStream> pFileStream;
CComPtr<IStream> pResourceStream;
CComPtr<IPortableDeviceValues> pResourceAttributes;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceResources> pResources;
if (SUCCEEDED(hr))
{
hr = pDevice->Content(&pContent);
if (FAILED(hr))
{
printf("! Failed to get IPortableDeviceContent from IPortableDevice, hr = 0x%lx\n",hr);
}
}
if (SUCCEEDED(hr))
{
hr = pContent->Transfer(&pResources);
if (FAILED(hr))
{
printf("! Failed to get IPortableDeviceResources from IPortableDeviceContent, hr = 0x%lx\n",hr);
}
}
그런 다음 샘플에는 사용자가 연락처 정보에 추가할 사진이 포함된 이미지 파일의 이름을 지정할 수 있는 FileOpen 대화 상자가 표시됩니다.
HRESULT hr = S_OK;
WCHAR wszSelection[81] = {0};
WCHAR wszFilePath[MAX_PATH] = {0};
DWORD cbOptimalTransferSize = 0;
CComPtr<IStream> pFileStream;
CComPtr<IStream> pResourceStream;
CComPtr<IPortableDeviceValues> pResourceAttributes;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceResources> pResources;
if (SUCCEEDED(hr))
{
OPENFILENAME OpenFileNameInfo = {0};
OpenFileNameInfo.lStructSize = sizeof(OPENFILENAME);
OpenFileNameInfo.hwndOwner = NULL;
OpenFileNameInfo.lpstrFile = wszFilePath;
OpenFileNameInfo.nMaxFile = ARRAYSIZE(wszFilePath);
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)
{
printf("The transfer operation was cancelled.\n");
hr = E_ABORT;
}
}
샘플에 IPortableDeviceResources 개체와 이미지 파일의 이름이 있으면 실제로 디바이스로 데이터를 전송하기 위한 준비에서 다음을 수행합니다.
- 선택한 파일에서 읽기 작업을 위해 IStream 개체를 엽니다.
- 이미지 크기 및 형식과 같은 정보를 포함하는 IPortableDeviceValues 개체를 만듭니다.
HRESULT hr = S_OK;
WCHAR wszSelection[81] = {0};
WCHAR wszFilePath[MAX_PATH] = {0};
DWORD cbOptimalTransferSize = 0;
CComPtr<IStream> pFileStream;
CComPtr<IStream> pResourceStream;
CComPtr<IPortableDeviceValues> pResourceAttributes;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceResources> pResources;
if (SUCCEEDED(hr))
{
// Open the selected file as an IStream. This will simplify reading the
// data and writing to the device.
hr = SHCreateStreamOnFile(wszFilePath, STGM_READ, &pFileStream);
if (SUCCEEDED(hr))
{
// CoCreate the IPortableDeviceValues to hold the resource attributes
hr = CoCreateInstance(CLSID_PortableDeviceValues,
NULL,
CLSCTX_INPROC_SERVER,
IID_IPortableDeviceValues,
(VOID**) &pResourceAttributes);
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 = pResourceAttributes->SetStringValue(WPD_OBJECT_ID, wszSelection);
if (FAILED(hr))
{
printf("! 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 = pResourceAttributes->SetKeyValue(WPD_RESOURCE_ATTRIBUTE_RESOURCE_KEY, WPD_RESOURCE_CONTACT_PHOTO);
if (FAILED(hr))
{
printf("! 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 = pFileStream->Stat(&statstg, STATFLAG_NONAME);
if (SUCCEEDED(hr))
{
hr = pResourceAttributes->SetUnsignedLargeIntegerValue(WPD_RESOURCE_ATTRIBUTE_TOTAL_SIZE, statstg.cbSize.QuadPart);
if (FAILED(hr))
{
printf("! Failed to set WPD_RESOURCE_ATTRIBUTE_TOTAL_SIZE, hr = 0x%lx\n",hr);
}
}
else
{
printf("! Failed to get file's total size, hr = 0x%lx\n",hr);
}
}
// Set the WPD_RESOURCE_ATTRIBUTE_FORMAT to WPD_OBJECT_FORMAT_JFIF because we are
// creating a contact photo resource with JPG image data.
if (SUCCEEDED(hr))
{
hr = pResourceAttributes->SetGuidValue(WPD_RESOURCE_ATTRIBUTE_FORMAT, WPD_OBJECT_FORMAT_JFIF);
if (FAILED(hr))
{
printf("! Failed to set WPD_RESOURCE_ATTRIBUTE_FORMAT to WPD_OBJECT_FORMAT_JFIF, hr = 0x%lx\n",hr);
}
}
}
}
if (FAILED(hr))
{
printf("! Failed to open file named (%ws) to transfer to device, hr = 0x%lx\n",wszFilePath, hr);
}
}
쓰기 작업을 위해 IStream 및 IPortableDeviceValues 개체를 준비한 후 샘플은 이미지를 디바이스로 전송합니다. 샘플은 다음과 같이 세 단계로 전송을 완료합니다.
- IPortableDeviceResources::CreateResource 메서드를 호출하여 디바이스에 리소스를 만듭니다.
- StreamCopy 도우미 함수를 호출하여 원본 스트림을 대상 스트림에 복사합니다.
- IPortableDeviceDataStream::Commit 메서드를 호출하여 전송이 완료되었다는 것을 디바이스 드라이버에 알릴 수 있습니다.
HRESULT hr = S_OK;
WCHAR wszSelection[81] = {0};
WCHAR wszFilePath[MAX_PATH] = {0};
DWORD cbOptimalTransferSize = 0;
CComPtr<IStream> pFileStream;
CComPtr<IStream> pResourceStream;
CComPtr<IPortableDeviceValues> pResourceAttributes;
CComPtr<IPortableDeviceContent> pContent;
CComPtr<IPortableDeviceResources> pResources;
if (SUCCEEDED(hr))
{
hr = pResources->CreateResource(pResourceAttributes, // Properties describing this resource
&pResourceStream, // Returned resource data stream (to transfer the data to)
&cbOptimalTransferSize, // Returned optimal buffer size to use during transfer
NULL);
// 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(pResourceStream, // Destination (The resource 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 = pResourceStream->Commit(0);
if (FAILED(hr))
{
printf("! Failed to commit resource to device, hr = 0x%lx\n",hr);
}
}
}
관련 항목