다음을 통해 공유


DevCreateObjectQuery 함수(devquery.h)

지정된 쿼리 매개 변수를 기반으로 속성을 검색하는 디바이스 쿼리를 만듭니다.

통사론

HRESULT DevCreateObjectQuery(
  [in]           DEV_OBJECT_TYPE                 ObjectType,
  [in]           ULONG                           QueryFlags,
  [in]           ULONG                           cRequestedProperties,
  [in]           const DEVPROPCOMPKEY            *pRequestedProperties,
  [in]           ULONG                           cFilterExpressionCount,
  [in, optional] const DEVPROP_FILTER_EXPRESSION *pFilter,
  [in]           PDEV_QUERY_RESULT_CALLBACK      pCallback,
  [in, optional] PVOID                           pContext,
  [out]          PHDEVQUERY                      phDevQuery
);

매개 변수

[in] ObjectType

이 쿼리가 작동해야 하는 개체 형식을 결정하는 DEV_OBJECT_TYPE 열거형의 값입니다.

[in] QueryFlags

비트 OR 연산을 사용하여 결합된 DEV_QUERY_FLAGS 값의 조합입니다.

[in] cRequestedProperties

pRequestedProperties제공된 DEVPROPCOMPKEY 구조의 수입니다. DevQueryFlagAllProperties 지정한 경우 0으로 설정해야 합니다.

[in] pRequestedProperties

필요에 따라 pCallback 호출될 때 쿼리 결과 집합의 개체에 대해 검색해야 하는 속성을 지정하는 DEVPROPCOMPKEY 구조체의 배열을 제공하여 결과 집합에 개체가 추가되었음을 쿼리에 알립니다.
DevQueryFlagUpdateResultsQueryFlags지정한 경우 쿼리의 결과 집합에 있는 개체에 대해 이러한 속성 값이 변경되면 쿼리에 알림이 표시됩니다.

DEVPROPCOMPKEY 구조체의 LocaleName 필드는 무시되며 NULL로 설정해야 합니다.

cRequestedProperties 0이면 NULL이어야 합니다.

[in] cFilterExpressionCount

pFilter제공된 DEVPROP_FILTER_EXPRESSION 구조체의 수입니다.

[in, optional] pFilter

필요에 따라 쿼리 결과 집합의 일부여야 하는 개체에 대한 필터 조건을 지정하는 DEVPROP_FILTER_EXPRESSION 구조의 배열을 제공합니다. cFilterExpressionCount 0이면 NULL이어야 합니다.

[in] pCallback

이 쿼리의 결과를 나타내는 PDEV_QUERY_RESULT_CALLBACK 콜백 함수를 보내야 합니다.

[in, optional] pContext

호출자가 제공한 컨텍스트입니다. 이 값은 수정되지 않은 콜백 함수에 전달됩니다.

[out] phDevQuery

쿼리를 나타내는 핸들을 받는 포인터입니다. DevQueryFlagsUpdateResults 지정한 경우 쿼리는 핸들이 닫힙니다. DevCloseObjectQuery 호출하여 이 핸들을 닫아 쿼리를 중지합니다.

반환 값

쿼리가 성공적으로 만들어진 경우 S_OK 반환됩니다. 그렇지 않으면 적절한 오류 값입니다.

발언

DevCreateObjectQuery 사용하여 지정된 DEV_OBJECT_TYPE대한 데이터를 쿼리합니다. 개체는 개체 형식, 문자열 ID 및 키/값 쌍의 속성 저장소로 표시됩니다. 각 쿼리에는 연결된 결과 집합이 있습니다. 개체는 시스템 상태 및 변경 내용에 따라 결과 집합에서 추가, 업데이트 또는 제거되며 연결된 콜백 함수에 알림이 표시됩니다. 콜백 함수에 대한 각 호출은 콜백이 호출될 때 속성 값의 스냅샷을 나타냅니다. pFilter 식에 표현된 조건과 일치하는 개체만 호출자에게 반환됩니다. 결과 집합을 업데이트하는 콜백 호출 외에도 클라이언트에 쿼리 상태에 대한 변경 내용을 알리는 상태 변경 콜백도 있습니다.

기본적으로 쿼리는 시스템의 현재 상태가 처리된 후에 업데이트를 받지 않습니다. 일치하는 모든 개체가 결과 집합에 추가되면 쿼리는 DevQueryStateEnumCompleted 상태가 되며 추가 콜백이 생성되지 않습니다. 쿼리가 DevQueryFlagUpdateResults 플래그를 지정하여 업데이트를 등록하면 해당 결과 집합이 계속 업데이트되고 관련 콜백이 알림을 받습니다. 쿼리가 DevQueryStateEnumCompleted 상태가 되면 필터 식 일치에 따라 개체를 추가하거나 제거하는 작업이 수행됩니다.

쿼리가 중단될 수 있습니다. 이 오류는 클라이언트에 알림을 전달할 수 없는 내부 오류가 발생할 때 발생합니다. 예를 들어 시스템이 메모리 부족 상태일 때 발생할 수 있습니다. 이 경우 호출자의 결과 집합은 더 이상 쿼리 상태의 실제 표현을 반영하지 않습니다. 호출자는 DevQueryStateAborted 콜백을 받습니다. 추가 콜백은 수신되지 않습니다. 호출자는 쿼리를 닫고 이 조건에서 복구할 새 쿼리를 만들어야 합니다.

예제

다음 예제에서는 쿼리 상태가 변경되거나 항목이 쿼리 결과에 추가, 업데이트 또는 제거될 때 상태 메시지를 출력하기 위해 PDEV_QUERY_RESULT_CALLBACK 메서드가 구현됩니다. 다음으로, DevCreateObjectQueryDEVPROPCOMPKEY 배열과 값이 GUID_DEVCLASS_NETDEVPKEY_Device_ClassGuid 속성이 있는 DevObjectTypeDevice 개체를 쿼리하는 DEVPROP_FILTER_EXPRESSION 사용하여 호출되는 간단한 쿼리 시나리오가 구현됩니다.

void WINAPI
Example1Callback(
    HDEVQUERY hDevQuery,
    PVOID pContext,
    const DEV_QUERY_RESULT_ACTION_DATA *pActionData
    )
{
    const DEVPROPERTY* NameProperty = NULL;

    UNREFERENCED_PARAMETER(hDevQuery);
    UNREFERENCED_PARAMETER(pContext);

    switch (pActionData->Action)
    {
    case DevQueryResultStateChange:
        if (pActionData->Data.State == DevQueryStateEnumCompleted)
        {
            wprintf(L"Enumeration of current system state complete.\n");
        }
        else if (pActionData->Data.State == DevQueryStateAborted)
        {
            wprintf(L"Query has aborted. No further results will be received.\n");
            // Communicate back to the creator of the query that it has aborted
            // so it can handle that appropriately, such as by recreating the
            // query
        }
        break;

    case DevQueryResultAdd:
        wprintf(L"Object '%ws' has been added to the result set.\n",
                pActionData->Data.DeviceObject.pszObjectId);

        NameProperty = DevFindProperty(&DEVPKEY_NAME,
                                       DEVPROP_STORE_SYSTEM,
                                       NULL,
                                       pActionData->Data.DeviceObject.cPropertyCount,
                                       pActionData->Data.DeviceObject.pProperties);

        if ((NameProperty == NULL) ||
            (NameProperty->Type == DEVPROP_TYPE_EMPTY) ||
            (NameProperty->Buffer == NULL))
        {
            wprintf(L"Object '%ws' had no name property.\n",
                    pActionData->Data.DeviceObject.pszObjectId);
        }
        else if ((NameProperty->Type != DEVPROP_TYPE_STRING) ||
                 (NameProperty->BufferSize < sizeof(WCHAR)))
        {
            wprintf(L"Object '%ws' had a corrupted name property.\n",
                    pActionData->Data.DeviceObject.pszObjectId);
        }
        else
        {
            wprintf(L"Object '%ws' has name '%ws'.\n",
                    pActionData->Data.DeviceObject.pszObjectId,
                    (PWSTR)NameProperty->Buffer);
        }

        break;

    case DevQueryResultUpdate:
        wprintf(L"Object '%ws' was updated.\n",
                pActionData->Data.DeviceObject.pszObjectId);

        NameProperty = DevFindProperty(&DEVPKEY_NAME,
                                       DEVPROP_STORE_SYSTEM,
                                       NULL,
                                       pActionData->Data.DeviceObject.cPropertyCount,
                                       pActionData->Data.DeviceObject.pProperties);

        if ((NameProperty == NULL) ||
            (NameProperty->Type == DEVPROP_TYPE_EMPTY) ||
            (NameProperty->Buffer == NULL))
        {
            wprintf(L"Object '%ws' had no name property.\n",
                    pActionData->Data.DeviceObject.pszObjectId);
        }
        else if ((NameProperty->Type != DEVPROP_TYPE_STRING) ||
                 (NameProperty->BufferSize < sizeof(WCHAR)))
        {
            wprintf(L"Object '%ws' had a corrupted name property.\n",
                    pActionData->Data.DeviceObject.pszObjectId);
        }
        else
        {
            wprintf(L"Object '%ws' has name '%ws'.\n",
                    pActionData->Data.DeviceObject.pszObjectId,
                    (PWSTR)NameProperty->Buffer);
        }

        break;

    case DevQueryResultRemove:
        wprintf(L"Object '%ws' has been removed from the result set.\n",
                pActionData->Data.DeviceObject.pszObjectId);
        break;
    }
}

void
Example1()
{
    DEVPROPCOMPKEY RequestedProperties[] =
    {
        { DEVPKEY_NAME, DEVPROP_STORE_SYSTEM, NULL }
    };
    DEVPROP_FILTER_EXPRESSION ObjectFilter[] =
    {
        {
            DEVPROP_OPERATOR_EQUALS,
            {
                { DEVPKEY_Device_ClassGuid, DEVPROP_STORE_SYSTEM, NULL },
                DEVPROP_TYPE_GUID,
                sizeof(GUID),
                (void*)&GUID_DEVCLASS_NET
            }
        }
    };

    HDEVQUERY hDevQuery = NULL;
    HRESULT hr = DevCreateObjectQuery(DevObjectTypeDevice,
                                      DevQueryFlagUpdateResults,
                                      RTL_NUMBER_OF(RequestedProperties),
                                      RequestedProperties,
                                      RTL_NUMBER_OF(ObjectFilter),
                                      ObjectFilter,
                                      Example1Callback,
                                      NULL,
                                      &hDevQuery);

    if (FAILED(hr))
    {
        wprintf(L"Failed to create query. hr = 0x%08x\n", hr);
        goto exit;
    }

    // do other work while the query monitors system state in the background

  exit:

    if (hDevQuery != NULL)
    {
        DevCloseObjectQuery(hDevQuery);
    }

    return;
}

다음 예제에서는 선택적 호출자 정의 pContext 매개 변수를 사용하여 이벤트 핸들을 PDEV_QUERY_RESULT_CALLBACK 메서드에 전달합니다. 콜백에서 쿼리 상태가 DevQueryStateAborted감지되면 이벤트는 기존 쿼리를 삭제하고 새 쿼리를 다시 만들어야 한다는 신호를 호출자에게 알립니다.

typedef struct _MY_QUERY_CONTEXT {
    HANDLE CompletionEvent;
    HRESULT hr;
} MY_QUERY_CONTEXT, *PMY_QUERY_CONTEXT;

void WINAPI
Example2Callback(
    HDEVQUERY hDevQuery,
    PVOID pContext,
    const DEV_QUERY_RESULT_ACTION_DATA *pActionData
    )
{
    PMY_QUERY_CONTEXT QueryContext = (PMY_QUERY_CONTEXT)pContext;
    const DEVPROPERTY* DevProperty = NULL;

    UNREFERENCED_PARAMETER(hDevQuery);

    switch (pActionData->Action)
    {
    case DevQueryResultStateChange:
        if (pActionData->Data.State == DevQueryStateEnumCompleted)
        {
            wprintf(L"Enumeration of current system state complete.\n");
            // The query did not use DevQueryFlagUpdateResults so the result set
            // is now complete. Signal the caller to stop waiting.
            if (!SetEvent(QueryContext->CompletionEvent))
            {
                wprintf(L"Failed to signal completion event. Err = 0x%08x\n",
                        GetLastError());
            }
        }
        else if (pActionData->Data.State == DevQueryStateAborted)
        {
            wprintf(L"Query has aborted. No further results will be received.\n");
            QueryContext->hr = E_FAIL;
            // Communicate back to the creator of the query that it has aborted
            // so it can handle that appropriately, such as by recreating the
            // query.
            if (!SetEvent(QueryContext->CompletionEvent))
            {
                wprintf(L"Failed to signal completion event. Err = 0x%08x\n",
                        GetLastError());
            }
        }
        break;

    case DevQueryResultAdd:
        wprintf(L"Object '%ws' has been added to the result set.\n",
                pActionData->Data.DeviceObject.pszObjectId);

        DevProperty = DevFindProperty(&DEVPKEY_Device_InstanceId,
                                      DEVPROP_STORE_SYSTEM,
                                      NULL,
                                      pActionData->Data.DeviceObject.cPropertyCount,
                                      pActionData->Data.DeviceObject.pProperties);

        if ((DevProperty == NULL) ||
            (DevProperty->Type == DEVPROP_TYPE_EMPTY) ||
            (DevProperty->Buffer == NULL))
        {
            wprintf(L"Object '%ws' had no instance ID property.\n",
                    pActionData->Data.DeviceObject.pszObjectId);
        }
        else if ((DevProperty->Type != DEVPROP_TYPE_STRING) ||
                 (DevProperty->BufferSize < sizeof(WCHAR)))
        {
            wprintf(L"Object '%ws' had a corrupted instance ID property.\n",
                    pActionData->Data.DeviceObject.pszObjectId);
        }
        else
        {
            wprintf(L"Object '%ws' was exposed by instance ID '%ws'.\n",
                    pActionData->Data.DeviceObject.pszObjectId,
                    (PWSTR)DevProperty->Buffer);
        }

        break;

    case DevQueryResultUpdate:
        wprintf(L"Object '%ws' was updated.\n",
                pActionData->Data.DeviceObject.pszObjectId);

        DevProperty = DevFindProperty(&DEVPKEY_Device_InstanceId,
                                      DEVPROP_STORE_SYSTEM,
                                      NULL,
                                      pActionData->Data.DeviceObject.cPropertyCount,
                                      pActionData->Data.DeviceObject.pProperties);

        if ((DevProperty == NULL) ||
            (DevProperty->Type == DEVPROP_TYPE_EMPTY) ||
            (DevProperty->Buffer == NULL))
        {
            wprintf(L"Object '%ws' had no instance ID property.\n",
                    pActionData->Data.DeviceObject.pszObjectId);
        }
        else if ((DevProperty->Type != DEVPROP_TYPE_STRING) ||
                 (DevProperty->BufferSize < sizeof(WCHAR)))
        {
            wprintf(L"Object '%ws' had a corrupted instance ID property.\n",
                    pActionData->Data.DeviceObject.pszObjectId);
        }
        else
        {
            wprintf(L"Object '%ws' was exposed by instance ID '%ws'.\n",
                    pActionData->Data.DeviceObject.pszObjectId,
                    (PWSTR)DevProperty->Buffer);
        }

        break;

    case DevQueryResultRemove:
        wprintf(L"Object '%ws' has been removed from the result set.\n",
                pActionData->Data.DeviceObject.pszObjectId);
        break;
    }
}

void
Example2()
{
    HRESULT hr = S_OK;
    MY_QUERY_CONTEXT QueryContext = {0};
    HDEVQUERY hDevQuery = NULL;
    DEVPROP_BOOLEAN DevPropTrue = DEVPROP_TRUE;
    DEVPROPCOMPKEY RequestedProperties[] =
    {
        { DEVPKEY_Device_InstanceId, DEVPROP_STORE_SYSTEM, NULL }
    };
    DEVPROP_FILTER_EXPRESSION ObjectFilter[] =
    {
        {
            DEVPROP_OPERATOR_AND_OPEN, {0}
        },
        {
            DEVPROP_OPERATOR_EQUALS,
            {
                { DEVPKEY_DeviceInterface_Enabled, DEVPROP_STORE_SYSTEM, NULL },
                DEVPROP_TYPE_BOOLEAN,
                sizeof(DevPropTrue),
                (void*)&DevPropTrue
            }
        },
        {
            DEVPROP_OPERATOR_OR_OPEN, {0}
        },
        {
            DEVPROP_OPERATOR_EQUALS,
            {
                { DEVPKEY_DeviceInterface_ClassGuid, DEVPROP_STORE_SYSTEM, NULL },
                DEVPROP_TYPE_GUID,
                sizeof(GUID),
                (void*)&GUID_DEVINTERFACE_MOUSE
            }
        },
        {
            DEVPROP_OPERATOR_EQUALS,
            {
                { DEVPKEY_DeviceInterface_ClassGuid, DEVPROP_STORE_SYSTEM, NULL },
                DEVPROP_TYPE_GUID,
                sizeof(GUID),
                (void*)&GUID_DEVINTERFACE_KEYBOARD
            }
        },
        {
            DEVPROP_OPERATOR_OR_CLOSE, {0}
        },
        {
            DEVPROP_OPERATOR_AND_CLOSE, {0}
        }
    };

    QueryContext.CompletionEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    if (!QueryContext.CompletionEvent)
    {
        wprintf(L"Failed to create event. Error = 0x%08x\n",
                GetLastError());
        goto exit;
    }

    hr = DevCreateObjectQuery(DevObjectTypeDeviceInterface,
                              DevQueryFlagNone,
                              RTL_NUMBER_OF(RequestedProperties),
                              RequestedProperties,
                              RTL_NUMBER_OF(ObjectFilter),
                              ObjectFilter,
                              Example2Callback,
                              &QueryContext,
                              &hDevQuery);

    if (FAILED(hr))
    {
        wprintf(L"Failed to create query. hr = 0x%08x\n", hr);
        goto exit;
    }

    switch (WaitForSingleObject(QueryContext.CompletionEvent, INFINITE))
    {
    case WAIT_OBJECT_0:
        if (SUCCEEDED(QueryContext.hr))
        {
            wprintf(L"Successfully enumerated results.\n");
        }
        else
        {
            wprintf(L"Failed to Successfully enumerate results. hr = 0x%08x\n",
                    QueryContext.hr);
        }
        break;

    default:
        wprintf(L"An error waiting occurred.\n");
        break;
    }

  exit:

    if (hDevQuery != NULL)
    {
        DevCloseObjectQuery(hDevQuery);
    }

    if (QueryContext.CompletionEvent != NULL)
    {
        CloseHandle(QueryContext.CompletionEvent);
    }

    return;
}

요구 사항

요구
지원되는 최소 클라이언트 Windows 10 버전 1809
지원되는 최소 서버 Windows Server 2019
헤더 devquery.h
라이브러리 onecore.lib
DLL Cfgmgr32.dll

참고 항목

DevCreateObjectQueryEx