这是Delphi XE3探索:Winapi.Functiondiscovery系列到第三篇文章。
思路分析
Discovery API 不仅仅可以用来枚举设备信息,还可以接收设备通知;例如设备的添加、移除或者设备的属性被修改。为了接收这些设备改变的通知就需要实现 IFunctionDiscoveryNotification接口。AddQueryConstraint 的PROVIDERPNP_QUERYCONSTRAINT_NOTIFICATIONSONLY值用于设置是否仅接收设备通知,最后调用 IFunctionInstanceCollectionQuery.Execute方法。
实现IFunctionDiscoveryNotification 接口
IFunctionDiscoveryNotification 有三个方法用于接收 IFunctionInstanceCollectionQuery.Execute 异步查询的结果。
接口方法
OnError : Receives errors that occur during asynchronous query processing.
OnEvent : Receives any add, remove, or update events.
OnUpdate : Indicates that a function instance has been added, removed, or changed.
IFunctionDiscoveryNotification 接口声明:
IFunctionDiscoveryNotification = interface(IUnknown) [SID_IFunctionDiscoveryNotification] function OnUpdate(enumQueryUpdateAction: QueryUpdateAction; fdqcQueryContext: FDQUERYCONTEXT; pIFunctionInstance: IFunctionInstance): HRESULT; stdcall; function OnError(hr: HRESULT; fdqcQueryContext: FDQUERYCONTEXT; pszProvider: PWCHAR): HRESULT; stdcall; function OnEvent(dwEventID: DWORD; fdqcQueryContext: FDQUERYCONTEXT; pszProvider: PWCHAR): HRESULT; stdcall; end;
接口实现代码
type TFunctionDiscoveryOnUpdate = procedure(enumQueryUpdateAction: QueryUpdateAction; fdqcQueryContext: FDQUERYCONTEXT; pIFunctionInstance: IFunctionInstance) of object; TFunctionDiscoveryOnError = procedure(hr: HRESULT; fdqcQueryContext: FDQUERYCONTEXT; pszProvider: PWCHAR) of object; TFunctionDiscoveryOnEvent = procedure(dwEventID: DWORD; fdqcQueryContext: FDQUERYCONTEXT; pszProvider: PWCHAR) of object; TFunctionDiscoveryNotificationSync=class(TInterfacedObject, IFunctionDiscoveryNotification) private FAction : QueryUpdateAction; FEventAdd : TEvent; FEventRemove : TEvent; FEventChange : TEvent; FOnUpdateEvent : TFunctionDiscoveryOnUpdate; FOnErrorEvent : TFunctionDiscoveryOnError; FOnEventEvent : TFunctionDiscoveryOnEvent; function OnUpdate(enumQueryUpdateAction: QueryUpdateAction; fdqcQueryContext: FDQUERYCONTEXT; pIFunctionInstance: IFunctionInstance): HRESULT; stdcall; function OnError(hr: HRESULT; fdqcQueryContext: FDQUERYCONTEXT; pszProvider: PWCHAR): HRESULT; stdcall; function OnEvent(dwEventID: DWORD; fdqcQueryContext: FDQUERYCONTEXT; pszProvider: PWCHAR): HRESULT; stdcall; public constructor Create; destructor Destroy; override; function WaitFor(dwTimeout : DWORD; pszCategory: PWCHAR; eAction : QueryUpdateAction) : HRESULT; property OnUpdateEvent: TFunctionDiscoveryOnUpdate read FOnUpdateEvent write FOnUpdateEvent; property OnErrorEvent : TFunctionDiscoveryOnError read FOnErrorEvent write FOnErrorEvent; property OnEventEvent : TFunctionDiscoveryOnEvent read FOnEventEvent write FOnEventEvent; end; {TFunctionDiscoveryNotificationSync} constructor TFunctionDiscoveryNotificationSync.Create; begin inherited; FOnUpdateEvent:=nil; //create the events objects FEventAdd := TEvent.Create(nil, False, False, '', true); FEventRemove := TEvent.Create(nil, False, False, '', true); FEventChange := TEvent.Create(nil, False, False, '', true); end; destructor TFunctionDiscoveryNotificationSync.Destroy; begin //release the event objects FEventAdd.Free; FEventRemove.Free; FEventChange.Free; inherited; end; function TFunctionDiscoveryNotificationSync.OnError(hr: HRESULT; fdqcQueryContext: FDQUERYCONTEXT; pszProvider: PWCHAR): HRESULT; begin //send the error notification if a callback method was defined if @FOnErrorEvent<>nil then FOnErrorEvent(hr, fdqcQueryContext, pszProvider); Exit(S_OK); end; function TFunctionDiscoveryNotificationSync.OnEvent(dwEventID: DWORD; fdqcQueryContext: FDQUERYCONTEXT; pszProvider: PWCHAR): HRESULT; begin //send the OnEvent notification if a callback method was defined if @FOnEventEvent<>nil then FOnEventEvent(dwEventID, fdqcQueryContext, pszProvider); Exit(S_OK); end; function TFunctionDiscoveryNotificationSync.OnUpdate( enumQueryUpdateAction: QueryUpdateAction; fdqcQueryContext: FDQUERYCONTEXT; pIFunctionInstance: IFunctionInstance): HRESULT; begin //signal the event object case enumQueryUpdateAction of QUA_ADD : FEventAdd.SetEvent; QUA_REMOVE : FEventRemove.SetEvent; QUA_CHANGE : FEventChange.SetEvent; end; //send the OnEvent notification if a callback method was defined if (@FOnUpdateEvent<>nil) and (FAction=enumQueryUpdateAction) then FOnUpdateEvent(enumQueryUpdateAction, fdqcQueryContext, pIFunctionInstance); Exit(S_OK); end; function TFunctionDiscoveryNotificationSync.WaitFor(dwTimeout : DWORD; pszCategory: PWCHAR; eAction : QueryUpdateAction) : HRESULT; var hr : HRESULT; LEvent : TEvent; LWaitResult : TWaitResult; FFunctionDiscovery : IFunctionDiscovery; ppIFunctionInstanceCollection: IFunctionInstanceCollection; ppIFunctionInstanceCollectionQuery: IFunctionInstanceCollectionQuery; begin FAction:=eAction; //reset the event objects FEventAdd.ResetEvent; FEventRemove.ResetEvent; FEventChange.ResetEvent; //create a instance to the IFunctionDiscovery FFunctionDiscovery := CreateComObject(CLSID_FunctionDiscovery) as IFunctionDiscovery; //create a new query passing the current class as callback hr := FFunctionDiscovery.CreateInstanceCollectionQuery(FCTN_CATEGORY_PNP, nil, true, Self, nil, ppIFunctionInstanceCollectionQuery); //instruct to the query to only receive notifications if hr=S_OK then hr := ppIFunctionInstanceCollectionQuery.AddQueryConstraint(PROVIDERPNP_QUERYCONSTRAINT_NOTIFICATIONSONLY,'TRUE'); //execute the query if hr=S_OK then hr := ppIFunctionInstanceCollectionQuery.Execute(ppIFunctionInstanceCollection); if( hr=E_PENDING) then hr := S_OK; case eAction of QUA_ADD : LEvent:=FEventAdd; QUA_REMOVE : LEvent:=FEventRemove; QUA_CHANGE : LEvent:=FEventChange; else LEvent := nil; end; if (hr=S_OK) and (LEvent<>nil) then LWaitResult:= LEvent.WaitFor(dwTimeout); // One device may correspond to multiple function instances // This sleep allows the OnUpdate call to output information // about each Function Instance. // THIS SLEEP IS MERELY FOR DISPLAY PURPOSES Sleep(1000); Exit(hr); end;
1 2
转载需保留链接来源:软件玩家 » Delphi XE3探索:Winapi.Functiondiscovery (三)