Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

734 lines
23 KiB

//--------------------------------------------------------------------
// HWProv.cpp - sample code
// Copyright (C) Microsoft Corporation, 2001
//
// Created by: Duncan Bryce (duncanb), 9-13-2001
//
// A sample hardware provider
//
#include "pch.h"
//
// This provider will read from hardware clocks which can be configured purely
// through serial port parametners. The clocks must periodically push data
// onto the serial cable, in a format specified by the "Format" reg value
// Furthermore, we will only accept input using ASCII character values.
//
// TODO: unicode support?
// need polling character?
// verify which clocks we work with
// dynamically allocate format string based on calculated length?
// why is 32seconds the irregular interval??
// ensure that w32time calls into providers in a single-threaded fashion
// should support placement of "time marker"?
//
struct HWProvState {
TimeProvSysCallbacks tpsc;
// Configuration information
DCB dcb;
HANDLE hComPort;
WCHAR *wszCommPort;
char cSampleInputBuffer[256]; // BUGBUG: add assert to ensure we cant overrun this buffer
WCHAR *wszRefID;
// Parser information
HANDLE hParser;
WCHAR *wszFormat;
DWORD dwSampleSize;
// Synchronization
HANDLE hStopEvent;
HANDLE hProvThread_EnterOrLeaveThreadTrapEvent;
HANDLE hProvThread_ThreadTrapTransitionCompleteEvent;
HANDLE hProvThread;
CRITICAL_SECTION csProv;
bool bIsCsProvInitialized;
// Time sample information
bool bSampleIsValid;
NtTimeEpoch teSampleReceived;
TimeSample tsCurrent;
};
struct HWProvConfig {
DWORD dwBaudRate; //
DWORD dwByteSize; //
DWORD dwParity; // 0-4=no,odd,even,mark,space
DWORD dwStopBits; //
WCHAR *wszCommPort; //
WCHAR *wszFormat; //
WCHAR *wszRefID; //
};
HWProvState *g_phpstate = NULL;
void __cdecl SeTransFunc(unsigned int u, EXCEPTION_POINTERS* pExp) {
throw SeException(u);
}
HRESULT TrapThreads(bool bEnter) {
DWORD dwWaitResult;
HRESULT hr;
// BUGBUG: need critsec to serialize TrapThreads?
// BUGBUG: should the trap threads events be manual?
// if auto, we'll try only once, but code simpler/
// if manual, we'll keep trying on failure, but might be expensive!
if (!SetEvent(g_phpstate->hProvThread_EnterOrLeaveThreadTrapEvent)) {
_JumpLastError(hr, error, "SetEvent");
}
dwWaitResult = WaitForSingleObject(g_phpstate->hProvThread_ThreadTrapTransitionCompleteEvent, INFINITE);
if (WAIT_FAILED == dwWaitResult) {
_JumpLastError(hr, error, "WaitForSingleObject");
}
hr = S_OK;
error:
return hr;
}
HRESULT ThreadTrap() {
DWORD dwWaitResult;
HRESULT hr;
if (!SetEvent(g_phpstate->hProvThread_ThreadTrapTransitionCompleteEvent)) {
_JumpLastError(hr, error, "SetEvent");
}
dwWaitResult = WaitForSingleObject(g_phpstate->hProvThread_EnterOrLeaveThreadTrapEvent, INFINITE);
if (WAIT_FAILED == dwWaitResult) {
_JumpLastError(hr, error, "WaitForSingleObject");
}
if (!SetEvent(g_phpstate->hProvThread_ThreadTrapTransitionCompleteEvent)) {
_JumpLastError(hr, error, "SetEvent");
}
hr = S_OK;
error:
return hr;
}
//--------------------------------------------------------------------
VOID CALLBACK HandleDataAvail(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED *po) {
bool bEnteredCriticalSection = false;
HRESULT hr;
unsigned __int64 nSysCurrentTime;
unsigned __int64 nSysPhaseOffset;
unsigned __int64 nSysTickCount;
// Parse the returned data based on the format string:
if (ERROR_SUCCESS != dwErrorCode) {
hr = HRESULT_FROM_WIN32(dwErrorCode);
_JumpError(hr, error, "HandleDataAvail: ReadFileEx failed");
}
// Get the required timestamp information:
hr = g_phpstate->tpsc.pfnGetTimeSysInfo(TSI_CurrentTime, &nSysCurrentTime);
_JumpIfError(hr, error, "g_phpstate->tpsc.pfnGetTimeSysInfo");
hr = g_phpstate->tpsc.pfnGetTimeSysInfo(TSI_TickCount, &nSysTickCount);
_JumpIfError(hr, error, "g_pnpstate->tpsc.pfnGetTimeSysInfo");
hr = g_phpstate->tpsc.pfnGetTimeSysInfo(TSI_PhaseOffset, &nSysPhaseOffset);
_JumpIfError(hr, error, "g_pnpstate->tpsc.pfnGetTimeSysInfo");
_EnterCriticalSectionOrFail(&g_phpstate->csProv, bEnteredCriticalSection, hr, error);
// Convert the data retrieved from the time hardware into a time sample:
hr = ParseSample(g_phpstate->hParser, g_phpstate->cSampleInputBuffer, nSysCurrentTime, nSysPhaseOffset, nSysTickCount, &g_phpstate->tsCurrent);
_JumpIfError(hr, error, "ParseFormatString");
// Indicate that we now have a valid sample
g_phpstate->bSampleIsValid = true;
hr = g_phpstate->tpsc.pfnAlertSamplesAvail();
_JumpIfError(hr, error, "g_pnpstate->tpsc.pfnAlertSamplesAvail");
hr = S_OK;
error:;
_LeaveCriticalSection(&g_phpstate->csProv, bEnteredCriticalSection, hr);
// BUGBUG: do we want to sleep on error?
// return hr;
}
//--------------------------------------------------------------------
MODULEPRIVATE DWORD WINAPI HwProvThread(void * pvIgnored) {
DWORD dwLength;
DWORD dwWaitResult;
HRESULT hr;
OVERLAPPED o;
HANDLE rghWait[] = {
g_phpstate->hStopEvent,
g_phpstate->hProvThread_EnterOrLeaveThreadTrapEvent
};
ZeroMemory(&o, sizeof(o));
if (!ReadFileEx(g_phpstate->hComPort, g_phpstate->cSampleInputBuffer, g_phpstate->dwSampleSize, &o, HandleDataAvail)) {
_JumpLastError(hr, error, "ReadFileEx");
}
while (true) {
dwWaitResult = WaitForMultipleObjectsEx(ARRAYSIZE(rghWait), rghWait, FALSE, INFINITE, TRUE);
if (WAIT_OBJECT_0 == dwWaitResult) {
// stop event
goto done;
} else if (WAIT_OBJECT_0+1 == dwWaitResult) {
// thread trap notification. Trap this thread:
hr = ThreadTrap();
_JumpIfError(hr, error, "ThreadTrap");
} else if (WAIT_IO_COMPLETION == dwWaitResult) {
// we read some data. Queue up another read.
ZeroMemory(&o, sizeof(o));
ZeroMemory(g_phpstate->cSampleInputBuffer, sizeof(g_phpstate->cSampleInputBuffer));
if (!ReadFileEx(g_phpstate->hComPort, g_phpstate->cSampleInputBuffer, g_phpstate->dwSampleSize, &o, HandleDataAvail)) {
_JumpLastError(hr, error, "ReadFileEx");
}
} else {
/*failed*/
_JumpLastError(hr, error, "WaitForMultipleObjects");
}
}
done:
hr = S_OK;
error:
// BUGBUG: is CancelIo called implicitly?
return hr;
}
//--------------------------------------------------------------------
HRESULT StopHwProv() {
DWORD dwWaitResult;
HRESULT hr = S_OK;
if (NULL != g_phpstate) {
// Shut down the HW prov thread:
if (NULL != g_phpstate->hStopEvent) {
SetEvent(g_phpstate->hStopEvent);
}
dwWaitResult = WaitForSingleObject(g_phpstate->hProvThread, INFINITE);
if (WAIT_FAILED == dwWaitResult) {
_IgnoreLastError("WaitForSingleObject");
}
if (!GetExitCodeThread(g_phpstate->hProvThread, (DWORD *)&hr)) {
_IgnoreLastError("GetExitCodeThread");
} else if (FAILED(hr)) {
_IgnoreError(hr, "(HwProvThread)");
}
CloseHandle(g_phpstate->hProvThread);
if (NULL != g_phpstate->hStopEvent) {
CloseHandle(g_phpstate->hStopEvent);
}
if (NULL != g_phpstate->hProvThread_EnterOrLeaveThreadTrapEvent) {
CloseHandle(g_phpstate->hProvThread_EnterOrLeaveThreadTrapEvent);
}
if (NULL != g_phpstate->hProvThread_ThreadTrapTransitionCompleteEvent) {
CloseHandle(g_phpstate->hProvThread_ThreadTrapTransitionCompleteEvent);
}
if (NULL != g_phpstate->hComPort && INVALID_HANDLE_VALUE != g_phpstate->hComPort) {
CloseHandle(g_phpstate->hComPort);
}
if (NULL != g_phpstate->wszCommPort) {
LocalFree(g_phpstate->wszCommPort);
}
if (NULL != g_phpstate->wszFormat) {
LocalFree(g_phpstate->wszFormat);
}
if (NULL != g_phpstate->hParser) {
FreeParser(g_phpstate->hParser);
}
if (g_phpstate->bIsCsProvInitialized) {
DeleteCriticalSection(&g_phpstate->csProv);
g_phpstate->bIsCsProvInitialized = false;
}
LocalFree(g_phpstate);
ZeroMemory(g_phpstate, sizeof(HWProvState));
}
return hr;
}
//--------------------------------------------------------------------
void FreeHwProvConfig(HWProvConfig *phwpConfig) {
if (NULL != phwpConfig) {
if (NULL != phwpConfig->wszCommPort) {
LocalFree(phwpConfig->wszCommPort);
}
if (NULL != phwpConfig->wszFormat) {
LocalFree(phwpConfig->wszFormat);
}
if (NULL != phwpConfig->wszRefID) {
LocalFree(phwpConfig->wszRefID);
}
LocalFree(phwpConfig);
}
}
//--------------------------------------------------------------------
HRESULT ReadHwProvConfig(HWProvConfig **pphwpConfig) {
DWORD dwResult;
HKEY hkConfig = NULL;
HRESULT hr;
HWProvConfig *phwpConfig = NULL;
WCHAR wszBuf[256];
dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, wszHwProvRegKeyConfig, 0, KEY_READ, &hkConfig);
if (ERROR_SUCCESS != dwResult) {
hr=HRESULT_FROM_WIN32(dwResult);
_JumpErrorStr(hr, error, "RegOpenKeyEx", wszHwProvRegKeyConfig);
}
phwpConfig = (HWProvConfig *)LocalAlloc(LPTR, sizeof(HWProvConfig));
_JumpIfOutOfMemory(hr, error, phwpConfig);
struct {
WCHAR *wszRegValue;
DWORD *pdwValue;
} rgRegParams[] = {
{
wszHwProvRegValueBaudRate,
&phwpConfig->dwBaudRate
}, {
wszHwProvRegValueByteSize,
&phwpConfig->dwByteSize
}, {
wszHwProvRegValueParity,
&phwpConfig->dwParity
}, {
wszHwProvRegValueStopBits,
&phwpConfig->dwStopBits
}
};
for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgRegParams); dwIndex++) {
DWORD dwSize = sizeof(DWORD);
DWORD dwType;
dwResult = RegQueryValueEx(hkConfig, rgRegParams[dwIndex].wszRegValue, NULL, &dwType, (BYTE *)rgRegParams[dwIndex].pdwValue, &dwSize);
if (ERROR_SUCCESS != dwResult) {
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpErrorStr(hr, error, "RegQueryValue", rgRegParams[dwIndex].wszRegValue);
}
_Verify(REG_DWORD == dwType, hr, error);
}
struct {
WCHAR *wszRegValue;
WCHAR **ppwszValue;
} rgRegSzParams[] = {
{
wszHwProvRegValueComPort,
&phwpConfig->wszCommPort
}, {
wszHwProvRegValueFormat,
&phwpConfig->wszFormat
}, {
wszHwProvRegValueRefID,
&phwpConfig->wszRefID
}
};
for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgRegSzParams); dwIndex++) {
DWORD dwSize = sizeof(wszBuf);
DWORD dwType;
dwResult = RegQueryValueEx(hkConfig, rgRegSzParams[dwIndex].wszRegValue, NULL, &dwType, (BYTE *)wszBuf, &dwSize);
if (ERROR_SUCCESS != dwResult) {
hr = HRESULT_FROM_WIN32(dwResult);
_JumpErrorStr(hr, error, "RegQueryValueEx", rgRegSzParams[dwIndex].wszRegValue);
}
_Verify(REG_SZ == dwType, hr, error);
*(rgRegSzParams[dwIndex].ppwszValue) = (WCHAR *)LocalAlloc(LPTR, dwSize);
_JumpIfOutOfMemory(hr, error, *(rgRegSzParams[dwIndex].ppwszValue));
wcscpy(*(rgRegSzParams[dwIndex].ppwszValue), wszBuf);
}
*pphwpConfig = phwpConfig;
phwpConfig = NULL;
hr = S_OK;
error:
if (NULL != hkConfig) {
RegCloseKey(hkConfig);
}
if (NULL != phwpConfig) {
FreeHwProvConfig(phwpConfig);
}
return hr;
}
//--------------------------------------------------------------------
HRESULT HandleUpdateConfig(void) {
bool bComConfigUpdated = false;
bool bTrappedThreads = false;
HRESULT hr;
HWProvConfig *phwpConfig = NULL;
hr = TrapThreads(true);
_JumpIfError(hr, error, "TrapThreads");
bTrappedThreads = true;
hr = ReadHwProvConfig(&phwpConfig);
_JumpIfError(hr, error, "ReadHwProvConfig");
// BUGBUG: need to update when com config changes!!
//
if (g_phpstate->dcb.BaudRate != phwpConfig->dwBaudRate) {
g_phpstate->dcb.BaudRate = phwpConfig->dwBaudRate;
bComConfigUpdated = true;
}
if (g_phpstate->dcb.ByteSize != (BYTE)phwpConfig->dwByteSize) {
g_phpstate->dcb.ByteSize = (BYTE)phwpConfig->dwByteSize;
bComConfigUpdated = true;
}
if (g_phpstate->dcb.Parity != (BYTE)phwpConfig->dwParity) {
g_phpstate->dcb.Parity = (BYTE)phwpConfig->dwParity;
bComConfigUpdated = true;
}
if (g_phpstate->dcb.StopBits != (BYTE)phwpConfig->dwStopBits) {
g_phpstate->dcb.StopBits = (BYTE)phwpConfig->dwStopBits;
bComConfigUpdated = true;
}
if (0 != wcscmp(g_phpstate->wszFormat, phwpConfig->wszFormat)) {
LocalFree(g_phpstate->wszFormat);
g_phpstate->wszFormat = phwpConfig->wszFormat;
phwpConfig->wszFormat = NULL;
FreeParser(g_phpstate->hParser);
g_phpstate->hParser = NULL;
hr = MakeParser(g_phpstate->wszFormat, &g_phpstate->hParser);
_JumpIfError(hr, error, "MakeParser");
g_phpstate->dwSampleSize = GetSampleSize(g_phpstate->hParser);
}
if (bComConfigUpdated) {
if (!SetCommState(g_phpstate->hComPort, &g_phpstate->dcb)) {
_JumpLastError(hr, error, "SetCommState");
}
// BUGBUG: PurgeComm()?
}
hr = S_OK;
error:
if (bTrappedThreads) {
HRESULT hr2 = TrapThreads(false);
_TeardownError(hr, hr2, "TrapThreads");
}
if (NULL != phwpConfig) {
FreeHwProvConfig(phwpConfig);
}
if (FAILED(hr)) {
HRESULT hr2 = StopHwProv();
_IgnoreIfError(hr2, "StopHwProv");
}
return hr;
}
//--------------------------------------------------------------------
MODULEPRIVATE HRESULT HandleTimeJump(TpcTimeJumpedArgs *ptjArgs) {
bool bEnteredCriticalSection = false;
HRESULT hr;
_EnterCriticalSectionOrFail(&g_phpstate->csProv, bEnteredCriticalSection, hr, error);
g_phpstate->bSampleIsValid = false;
hr = S_OK;
error:
_LeaveCriticalSection(&g_phpstate->csProv, bEnteredCriticalSection, hr);
return hr;
}
//--------------------------------------------------------------------
HRESULT HandleGetSamples(TpcGetSamplesArgs * ptgsa) {
bool bEnteredCriticalSection = false;
DWORD dwBytesRemaining;
HRESULT hr;
TimeSample *pts = NULL;
pts = (TimeSample *)ptgsa->pbSampleBuf;
dwBytesRemaining = ptgsa->cbSampleBuf;
ptgsa->dwSamplesAvailable = 0;
ptgsa->dwSamplesReturned = 0;
_EnterCriticalSectionOrFail(&g_phpstate->csProv, bEnteredCriticalSection, hr, error);
if (g_phpstate->bSampleIsValid) {
ptgsa->dwSamplesAvailable++;
if (dwBytesRemaining < sizeof(TimeSample)) {
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
_JumpError(hr, error, "HandleGetSamples: filling in sample buffer");
}
// Copy our current time sample over to the output buffer:
memcpy(pts, &g_phpstate->tsCurrent, sizeof(TimeSample));
ptgsa->dwSamplesReturned++;
// calculate the dispersion - add skew dispersion due to time
// since the sample's dispersion was last updated, and clamp to max dispersion.
NtTimePeriod tpDispersionTemp;
NtTimeEpoch teNow;
hr = g_phpstate->tpsc.pfnGetTimeSysInfo(TSI_CurrentTime, &teNow.qw);
_JumpIfError(hr, error, "g_phpstate->tpsc.pfnGetTimeSysInfo");
// see how long it's been since we received the sample:
if (teNow > g_phpstate->teSampleReceived) {
tpDispersionTemp = abs(teNow - g_phpstate->teSampleReceived);
tpDispersionTemp = NtpConst::timesMaxSkewRate(tpDispersionTemp);
}
tpDispersionTemp.qw += g_phpstate->tsCurrent.tpDispersion;
if (tpDispersionTemp > NtpConst::tpMaxDispersion) {
tpDispersionTemp = NtpConst::tpMaxDispersion;
}
pts->tpDispersion = tpDispersionTemp.qw;
}
hr = S_OK;
error:
_LeaveCriticalSection(&g_phpstate->csProv, bEnteredCriticalSection, hr);
return hr;
}
//--------------------------------------------------------------------
HRESULT StartHwProv(TimeProvSysCallbacks * pSysCallbacks) {
DWORD dwThreadID;
HRESULT hr;
HWProvConfig *phpc = NULL;
g_phpstate = (HWProvState *)LocalAlloc(LPTR, sizeof(HWProvState));
_JumpIfOutOfMemory(hr, error, g_phpstate);
hr = myInitializeCriticalSection(&g_phpstate->csProv);
_JumpIfError(hr, error, "myInitializeCriticalSection");
g_phpstate->bIsCsProvInitialized = true;
// save the callbacks table
if (sizeof(g_phpstate->tpsc) != pSysCallbacks->dwSize) {
hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
_JumpIfError(hr, error, "StartHwProv: save the callbacks table");
}
memcpy(&g_phpstate->tpsc, pSysCallbacks, sizeof(g_phpstate->tpsc));
// read the configuration
hr = ReadHwProvConfig(&phpc);
_JumpIfError(hr, error, "ReadHwProvConfig");
// Copy over the string config info:
g_phpstate->wszCommPort = phpc->wszCommPort;
phpc->wszCommPort = NULL; // prevent wszCommPort from being double-freed
g_phpstate->wszFormat = phpc->wszFormat;
phpc->wszFormat = NULL; // prevent wszFormat from being double-freed
g_phpstate->wszRefID = phpc->wszRefID;
phpc->wszRefID = NULL; // prevent wszRefID from being double-freed
// Create a parser from the specified format string:
hr = MakeParser(g_phpstate->wszFormat, &g_phpstate->hParser);
_JumpIfError(hr, error, "MakeParser");
g_phpstate->dwSampleSize = GetSampleSize(g_phpstate->hParser);
// The remaining info are comm configuration, which we'll add to the
// current comm configuration. Open the comm port so we can get the
// comm state.
g_phpstate->hComPort = CreateFile(g_phpstate->wszCommPort, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == g_phpstate->hComPort || NULL == g_phpstate->hComPort) {
_JumpLastError(hr, error, "CreateFile");
}
// Set the Comm state based on
// a) the existing Comm state
// and b) Comm config found in the registry
if (!GetCommState(g_phpstate->hComPort, &g_phpstate->dcb)) {
_JumpLastError(hr, error, "GetCommState");
}
g_phpstate->dcb.BaudRate = phpc->dwBaudRate;
g_phpstate->dcb.ByteSize = (BYTE)phpc->dwByteSize;
g_phpstate->dcb.Parity = (BYTE)phpc->dwParity;
g_phpstate->dcb.StopBits = (BYTE)phpc->dwStopBits;
// BUGBUG: pulled these values from timeserv.c. Need to document
// why they work??
g_phpstate->dcb.fOutxCtsFlow = FALSE;
g_phpstate->dcb.fDsrSensitivity = FALSE;
g_phpstate->dcb.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(g_phpstate->hComPort, &g_phpstate->dcb)) {
_JumpLastError(hr, error, "SetCommState");
}
// create the events used by the hw prov
g_phpstate->hStopEvent = CreateEvent(NULL/*security*/, TRUE/*manual*/, FALSE/*state*/, NULL/*name*/);
if (NULL == g_phpstate->hStopEvent) {
_JumpLastError(hr, error, "CreateEvent");
}
g_phpstate->hProvThread_EnterOrLeaveThreadTrapEvent = CreateEvent(NULL/*security*/, FALSE/*auto*/, FALSE/*state*/, NULL/*name*/);
if (NULL == g_phpstate->hProvThread_EnterOrLeaveThreadTrapEvent) {
_JumpLastError(hr, error, "CreateEvent");
}
g_phpstate->hProvThread_ThreadTrapTransitionCompleteEvent = CreateEvent(NULL/*security*/, FALSE/*auto*/, FALSE/*state*/, NULL/*name*/);
if (NULL == g_phpstate->hProvThread_ThreadTrapTransitionCompleteEvent) {
_JumpLastError(hr, error, "CreateEvent");
}
g_phpstate->hProvThread = CreateThread(NULL, NULL, HwProvThread, NULL, 0, &dwThreadID);
if (NULL == g_phpstate->hProvThread) {
_JumpLastError(hr, error, "CreateThread");
}
hr = S_OK;
error:
if (NULL != phpc) {
FreeHwProvConfig(phpc);
}
if (FAILED(hr)) {
StopHwProv();
}
return hr;
}
//--------------------------------------------------------------------------------
//
// PROVIDER INTERFACE IMPLEMENTATION
//
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------
HRESULT __stdcall
TimeProvOpen(IN WCHAR * wszName, IN TimeProvSysCallbacks * pSysCallbacks, OUT TimeProvHandle * phTimeProv) {
HRESULT hr;
if (NULL != g_phpstate) {
hr=HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED);
_JumpError(hr, error, "(provider init)");
}
hr = StartHwProv(pSysCallbacks);
_JumpIfError(hr, error, "StartHwProv");
*phTimeProv = 0; /*ignored*/
hr=S_OK;
error:
return hr;
}
//--------------------------------------------------------------------
HRESULT __stdcall
TimeProvCommand(IN TimeProvHandle hTimeProv, IN TimeProvCmd eCmd, IN TimeProvArgs pvArgs) {
HRESULT hr;
LPCWSTR wszProv;
if (0 != hTimeProv) {
hr = HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
_JumpError(hr, error, "HwTimeProvCommand: provider handle verification");
}
switch (eCmd)
{
case TPC_TimeJumped:
hr = HandleTimeJump((TpcTimeJumpedArgs *)pvArgs);
_JumpIfError(hr, error, "HandleTimeJump");
break;
case TPC_UpdateConfig:
hr = HandleUpdateConfig();
_JumpIfError(hr, error, "HandleUpdateConfig");
break;
case TPC_GetSamples:
hr = HandleGetSamples((TpcGetSamplesArgs *)pvArgs);
_JumpIfError(hr, error, "HandleGetSamples");
break;
case TPC_PollIntervalChanged: // BUGBUG: unnecessary until we add support for polling
case TPC_NetTopoChange: // unnecessary for HW prov
// Don't need to do anything here.
break;
case TPC_Query:
hr = HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
_JumpError(hr, error, "HwTimeProvCommand");
case TPC_Shutdown:
hr=StopHwProv();
_JumpIfError(hr, error, "StopHwProv");
break;
default:
hr=HRESULT_FROM_WIN32(ERROR_BAD_COMMAND);
_JumpError(hr, error, "(command dispatch)");
}
hr=S_OK;
error:
return hr;
}
//--------------------------------------------------------------------
HRESULT __stdcall
TimeProvClose(IN TimeProvHandle hTimeProv) {
HRESULT hr;
LPCWSTR wszProv;
if (0 != hTimeProv) {
hr=HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE);
_JumpError(hr, error, "(provider handle verification)");
}
hr=StopHwProv();
_JumpIfError(hr, error, "StopHwServer");
hr=S_OK;
error:
return hr;
}