Асинхронный вызов методов службы
Приложение WpdServiceApiSample содержит код, демонстрирующий, как приложение может асинхронно вызывать методы службы. В этом примере используются следующие интерфейсы.
Интерфейс | Описание |
---|---|
IPortableDeviceService | Используется для получения интерфейса IPortableDeviceServiceMethods для вызова методов в данной службе. |
IPortableDeviceServiceMethods | Используется для вызова метода службы. |
IPortableDeviceValues | Используется для хранения параметров исходящего метода и входящих результатов метода. Это значение может иметь значение NULL , если метод не требует никаких параметров или не возвращает результаты. |
IPortableDeviceServiceMethodCallback | Реализуется приложением для получения результатов метода после завершения метода. |
Когда пользователь выбирает параметр "10" в командной строке, приложение вызывает метод InvokeMethodsAsync , который находится в модуле ServiceMethods.cpp. Обратите внимание, что перед вызовом методов пример приложения открывает службу контактов на подключенном устройстве.
Методы службы инкапсулируют функциональные возможности, которые каждая служба определяет и реализует. Они уникальны для каждого типа службы и представлены идентификатором GUID. Например, служба "Контакты" определяет метод BeginSync , вызываемый приложениями для подготовки устройства к синхронизации объектов Contact, и метод EndSync для уведомления устройства о завершении синхронизации. Приложения выполняют метод службы переносимого устройства, вызывая метод IPortableDeviceServiceMethods::Invoke.
Методы службы не следует путать с командами WPD. Команды WPD являются частью стандартного интерфейса драйвера устройства WPD (DDI) и являются механизмом взаимодействия между приложением WPD и драйвером. Команды предварительно определены, сгруппированы по категориям (например, WPD_CATEGORY_COMMON) и представлены структурой PROPERTYKEY . Приложение отправляет команды драйверу устройства, вызывая IPortableDeviceService::SendCommand. Дополнительные сведения см. в разделе Команды.
Метод InvokeMethodsAsync вызывает IPortableDeviceService::Methods для получения интерфейса IPortableDeviceServiceMethods . Используя этот интерфейс, он вызывает вспомогательную функцию InvokeMethodAsync дважды; один раз для метода BeginSync и один раз для метода EndSync . В этом примере InvokeMethodAsync бесконечно ожидает глобального события при вызове метода IPortableDeviceServiceMethodCallback::OnComplete .
В следующем коде используется метод InvokeMethodsAsync .
// Invoke methods on the Contacts Service asynchornously.
// BeginSync and EndSync are methods defined by the FullEnumerationSync Device Service.
void InvokeMethodsAsync(IPortableDeviceService* pService)
{
HRESULT hr = S_OK;
CComPtr<IPortableDeviceServiceMethods> pMethods;
if (pService == NULL)
{
printf("! A NULL IPortableDeviceService interface pointer was received\n");
return;
}
// Get an IPortableDeviceServiceMethods interface from the IPortableDeviceService interface to
// invoke methods.
hr = pService->Methods(&pMethods);
if (FAILED(hr))
{
printf("! Failed to get IPortableDeviceServiceMethods from IPortableDeviceService, hr = 0x%lx\n",hr);
}
// Invoke the BeginSync method asynchronously
if (SUCCEEDED(hr))
{
printf("Invoking %ws asynchronously...\n",NAME_FullEnumSyncSvc_BeginSync);
// This method does not take any parameters, so we pass in NULL
hr = InvokeMethodAsync(pMethods, METHOD_FullEnumSyncSvc_BeginSync, NULL);
if (FAILED(hr))
{
printf("! Failed to invoke %ws asynchronously, hr = 0x%lx\n",NAME_FullEnumSyncSvc_BeginSync, hr);
}
}
// Invoke the EndSync method asynchronously
if (SUCCEEDED(hr))
{
printf("Invoking %ws asynchronously...\n",NAME_FullEnumSyncSvc_EndSync);
hr = InvokeMethodAsync(pMethods, METHOD_FullEnumSyncSvc_EndSync, NULL);
if (FAILED(hr))
{
printf("! Failed to invoke %ws asynchronously, hr = 0x%lx\n",NAME_FullEnumSyncSvc_EndSync, hr);
}
}
}
Вспомогающая функция InvokeMethodAsync выполняет следующие действия для каждого вызываемого метода:
- Создает глобальный дескриптор событий, отслеживаемый для определения завершения метода.
- Создает объект CMethodCallback , который предоставляется в качестве аргумента для IPortableDeviceServiceMethods:InvokeAsync.
- Вызывает метод IPortableDeviceServiceMethods::InvokeAsync для вызова заданного метода.
- Отслеживает глобальный дескриптор событий для завершения.
- Выполняет очистку.
Класс CMethodCallback демонстрирует, как приложение может реализовать IPortableDeviceServiceMethodCallback. Реализация OnComplete в этом классе сигнализирует о событии для уведомления приложения о завершении метода службы. В дополнение к методу OnComplete этот класс реализует AddRef, QueryInterface и Release, которые используются для поддержания количества ссылок объекта и интерфейсов, которые он реализует.
class CMethodCallback : public IPortableDeviceServiceMethodCallback
{
public:
CMethodCallback () : m_cRef(1)
{
}
~CMethodCallback ()
{
}
public:
// IPortableDeviceServiceMethodCallback::QueryInterface
virtual HRESULT STDMETHODCALLTYPE OnComplete(
HRESULT hrStatus,
IPortableDeviceValues* /*pResults*/) // We are ignoring results as our methods will not return any results
{
printf("** Method completed, status HRESULT = 0x%lx **\n", hrStatus);
if (g_hMethodCompleteEvent != NULL)
{
SetEvent(g_hMethodCompleteEvent);
}
return S_OK;
}
// IUnknown::AddRef
virtual ULONG STDMETHODCALLTYPE AddRef(void)
{
InterlockedIncrement((long*) &m_cRef);
return m_cRef;
}
// IUnknown::QueryInterface
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
LPVOID* ppvObj)
{
HRESULT hr = S_OK;
if (ppvObj == NULL)
{
hr = E_INVALIDARG;
return hr;
}
if ((riid == IID_IUnknown) ||
(riid == IID_IPortableDeviceServiceMethodCallback))
{
AddRef();
*ppvObj = this;
}
else
{
*ppvObj = NULL;
hr = E_NOINTERFACE;
}
return hr;
}
// IUnknown::Release
virtual ULONG STDMETHODCALLTYPE Release(void)
{
ULONG ulRefCount = m_cRef - 1;
if (InterlockedDecrement((long*) &m_cRef) == 0)
{
delete this;
return 0;
}
return ulRefCount;
}
private:
DWORD m_cRef;
};
Связанные темы