イベントの生成
センサー イベントの動作方法については、「センサー ドライバー イベントについて」を参照してください。
次のコード例は、データ更新イベントおよび状態変更イベントを生成するクラスを示しています。時間センサー サンプルでこのコードの動作を確認できます。
メンバー変数
このクラスでは、次のメンバー変数が定義されています。
// Smart pointer to the sensor class extension object.
CComPtr<ISensorClassExtension> m_spSensorCXT;
// Pointer to the callback class that the class extension calls.
CSensorDdi* m_pDdi;
// The event thread handle
HANDLE m_hEventThread;
// Handle to an event used to signal the thread to close.
HANDLE m_hCloseThread;
// The current report interval.
DWORD m_dwInterval;
グローバル変数
ドライバーは、このクラスが使用する次のグローバル変数を定義しています。
// Sensor ID
static const LPWSTR g_wszSensorID = L"My Sensor ID";
// Default event interval
static const DWORD g_dwDefaultInterval = 1000; // one second
有効期間管理
最初のクライアントがイベントをサブスクライブした時点で、ISensorDriver を実装した、CSensorDdi という名前のコールバック クラスにより、CSampleEvents イベント クラスのインスタンスが作成されます。このコールバック クラスは、クライアントがイベントをサブスクライブしなくなった時点で、CSampleEvents インスタンスを破棄します。
CSampleEvents は、ISensorDriver::OnGetDataFields など、クラス拡張が使用する同じメソッドを使用することで、CSensorDdi にコールバックして最新のデータを取得します。
次のコード例には、CSampleEvents イベント クラスのメソッド実装が含まれています。
CSampleEvents::CSampleEvents()
{
// Initialize member variables.
m_hEventThread = NULL;
m_hCloseThread = NULL;
m_dwInterval = g_dwDefaultInterval;
};
CSampleEvents::~CSampleEvents()
{
};
// Initialize
// Sets the pointers to the class extension and the callback class.
HRESULT CSampleEvents::Initialize(ISensorClassExtension *pSensorCXT, CSensorDdi* pDdi)
{
HRESULT hr = S_OK;
if(NULL == pSensorCXT || NULL == pDdi)
{
return E_POINTER;
}
// Cache the pointers to the class extension and DDI callback class.
m_spSensorCXT = pSensorCXT;
m_pDdi = pDdi;
// Create the event used to close the thread.
m_hCloseThread = ::CreateEvent(NULL, FALSE, FALSE, TEXT("CloseThreadEvent"));
if(NULL == m_hCloseThread)
{
hr = E_UNEXPECTED;
}
if(SUCCEEDED(hr))
{
m_hEventThread = ::CreateThread(NULL, // Cannot be inherited by child process
0, // Default stack size
&CSampleEvents::_EventThreadProc, // Thread proc
(LPVOID)this, // Thread proc argument
0, // Starting state = running
NULL); // No thread identifier
if(NULL == m_hEventThread)
{
hr = E_UNEXPECTED;
}
}
return hr;
};
// Uninitializes the event class.
HRESULT CSampleEvents::Uninitialize()
{
HRESULT hr = S_OK;
// Stop the event thread.
::SetEvent(m_hCloseThread);
// Wait for the thread to end.
::WaitForSingleObject(m_hEventThread, INFINITE);
if (NULL != m_hEventThread)
{
CloseHandle(m_hEventThread);
m_hEventThread = NULL;
}
if(NULL != m_hCloseThread)
{
CloseHandle(m_hCloseThread);
m_hCloseThread = NULL;
}
// After Uninitialize, clients must call Initialize to set new pointers.
m_pDdi = NULL;
m_spSensorCXT.Release();
return hr;
};
// Post a state change event
HRESULT CSampleEvents::PostStateEvent()
{
HRESULT hr = (NULL == m_spSensorCXT) ? E_UNEXPECTED : S_OK ;
if (SUCCEEDED(hr))
{
SensorState st;
hr = m_pDdi->GetSensorState(&st);
if (SUCCEEDED(hr))
{
// Post the state change event.
hr = m_spSensorCXT->PostStateChange(g_wszSensorID, st);
}
}
return hr;
}
// Post a data updated event
HRESULT CSampleEvents::PostDataEvent(IPortableDeviceValues* pValues)
{
HRESULT hr = (NULL == m_spSensorCXT) ? E_UNEXPECTED : S_OK ;
if (SUCCEEDED(hr))
{
CComPtr<IPortableDeviceValuesCollection> spValuesCollection;
hr = spValuesCollection.CoCreateInstance(CLSID_PortableDeviceValuesCollection);
if (SUCCEEDED(hr))
{
hr = spValuesCollection->Add(pValues);
if (SUCCEEDED(hr))
{
hr = m_spSensorCXT->PostEvent(g_wszSensorID, spValuesCollection);
}
}
}
return hr;
}
スレッド プロシージャ
次のコード例は、CSampleEvents クラスを使用してデータ更新イベントを生成するスレッド プロシージャを示しています。
DWORD WINAPI CSampleEvents::_EventThreadProc(__in LPVOID pvData)
{
// Cast the argument to the correct type.
CSampleEvents* pThis = static_cast<CSampleEvents*>(pvData);
// New threads must always CoInitialize...
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(hr))
{
// Wait loop timed to use current report interval.
while (WAIT_TIMEOUT == WaitForSingleObject(pThis->m_hCloseThread, pThis->m_dwInterval))
{
if(NULL == pThis->m_pDdi ||
NULL == pThis->m_spSensorCXT.p)
{
Trace(TRACE_LEVEL_ERROR, "%!FUNC!: NULL pointer in helper function.");
hr = E_POINTER;
}
CComPtr<IPortableDeviceValues> spEventParams;
CComPtr<IPortableDeviceKeyCollection> spKeys;
if(SUCCEEDED(hr))
{
// Use the Ddi class to create the key collection.
hr = pThis->m_pDdi->OnGetSupportedDataFields(g_wszSensorID, &spKeys);
}
if(SUCCEEDED(hr))
{
CComPtr<IWDFFile> spTemp;
// Get the data fields.
// Note that we're using a DDI call as a helper function, here.
// Setting the first parameter to NULL will be problematic if you
// choose to track or use IWDFFile pointers in OnGetDataFields.
// This sample does not do so, therefore this is a safe thing to do
// in this code.
hr = pThis->m_pDdi->OnGetDataFields(spTemp, g_wszSensorID, spKeys,
&spEventParams);
}
if(SUCCEEDED(hr))
{
// Add the data event property key.
hr = spEventParams->SetGuidValue(SENSOR_EVENT_PARAMETER_EVENT_ID,
SENSOR_EVENT_DATA_UPDATED);
if(SUCCEEDED(hr))
{
// Post the event.
hr = pThis->PostDataEvent(spEventParams);
}
}
}
}
CoUninitialize();
return SUCCEEDED(hr) ? 0 : 1;
};