다음을 통해 공유


여러 개체에 대한 속성 설정

일부 디바이스 드라이버는 단일 함수 호출에서 여러 개체에 대한 설정 속성을 지원합니다. 이를 대량 쓰기라고 합니다. 애플리케이션은 다음 표에 설명된 인터페이스를 사용하여 대량 쓰기를 수행할 수 있습니다.

인터페이스 Description
IPortableDeviceContent 인터페이스 콘텐츠별 메서드에 대한 액세스를 제공합니다.
IPortableDeviceProperties 인터페이스 속성별 메서드에 대한 액세스를 제공합니다.
IPortableDevicePropertiesBulk 인터페이스 대량 쓰기 작업을 지원합니다.
IPortableDevicePropVariantCollection 인터페이스 대량 작업에 대한 개체 식별자를 저장하는 데 사용됩니다.
IPortableDeviceValuesCollection 인터페이스 작성할 속성을 식별하는 데 사용됩니다.

 

샘플 애플리케이션의 ContentProperties.cpp 모듈의 함수는 WriteContentPropertiesBulk 대량 쓰기 작업을 보여 줍니다.

이 샘플에서 수행된 첫 번째 작업은 지정된 드라이버가 대량 작업을 지원하는지 여부를 결정하는 것입니다. 이 작업은 IPortableDeviceProperties 개체에서 QueryInterface를 호출하고 IPortableDevicePropertiesBulk의 존재를 확인하여 수행됩니다.

HRESULT                                       hr                = S_OK;
GUID                                          guidContext       = GUID_NULL;
CSetBulkValuesCallback*                       pCallback         = NULL;
CComPtr<IPortableDeviceProperties>            pProperties;
CComPtr<IPortableDevicePropertiesBulk>        pPropertiesBulk;
CComPtr<IPortableDeviceValues>                pObjectProperties;
CComPtr<IPortableDeviceContent>               pContent;
CComPtr<IPortableDeviceValuesCollection>      pPropertiesToWrite;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
DWORD                                         cObjectIDs        = 0;
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->Properties(&pProperties);
    if (FAILED(hr))
    {
        printf("! Failed to get IPortableDeviceProperties from IPortableDevice, hr = 0x%lx\n",hr);
    }
}



if (SUCCEEDED(hr))
{
    hr = pProperties->QueryInterface(IID_PPV_ARGS(&pPropertiesBulk));
    if (FAILED(hr))
    {
        printf("This driver does not support BULK property operations.\n");
    }
}

다음 작업에서는 IPortableDeviceValuesCollection 개체를 만들어야 합니다. 샘플에서 쓸 속성 값이 들어 있는 개체입니다.

HRESULT                                       hr                = S_OK;
GUID                                          guidContext       = GUID_NULL;
CSetBulkValuesCallback*                       pCallback         = NULL;
CComPtr<IPortableDeviceProperties>            pProperties;
CComPtr<IPortableDevicePropertiesBulk>        pPropertiesBulk;
CComPtr<IPortableDeviceValues>                pObjectProperties;
CComPtr<IPortableDeviceContent>               pContent;
CComPtr<IPortableDeviceValuesCollection>      pPropertiesToWrite;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
DWORD                                         cObjectIDs        = 0;
if (SUCCEEDED(hr))
{
    hr = CoCreateInstance(CLSID_PortableDeviceValuesCollection,
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          IID_IPortableDeviceValuesCollection,
                          (VOID**) &pPropertiesToWrite);
    if (FAILED(hr))
    {
        printf("! Failed to CoCreate IPortableDeviceValuesCollection for bulk property values, hr = 0x%lx\n", hr);
    }
}

이 후 샘플은 IPortableDevicePropertiesBulkCallback 인터페이스의 instance 만듭니다. 애플리케이션은 이 인터페이스의 메서드를 사용하여 비동기 대량 쓰기 작업의 진행률을 추적합니다.

HRESULT                                       hr                = S_OK;
GUID                                          guidContext       = GUID_NULL;
CSetBulkValuesCallback*                       pCallback         = NULL;
CComPtr<IPortableDeviceProperties>            pProperties;
CComPtr<IPortableDevicePropertiesBulk>        pPropertiesBulk;
CComPtr<IPortableDeviceValues>                pObjectProperties;
CComPtr<IPortableDeviceContent>               pContent;
CComPtr<IPortableDeviceValuesCollection>      pPropertiesToWrite;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
DWORD                                         cObjectIDs        = 0;
if (SUCCEEDED(hr))
{
    pCallback = new CSetBulkValuesCallback();
    if (pCallback == NULL)
    {
        hr = E_OUTOFMEMORY;
        printf("! Failed to allocate CSetBulkValuesCallback, hr = 0x%lx\n", hr);
    }
}

샘플 애플리케이션에서 호출하는 다음 함수는 도우미 함수입니다 CreateIPortableDevicePropVariantCollectionWithAllObjectIDs . 이 함수는 지정된 디바이스의 모든 개체를 재귀적으로 열거하고 찾은 각 개체에 대한 식별자가 포함된 IPortableDevicePropVariantCollection 인터페이스 를 반환합니다. 이 함수는 ContentEnumeration.cpp 모듈에 정의되어 있습니다.

// 7) Call our helper function CreateIPortableDevicePropVariantCollectionWithAllObjectIDs
// to enumerate and create an IPortableDevicePropVariantCollection with the object
// identifiers needed to perform the bulk operation on.
if (SUCCEEDED(hr))
{
    hr = CreateIPortableDevicePropVariantCollectionWithAllObjectIDs(pDevice,
                                                                    pContent,
                                                                    &pObjectIDs);
}

IPortableDevicePropVariantCollection 개체는 동일한 VARTYPE의 인덱싱된 PROPVARIANT 값 컬렉션을 보유합니다. 이 경우 이러한 값에는 디바이스에 있는 각 개체에 대해 지정된 개체 식별자가 포함됩니다.

개체 식별자와 해당 이름 속성은 IPortableDeviceValuesCollection 개체에 저장됩니다. 이름 속성은 첫 번째 개체에 "NewName0"의 이름 속성이 할당되고, 두 번째 개체에는 "NewName1" 등의 이름 속성이 할당되도록 구성됩니다.

샘플에서 발췌한 다음 예제에서는 개체 식별자 및 새 이름 문자열을 사용하여 IPortableDeviceValuesCollection 개체를 초기화하는 방법을 보여 줍니다.

HRESULT                                       hr                = S_OK;
GUID                                          guidContext       = GUID_NULL;
CSetBulkValuesCallback*                       pCallback         = NULL;
CComPtr<IPortableDeviceProperties>            pProperties;
CComPtr<IPortableDevicePropertiesBulk>        pPropertiesBulk;
CComPtr<IPortableDeviceValues>                pObjectProperties;
CComPtr<IPortableDeviceContent>               pContent;
CComPtr<IPortableDeviceValuesCollection>      pPropertiesToWrite;
CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
DWORD                                         cObjectIDs        = 0;
if (SUCCEEDED(hr))
{
    hr = pObjectIDs->GetCount(&cObjectIDs);
    if (FAILED(hr))
    {
        printf("! Failed to get number of objectIDs from IPortableDevicePropVariantCollection, hr = 0x%lx\n", hr);
    }
}


if (SUCCEEDED(hr))
{
    for(DWORD dwIndex = 0; (dwIndex < cObjectIDs) && (hr == S_OK); dwIndex++)
    {
        CComPtr<IPortableDeviceValues>  pValues;
        PROPVARIANT                     pv = {0};

        PropVariantInit(&pv);
        hr = CoCreateInstance(CLSID_PortableDeviceValues,
                              NULL,
                              CLSCTX_INPROC_SERVER,
                              IID_IPortableDeviceValues,
                              (VOID**) &pValues);
        if (FAILED(hr))
        {
            printf("! Failed to CoCreate CLSID_PortableDeviceValues, hr = 0x%lx\n", hr);
        }

        // Get the Object ID whose properties we will set
        if (hr == S_OK)
        {
            hr = pObjectIDs->GetAt(dwIndex, &pv);
            if (FAILED(hr))
            {
                printf("! Failed to get next Object ID from list, hr = 0x%lx\n", hr);
            }
        }

        // Save them into the IPortableDeviceValues so the driver knows which object this proeprty set belongs to
        if (hr == S_OK)
        {
            hr = pValues->SetStringValue(WPD_OBJECT_ID, pv.pwszVal);
            if (FAILED(hr))
            {
                printf("! Failed to set WPD_OBJECT_ID, hr = 0x%lx\n", hr);
            }
        }

        // Set the new values.  In this sample, we attempt to set the name property.
        if (hr == S_OK)
        {
            CAtlStringW strValue;
            strValue.Format(L"NewName%d", dwIndex);

            hr = pValues->SetStringValue(WPD_OBJECT_NAME, strValue.GetString());
            if (FAILED(hr))
            {
                printf("! Failed to set WPD_OBJECT_NAME, hr = 0x%lx\n", hr);
            }
        }

        // Add this property set to the collection
        if (hr == S_OK)
        {
            hr = pPropertiesToWrite->Add(pValues);
            if (FAILED(hr))
            {
                printf("! Failed to add values to collection, hr = 0x%lx\n", hr);
            }
        }
        PropVariantClear(&pv);
    }
}

샘플이 개체 식별자와 이름 쌍을 포함하는 IPortableDeviceValuesCollection 개체를 만들면 비동기 작업을 시작할 수 있습니다.

비동기 쓰기 작업은 샘플이 IPortableDevicePropertiesBulk::QueueSetValuesByObjectList 메서드를 호출할 때 시작됩니다. 이 메서드는 대량 작업이 시작된다는 것을 드라이버에 알 수 있습니다. 그런 다음 샘플은 IPortableDeviceBulk::Start 메서드를 호출하여 실제로 새 이름 값 작성을 시작합니다.

   HRESULT                                       hr                = S_OK;
   GUID                                          guidContext       = GUID_NULL;
   CSetBulkValuesCallback*                       pCallback         = NULL;
   CComPtr<IPortableDeviceProperties>            pProperties;
   CComPtr<IPortableDevicePropertiesBulk>        pPropertiesBulk;
   CComPtr<IPortableDeviceValues>                pObjectProperties;
   CComPtr<IPortableDeviceContent>               pContent;
   CComPtr<IPortableDeviceValuesCollection>      pPropertiesToWrite;
   CComPtr<IPortableDevicePropVariantCollection> pObjectIDs;
   DWORD                                         cObjectIDs        = 0;
   if (SUCCEEDED(hr))
   {
       hr = pPropertiesBulk->QueueSetValuesByObjectList(pPropertiesToWrite,
                                                        pCallback,
                                                        &guidContext);


       if(SUCCEEDED(hr))
       {
           // Cleanup any previously created global event handles.
           if (g_hBulkPropertyOperationEvent != NULL)
           {
               CloseHandle(g_hBulkPropertyOperationEvent);
               g_hBulkPropertyOperationEvent = NULL;
           }

           // In order to create a simpler to follow example we create and wait infinitly
           // for the bulk property operation to complete and ignore any errors.
           // Production code should be written in a more robust manner.
           // Create the global event handle to wait on for the bulk operation
           // to complete.
           g_hBulkPropertyOperationEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
           if (g_hBulkPropertyOperationEvent != NULL)
           {
               // Call Start() to actually being the Asynchronous bulk operation.
               hr = pPropertiesBulk->Start(guidContext);
               if(FAILED(hr))
               {
                   printf("! Failed to start property operation, hr = 0x%lx\n", hr);
               }
           }
           else
           {
               printf("! Failed to create the global event handle to wait on for the bulk operation. Aborting operation.\n");
           }
       }
       else
       {
           printf("! QueueSetValuesByObjectList Failed, hr = 0x%lx\n", hr);
       }
   }

샘플은 작업이 완료되기까지 무한히 긴 시간을 기다립니다. 프로덕션 애플리케이션인 경우 코드를 수정해야 합니다.

IPortableDevice 인터페이스

IPortableDeviceContent 인터페이스

IPortableDeviceProperties 인터페이스

IPortableDevicePropertiesBulk 인터페이스

IPortableDevicePropVariantCollection 인터페이스

프로그래밍 가이드