다음을 통해 공유


CM_Unregister_Notification 함수(cfgmgr32.h)

코드가 Windows 7 또는 이전 버전의 Windows를 대상으로 하는 경우 CM_Unregister_Notification 대신 UnregisterDeviceNotification을 사용합니다.

CM_Unregister_Notification 함수는 지정된 HCMNOTIFICATION 핸들을 닫습니다.

구문

CMAPI CONFIGRET CM_Unregister_Notification(
  [in] HCMNOTIFICATION NotifyContext
);

매개 변수

[in] NotifyContext

CM_Register_Notification 함수에서 반환된 HCMNOTIFICATION 핸들입니다.

반환 값

작업이 성공하면 함수는 CR_SUCCESS 반환합니다. 그렇지 않으면 Cfgmgr32.h에 정의된 CR_ 접두사 오류 코드 중 하나를 반환합니다.

설명

알림 콜백에서 CM_Unregister_Notification 호출하지 마세요. 이렇게 하면 CM_Unregister_Notification 보류 중인 콜백이 완료될 때까지 대기하므로 교착 상태가 발생할 수 있습니다.

대신 알림 콜백에서 등록을 취소하려면 비동기적으로 등록을 취소해야 합니다. 다음 시퀀스는 이 작업을 수행하는 한 가지 방법을 보여줍니다.

  1. 알림과 함께 사용할 컨텍스트 구조를 할당합니다. threadpool 작업 구조(PTP_WORK) 및 알림 콜백에 전달하려는 기타 정보에 대한 포인터를 포함합니다.
  2. CreateThreadpoolWork를 호출합니다. CM_Unregister_Notification 호출하는 콜백 함수를 제공합니다. 반환된 작업 구조를 이전에 할당된 컨텍스트 구조에 추가합니다.
  3. CM_Register_Notification 호출하고 컨텍스트 구조를 pContext 매개 변수로 제공합니다.
  4. 작업 수행, 알림 받기 등
  5. 알림 콜백 내에서 SubmitThreadpoolWork 를 호출하여 컨텍스트 구조에 저장된 스레드 풀 작업 구조(PTP_WORK)에 대한 포인터를 제공합니다.
  6. 스레드 풀 스레드가 실행되면 작업 항목은 CM_Unregister_Notification 호출합니다.
  7. CloseThreadpoolWork를 호출하여 작업 개체를 해제합니다.
컨텍스트 구조를 완료한 경우 리소스를 해제하고 구조를 해제하는 것을 잊지 마세요.
주의 작업 항목이 CM_Unregister_Notification 호출될 때까지 컨텍스트 구조를 해제하지 마세요. threadpool 작업 항목을 제출하고 작업 항목이 CM_Unregister_Notification 호출하기 전에 알림을 받을 수 있습니다.
 

예제

다음 예제에서는 주의 섹션에 설명된 대로 알림 콜백에서 등록을 취소하는 방법을 보여 줍니다.

typedef struct _CALLBACK_CONTEXT {
    BOOL bUnregister;
    PTP_WORK pWork;
    HCMNOTIFICATION hNotify;
    CRITICAL_SECTION lock;
} CALLBACK_CONTEXT, *PCALLBACK_CONTEXT;

DWORD
WINAPI
EventCallback(
    __in HCMNOTIFICATION hNotification,
    __in PVOID Context,
    __in CM_NOTIFY_ACTION Action,
    __in PCM_NOTIFY_EVENT_DATA EventData,
    __in DWORD EventDataSize
    )
{
    PCALLBACK_CONTEXT pCallbackContext = (PCALLBACK_CONTEXT)Context;

   // unregister from the callback
    EnterCriticalSection(&(pCallbackContext->lock));

    // in case this callback fires before the registration call returns, make sure the notification handle is properly set
    Context->hNotify = hNotification;

    if (!pCallbackContext->bUnregister) {
        pCallbackContext->bUnregister = TRUE;
        SubmitThreadpoolWork(pCallbackContext->pWork);
    }

    LeaveCriticalSection(&(pCallbackContext->lock));

    return ERROR_SUCCESS;
};

VOID
CALLBACK
WorkCallback(
    _Inout_ PTP_CALLBACK_INSTANCE Instance,
    _Inout_opt_ PVOID Context,
    _Inout_ PTP_WORK pWork
    )
{
    PCALLBACK_CONTEXT pCallbackContext = (PCALLBACK_CONTEXT)Context;

    CM_Unregister_Notification(pCallbackContext->hNotify);
}

VOID NotificationFunction()
{
    CONFIGRET cr = CR_SUCCESS;
    HRESULT hr = S_OK;
    CM_NOTIFY_FILTER NotifyFilter = { 0 };
    BOOL bShouldUnregister = FALSE;
    PCALLBACK_CONTEXT context;

    context = (PCALLBACK_CONTEXT)HeapAlloc(GetProcessHeap(),
                                           HEAP_ZERO_MEMORY,
                                           sizeof(CALLBACK_CONTEXT));
    if (context == NULL) {
        goto end;
    }

    InitializeCriticalSection(&(context->lock));

    NotifyFilter.cbSize = sizeof(NotifyFilter);
    NotifyFilter.Flags = 0;
    NotifyFilter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE;
    NotifyFilter.Reserved = 0;

    hr = StringCchCopy(NotifyFilter.u.DeviceInstance.InstanceId,
                       MAX_DEVICE_ID_LEN,
                       TEST_DEVICE_INSTANCE_ID);
    if (FAILED(hr)) {
        goto end;
    }

    context->pWork = CreateThreadpoolWork(WorkCallback, context, NULL);
    if (context->pWork == NULL) {
        goto end;
    }

    cr = CM_Register_Notification(&NotifyFilter,
                                  context,
                                  EventCallback,
                                  &context->hNotify);
   if (cr != CR_SUCCESS) {
        goto end;
    }

    // ... do work here ...

    EnterCriticalSection(&(context->lock));

    if (!context->bUnregister) {
        // unregister not from the callback
        bShouldUnregister = TRUE;
        context->bUnregister = TRUE;
    }

    LeaveCriticalSection(&(context->lock));

    if (bShouldUnregister) {
        cr = CM_Unregister_Notification(context->hNotify);
        if (cr != CR_SUCCESS) {
            goto end;
        }
    } else {
        // if the callback is the one performing the unregister, wait for the threadpool work item to complete the unregister
        WaitForThreadpoolWorkCallbacks(context->pWork, FALSE);
    }

end:

    if (context != NULL) {
        if (context->pWork != NULL) {
            CloseThreadpoolWork(context->pWork);
        }

        DeleteCriticalSection(&(context->lock));

        HeapFree(GetProcessHeap(), 0, context);
    }

    return;
}

요구 사항

요구 사항
지원되는 최소 클라이언트 Microsoft Windows 8 이상 버전의 Windows에서 사용할 수 있습니다.
대상 플랫폼 유니버설
헤더 cfgmgr32.h(Cfgmgr32.h 포함)
라이브러리 Cfgmgr32.lib; Windows 10 OneCoreUAP.lib
DLL CfgMgr32.dll

추가 정보

UnregisterDeviceNotification