支持 WPD 属性命令 (WpdBasicHardwareDriverSample)
示例驱动程序支持六个属性命令。 这些命令最初由 WpdObjectProperties::D ispatchMessage 方法进行处理,该方法反过来又调用相应的命令处理程序。 DispatchMessage 方法和各个处理程序都在 WpdObjectProperties.cpp 文件中找到。
下表中的信息描述了每个受支持的属性命令,以及 WpdObjectProperties::D ispatchMessage 在处理给定命令时调用的处理程序的名称。
命令 | Handler | 说明 |
---|---|---|
WPD_COMMAND_OBJECT_PROPERTIES_GET_SUPPORTED | OnGetSupportedProperties | 返回给定对象的属性键数组。 |
WPD_COMMAND_OBJECT_PROPERTIES_GET | OnGetPropertyValues | 返回属性值的集合,该值对应于提供给驱动程序的属性键。 |
WPD_COMMAND_OBJECT_PROPERTIES_GET_ALL | OnGetAllProperties | 返回给定对象的所有属性值。 |
WPD_COMMAND_OBJECT_PROPERTIES_SET | OnSetPropertyValues | 设置设备上的指定属性值。 |
WPD_COMMAND_OBJECT_PROPERTIES_GET_ATTRIBUTES | OnGetPropertyAttributes | 返回给定对象上一个或多个属性的属性集合。 |
WPD_COMMAND_OBJECT_PROPERTIES_DELETE | OnDeleteProperties | 删除由给定属性键标识的属性。 |
WPD_COMMAND_OBJECT_PROPERTIES_GET_SUPPORTED
驱动程序调用 WpdObjectProperties::OnGetSupportedProperties 处理程序,以响应 WPD_COMMAND_OBJECT_PROPERTIES_GET_ SUPPORTED 命令。 处理程序依次调用 AddSupportedPropertyKeys 方法来检索所请求对象的支持键。
由于示例设备不支持 WpdHelloWorldSample 驱动程序中的 Storage、Folder 或 File 对象,并且新驱动程序支持在原始驱动程序中找不到的对象,因此需要更新 AddSupportedPropertyKeys 方法。
以下代码取自修改后的 AddSupportedPropertyKeys 方法。 此方法调用两个支持方法 (AddDevicePropertyKeys 和 AddSensorPropertyKeys) 来检索所请求对象的密钥:
HRESULT AddSupportedPropertyKeys(
LPCWSTR wszObjectID,
IPortableDeviceKeyCollection* pKeys)
{
HRESULT hr = S_OK;
CAtlStringW strObjectID = wszObjectID;
// Add Common PROPERTYKEYs for ALL WPD objects
AddCommonPropertyKeys(pKeys);
if (strObjectID.CompareNoCase(WPD_DEVICE_OBJECT_ID) == 0)
{
// Add the PROPERTYKEYs for the 'DEVICE' object
AddDevicePropertyKeys(pKeys);
}
// Add other PROPERTYKEYs for other supported objects...
if (
(strObjectID.CompareNoCase(SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(TEMP_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(FLEX_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(PIR_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(PING_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(QTI_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(MEMSIC_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(HITACHI_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(PIEZO_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(COMPASS_SENSOR_OBJECT_ID) == 0)
)
{
// Add the PROPERTYKEYs for the Sensor object
AddSensorPropertyKeys(pKeys);
}
return hr;
}
WPD_COMMAND_OBJECT_PROPERTIES_GET
驱动程序调用 WpdObjectProperties::OnGetPropertyValues 处理程序以响应 WPD_COMMAND_OBJECT_PROPERTIES_GET 命令。 处理程序又调用 GetPropertyValuesForObject 方法来检索所请求属性的当前值。 由于传感器设备不支持在 WpdHelloWorldSample 驱动程序中找到的 Storage、Folder 或 File 对象,并且由于新驱动程序支持在原始驱动程序中找不到的对象,因此有必要更新此方法。
返回 Device 对象的属性的代码保持不变。 这是返回固件版本、电源级别、电源、设备协议、设备型号等的代码。
尽管此代码未更改,但示例驱动程序返回的设备模型 (和其他类似属性) 不同于 WpdHelloWorldSample 驱动程序返回的属性值。 这是因为我们更新了 WpdObjectProperties.h 中的定义:
#define DEVICE_PROTOCOL_VALUE L"Sensor Protocol ver 1.00"
#define DEVICE_FIRMWARE_VERSION_VALUE L"1.0.0.0"
#define DEVICE_POWER_LEVEL_VALUE 100
#define DEVICE_MODEL_VALUE L"RS232 Sensor"
#define DEVICE_FRIENDLY_NAME_VALUE L"Parallax BS2 Sensor"
#define DEVICE_MANUFACTURER_VALUE L"Windows Portable Devices Group"
#define DEVICE_SERIAL_NUMBER_VALUE L"01234567890123-45676890123456"
#define DEVICE_SUPPORTS_NONCONSUMABLE_VALUE FALSE
下表列出了 WpdObjectProperties.h 中的定义、WpdHelloWorldSample 中的原始值,以及示例驱动程序中指定的新值。
定义 | 原始值 | 新值 |
---|---|---|
DEVICE_PROTOCOL_VALUE | Hello World 协议 v1.00 | 传感器协议 v1.00 |
DEVICE_FIRMWARE_VERSION | 1.0.0.0 | 1.0.0.0 |
DEVICE_POWER_LEVEL | 100 | 100 |
DEVICE_MODEL_VALUE | Hello World! | RS-232 传感器 |
DEVICE_FRIENDLY_NAME | Hello World! | 视差 BS2 传感器 |
DEVICE_MANUFACTURER_VALUE | WPD 组 | WPD 组 |
DEVICE_SERIAL_NUMBER_VALUE | 012345678901234567890123456 | 012345678901234567890123456 |
DEVICE_SUPPORTS_NONCONSUMABLE_VALUE | FALSE | FALSE |
对 GetPropertyValuesForObject 方法的最重大更改发生在检索传感器属性的 部分中。 此代码检索 在 WpdObjectProperties.h 中定义的多个值,例如对象名称、格式、内容类型以及是否可以删除它。
此外,此代码还检索当前传感器读数和传感器更新间隔。 通过调用两个帮助程序函数( GetSensorReading 和 GetUpdateInterval)检索最后两个属性。
GetPropertyValuesForObject 方法的以下摘录包含检索传感器对象属性的代码:
// Retrieve the sensor properties
else if (
(strObjectID.CompareNoCase(SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(TEMP_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(FLEX_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(PIR_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(PING_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(QTI_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(MEMSIC_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(HITACHI_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(PIEZO_SENSOR_OBJECT_ID) == 0) ||
(strObjectID.CompareNoCase(COMPASS_SENSOR_OBJECT_ID) == 0)
)
{
for (DWORD dwIndex = 0; dwIndex < cKeys; dwIndex++)
{
PROPERTYKEY Key = WPD_PROPERTY_NULL;
hr = pKeys->GetAt(dwIndex, &Key);
CHECK_HR(hr, "Failed to get PROPERTYKEY at index %d in collection", dwIndex);
if (hr == S_OK)
{
// Preset the property value to 'error not supported'. The actual value
// will replace this value, if read from the device.
pValues->SetErrorValue(Key, HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED));
if (IsEqualPropertyKey(Key, WPD_OBJECT_ID))
{
hr = pValues->SetStringValue(WPD_OBJECT_ID, strObjectID);
CHECK_HR(hr, "Failed to set WPD_OBJECT_ID");
}
else if (IsEqualPropertyKey(Key, WPD_OBJECT_PERSISTENT_UNIQUE_ID))
{
// Retrieve the ID of the sensor using the m_SensorType member of the
// basedriver that is set during the data-read operation.
hr = pValues->SetStringValue(WPD_OBJECT_PERSISTENT_UNIQUE_ID, strObjectID);
CHECK_HR(hr, "Failed to set WPD_OBJECT_PERSISTENT_UNIQUE_ID");
}
else if (IsEqualPropertyKey(Key, WPD_OBJECT_PARENT_ID))
{
hr = pValues->SetStringValue(WPD_OBJECT_PARENT_ID, WPD_DEVICE_OBJECT_ID);
CHECK_HR(hr, "Failed to set WPD_OBJECT_PARENT_ID");
}
else if (IsEqualPropertyKey(Key, WPD_OBJECT_NAME))
{
// Retrieve the name of the sensor using the m_SensorType member of the
// basedriver that is set during the data-read operation.
if (m_pBaseDriver->m_SensorType == 0)
hr = pValues->SetStringValue(WPD_OBJECT_NAME, SENSOR_OBJECT_NAME_VALUE);
else if (m_pBaseDriver->m_SensorType == 2)
hr = pValues->SetStringValue(WPD_OBJECT_NAME, TEMP_SENSOR_OBJECT_NAME_VALUE);
else if (m_pBaseDriver->m_SensorType == 3)
hr = pValues->SetStringValue(WPD_OBJECT_NAME, FLEX_SENSOR_OBJECT_NAME_VALUE);
else if (m_pBaseDriver->m_SensorType == 4)
hr = pValues->SetStringValue(WPD_OBJECT_NAME, PING_SENSOR_OBJECT_NAME_VALUE);
else if (m_pBaseDriver->m_SensorType == 5)
hr = pValues->SetStringValue(WPD_OBJECT_NAME, PIR_SENSOR_OBJECT_NAME_VALUE);
else if (m_pBaseDriver->m_SensorType == 6)
hr = pValues->SetStringValue(WPD_OBJECT_NAME, MEMSIC_SENSOR_OBJECT_NAME_VALUE);
else if (m_pBaseDriver->m_SensorType == 7)
hr = pValues->SetStringValue(WPD_OBJECT_NAME, QTI_SENSOR_OBJECT_NAME_VALUE);
else if (m_pBaseDriver->m_SensorType == 8)
hr = pValues->SetStringValue(WPD_OBJECT_NAME, PIEZO_SENSOR_OBJECT_NAME_VALUE);
else if (m_pBaseDriver->m_SensorType == 9)
hr = pValues->SetStringValue(WPD_OBJECT_NAME, HITACHI_SENSOR_OBJECT_NAME_VALUE);
CHECK_HR(hr, "Failed to set WPD_OBJECT_NAME");
}
else if (IsEqualPropertyKey(Key, WPD_OBJECT_FORMAT))
{
hr = pValues->SetGuidValue(WPD_OBJECT_FORMAT, WPD_OBJECT_FORMAT_UNSPECIFIED);
CHECK_HR(hr, "Failed to set WPD_OBJECT_FORMAT");
}
else if (IsEqualPropertyKey(Key, WPD_OBJECT_CONTENT_TYPE))
{
hr = pValues->SetGuidValue(WPD_OBJECT_CONTENT_TYPE, WPD_CONTENT_TYPE_FUNCTIONAL_OBJECT);
CHECK_HR(hr, "Failed to set WPD_OBJECT_CONTENT_TYPE");
}
else if (IsEqualPropertyKey(Key, WPD_OBJECT_CAN_DELETE))
{
hr = pValues->SetBoolValue(WPD_OBJECT_CAN_DELETE, FALSE);
CHECK_HR(hr, "Failed to set WPD_OBJECT_CAN_DELETE");
}
else if (IsEqualPropertyKey(Key, SENSOR_READING))
{
hr = pValues->SetUnsignedLargeIntegerValue(SENSOR_READING, GetSensorReading());
CHECK_HR(hr, "Failed to set SENSOR_READING");
}
else if (IsEqualPropertyKey(Key, SENSOR_UPDATE_INTERVAL))
{
hr = pValues->SetUnsignedLargeIntegerValue(SENSOR_UPDATE_INTERVAL, GetUpdateInterval());
CHECK_HR(hr, "Failed to set SENSOR_UPDATE_INTERVAL");
}
else if (IsEqualPropertyKey(Key, WPD_FUNCTIONAL_OBJECT_CATEGORY))
{
hr = pValues->SetGuidValue(WPD_FUNCTIONAL_OBJECT_CATEGORY, FUNCTIONAL_CATEGORY_SENSOR_SAMPLE);
CHECK_HR(hr, "Failed to set WPD_FUNCTIONAL_OBJECT_CATEGORY");
}
}
} // end for
} // end else if
GetSensorReading 帮助程序函数检索数字 (DWORD) 格式的最新传感器读数:
LONGLONG WpdObjectProperties::GetSensorReading()
{
// Ensure that this value isn't currently being accessed by another thread
CComCritSecLock<CComAutoCriticalSection> Lock(m_SensorReadingCriticalSection);
return m_llSensorReading;
}
注意 需要一个关键节来阻止 m_llSensorReading 成员变量的并发访问。 当每个 RS232 读取以异步方式完成时,都会覆盖此值,并且每当 WPD 应用程序检索SENSOR_READING属性时,都会读取此值。
GetUpdateInterval 帮助程序函数执行相同的操作:它访问 m_dwUpdateInterval 成员变量,并返回数值 (DWORD) 格式的值(如果可用):
DWORD WpdObjectProperties::GetUpdateInterval()
{
return m_dwUpdateInterval;
}
请注意,如果多个线程将访问此值 (, m_dwUpdateInterval 成员变量必须受到关键节的保护,例如,如果使用 WDF 并行调度队列而不是顺序调度队列,或者修改 WpdBaseDriver::P rocessReadData 以在初始化) 期间多次设置更新间隔而不是一次。 为简单起见,省略了关键部分。
WPD_COMMAND_OBJECT_PROPERTIES_GET_ALL
驱动程序调用 WpdObjectProperties::OnGetAllPropertyValues 处理程序以响应 WPD_COMMAND_OBJECT_PROPERTIES_GET_ALL 命令。 处理程序又检索给定对象的所有属性键,然后调用 GetPropertyValuesForObject 帮助程序函数来检索所请求属性的当前值。
WPD_COMMAND_OBJECT_PROPERTIES_SET
驱动程序调用 WpdObjectProperties::OnSetPropertyValues 处理程序以响应 WPD_COMMAND_OBJECT_PROPERTIES_SET 命令。 唯一可以在示例驱动程序中写入或设置) (属性是SENSOR_UPDATE_INTERVAL。
处理程序首先检查给定属性的对象标识符,然后检查属性键本身。 如果对象标识符设置为 SENSOR_OBJECT_ID 并且属性键SENSOR_UPDATE_INTERVAL,则处理程序将调用 SendUpdateIntervalToDevice 帮助程序函数来更新值。
SendUpdateIntervalToDevice 帮助程序函数通过检查有效输入值、使用该值格式化写入请求,然后将写入请求发送到设备来执行写入操作。
HRESULT WpdObjectProperties::SendUpdateIntervalToDevice(DWORD dwNewInterval)
{
HRESULT hr = S_OK;
RS232Target* pDeviceTarget = NULL;
CHAR szInterval[INTERVAL_DATA_LENGTH+1] = {0};
// Check the input value
if (IsValidUpdateInterval(dwNewInterval) == FALSE)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
CHECK_HR(hr, "Invalid update interval: %d", dwNewInterval);
}
// Format a write request with the input value
if (hr == S_OK)
{
hr = StringCchPrintfA(szInterval,
ARRAYSIZE(szInterval), "%d", dwNewInterval);
CHECK_HR(hr, "Failed to convert the new interval to a CHAR string");
}
// Send the write request to the device
if (hr == S_OK)
{
pDeviceTarget = m_pBaseDriver->GetRS232Target();
if (pDeviceTarget->IsReady())
{
hr = pDeviceTarget->
SendWriteRequest((BYTE *)szInterval, sizeof(szInterval));
CHECK_HR(hr,
"Failed to send the write request to
set the new temperature update interval");
if (hr == S_OK)
{
TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_FLAG_DRIVER,
"%!FUNC! Sent new interval: %s", szInterval);
}
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);
CHECK_HR(hr, "Device is not ready to receive write requests");
}
}
if (hr == S_OK)
{
// Update the cached value on the driver
SetUpdateInterval(dwNewInterval);
}
return hr;
}
WPD_COMMAND_OBJECT_PROPERTIES_GET_ATTRIBUTES
驱动程序调用 WpdObjectProperties::OnGetPropertyAttributes 处理程序以响应 WPD_COMMAND_OBJECT_PROPERTIES_GET_ATTRIBUTES 命令。 处理程序又调用 GetPropertyAttributesForObject 帮助程序函数来检索给定对象的属性。
在原始 WpdHelloWorldSample 驱动程序中,每个属性的属性都相同,并且所有属性都是只读的。 但是,在更新的驱动程序中,SENSOR_UPDATE_INTERVAL是可读/写的,SENSOR_UPDATE_INTERVAL和SENSOR_READING的形式WPD_PROPERTY_ATTRIBUTE_FORM_RANGE。 因此,需要对此帮助程序函数进行细微更改。