该例子演示了利用微软Net框架的Web服务与天气预报站点的硬件进行数据交换来实现Web天气预报的服务
微软力推Net的目的用他自己的话来说就是使人们能够在任何时候任何地点以及任何设备上通过我们开发的软件发挥最大的潜能在这里大多数人可能认为微软所讲的任何设备是指袖珍PC手持设备台式电脑及笔记本电脑等下面的例子我们将向大家展示Net如何使那些电脑硬件设备驱动程序开发人员发挥自己的潜能这些设备驱动程序可能和一些专用的PC控制器或PC的标准端口直接通讯这些驱动程序开发人员大多依靠Windows的驱动开发工具包(DDK)及其其他各种工具如可安装文件系统开发工具包(IFS)等虽然这些微软的工具包并没有随着Net的推出而改变但是Net构架仍然给这些硬件设备开发带来了新的机遇
我们将要构造的示例方案的目的就是通过专用的PC卡自动采集来自于不同天气情报采集点的天气信息PC卡可以通过每个采集点的标识ID来同时控制每个采集点的数据按要求每个采集点可以提供该点的温度湿度和气压等数据
我们的目标是让用户通过互联网(Web)获得指定采集点的天气预报信息接下来我们开始结构设计首先需要为PC卡写一个Windows的驱动程序以便PC卡可以读取指定采集点的天气信息另外我们还需要利用Net构造一个网络服务(Web Service)以便互联网用户可以通过Internet访问采集到的天气信息数据
Net的托管代码是不能直接访问Windows的内核的所有我们必须先利用非托管代码写一个用户级(User level)的模块以便网络服务和PC卡的驱动程序之间可以相互交流数据
PC卡的驱动程序接口
假设我们PC采集卡已安装到专用PC上而且采集点到PC采集开的信号电缆也连接好接下来的任务就是驱动程序开发人员开始开发硬件驱动程序
我们并不打算深入研究如何开发PC卡的硬件驱动程序其实网上有很多介绍开发驱动程序的工具和资源也有一些介绍在NT和XP下开发驱动程序差异的文章我们的主要目的是关心采集数据的封装形式以及用户模块和驱动程序通讯的方法
我们准备有下面定义的结构来封装采集到的数据
typedef struct {
unsigned long stationID;
unsigned long state; // for management purposes
unsigned long timeStamp;
double temperature; // celcius
double humidity; // percent
double airPressure; // millibar
} WEATHER_DATA *PWEATHER_DATA;
从PC卡读取数据我们可以利用Win API DeviceIOControl()为了调用该函数设备驱动程序和用户程序必须共享用户定义的IOCTL码为了简单起见我们用WEATHER_DATA结构表示用户程序和驱动程序共享的数据缓沖区但是在实际应用中应该小心谨慎您可以参考微软的技术文章Q和Q
用户要求得到指定的采集点的天气信息的过程如下
用户程序分配WEATHER_DATA结构设置 stationID 和 dataTag
用户程序利用Win API CreateFile()打开与PC卡相关联的设备句柄
用户程序调用DeviceIOControl()并将结构 WEATHER_DATA 作为参数
驱动程序处理调用利用用户选择的数据采集点的数据填充WEATHER_DATA数据缓沖区(在我们的例子中用虚拟数据以模仿显示中的数据采集)
驱动程序返回数据个用户程序结束DeviceIOControl()调用
用户程序处理得到的数据
以下的头定义文件为驱动程序和用户程序共用
// weather_commonh
// Common definitions used by both user level module and
// kernel driver
//
#define WEATHER_TYPE
// The IOCTL function codes from x to xFFF
// are for customer use
#define IOCTL_GET_WEATHER_DATA
CTL_CODE( WEATHER_TYPE x METHOD_BUFFERED FILE_READ_ACCESS | FILE_WRITE_ACCESS)
// Define common used weather data structure
typedef struct {
unsigned long stationID;
unsigned long state;
unsigned long timeStamp;
double temperature;
double humidity;
double airPressure;
} WEATHER_DATA *PWEATHER_DATA;
接下来的代码是用户端的实现
// UserLevelModulecpp
//
// Implementation of user level module
DWORD dwBytesReturned;
// Create structure and fill initial data
WEATHER_DATA dataStruct;
// specify station to request
dataStructstationID = stationID;
// Open driver
HANDLE hDriver;
hDriver = CreateFile(\\\Device\WeatherDevice);
// Issue control call to driver passing prepared structure
DeviceIOControl(hDriverIOCTL_WEATHER_DATA
(void*)&dataStructsizeof(dataStruct)
(void*)&dataStructsizeof(dataStruct)
&dwBytesReturnedNULL);
// If succeeded the structure now contains
// the requested data in data
// Close driver
CloseHandle(hDriver);
接下来是驱动程序的部分代码
// WeatherDrvc
//
// Implementation of kernel driver
NTSTATUS
WeatherDispatch(
IN PDEVICE_OBJECT DeviceObject
IN PIRP Irp
)
{
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
// Dispatch based on major fcn code
switch (pIrpStack>MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
// Dispatch on IOCTL
switch (pIrpStack>ParametersDeviceIoControl
IoControlCode)
{
case IOCTL_GET_WEATHER_DATA:
pWeatherData = (PWEATHER_DATA)
pIrp>AssociatedIrpSystemBuffer;
if(pWeatherData != NULL)
{
// Fill time stamp in data structure
KeQuerySystemTime(&sysTime);
RtlTimeToTimeFields(&sysTime&tFields);
pWeatherData>timeStamp = tFieldsSecond
+ * tFieldsMinute
+ * tFieldsHour;
// Emulate controller card work with
// sample data
pWeatherData>temperature = ;
pWeatherData>humidity = ;
pWeatherData>airPressure = ;
}
pIrp>IoStatusInformation =
sizeof(WEATHER_DATA);
break;
default:
break;
}
Status = STATUS_SUCCESS;
break;
// Complete request
}
用户端代码
驱动程序以及驱动程序和用户程序的通讯协议定义好了以后接下来就是开发用户端模块了
我们可以开发一个应用程序或者动态连接库在这里我们实现一个动态连接库以下代码演示了如何输出一个函数供外部调用
// weatherDrvCtrlh
//
// Declaration of GetWeatherData()
DWORD WINAPI GetWeatherData(WEATHER_DATA* pData);
// weatherDrvCtrlcpp
//
// Definition of GetWeatherData()
DWORD WINAPI GetWeatherData(
WEATHER_DATA* pData)
{
HANDLE hDriver;
DWORD dwErr = ERROR_SUCCESS;
DWORD dwBytesReturned;
// Open driver
HANDLE hDriver;
hDriver = CreateFile(DRIVER_DEVICE_NAME);
if(hDriver != INVALID_HANDLE_VALUE)
{
// Issue control call to driver
// passing prepared structure
dwErr = DeviceIOControl(hDriverIOCTL_WEATHER_DATA
(void*)&dataStructsizeof(dataStruct)
(void*)&dataStructsizeof(dataStruct)
&dwBytesReturnedNULL);
if(!dwErr)
{
// If succeeded the structure now contains
// requested data in data field
}
// Close driver
CloseHandle(hDriver);
}
else
{
// Handle device open error;
}
return dwErr;
}
附件的weatherDrvCtrl项目是用Visual Studio Net构造的我们还提供了一个Win的应用程序以供你测试应用程序(weatherDrvCtrl)和驱动程序(weatherDrv)
到现在为止我们已经完成了驱动程序和用户端调用的所有工作任何用户程序都可以通过调用动态库输出函数得到指定采集点的天气信息数据
网络服务Web Service
下面我们来实现Net的网络服务以便互联网用户可以享受我们的服务利用Visual Studio Net创建Web Service很简单
启动Visuao Studio Net;
新健一个新项目选择 C# ASP Net Web服务
编写数据结构
[ StructLayout( LayoutKindSequential )]
public struct WeatherData
{
public UInt stationID;
public UInt state;
public UInt timeStamp;
public Double temperature;
public Double humidity;
public Double airPressure;
}
利用属性DllImport绑定动态库weatherDrvCtrlDLL
[DllImport(weatherDrvCtrldll)]
static extern unsafe uint GetWeatherData
(ref WeatherData data);
创建一个Web方法
[WebMethod(Description=Get weather data and station state from specified weather station)]
public unsafe WeatherData
QueryWeatherData(uint stationID)
{
// Create and initialize data structure
WeatherData weatherData = new WeatherData();
weatherDatastationID = stationID;
// Call user level wrapper for device driver
uint dwRet = GetWeatherData(ref weatherData);
// If call failed hqndle error here
return weatherData;
}
生成并测试
如果您按照上述过程正确操作应该得到结果这是一个重要的里程碑因为你已经创建了一个完整的Web服务您可以注册您的服务让更多的人使用它(具体的注册Web服务请参考)(代码实验室)