开发网络防火墙技术分析,Socket编程实现网络封包监视
分类:高并发

 N-Byte网络守望者是一款单机版互连网安全工具,简言之,正是三个用.NET开辟的私人商品房版防火墙。在N-Byte网络守望者1.0版的支付中,使用了NDIS Hook Driver才具来兑现互联网封包过滤效果,那使N-Byte互联网守望者能够在互联网层过滤网络封包,进而实现强盛的效果。

1 何以编写WINDOWS CE.NET的USB驱动程序 

在合营开辟时,C#时常须要调用C++DLL,当传递参数时日常遭遇标题,越发是传递和再次来到字符串是,现总计一下,分享给我们:

谈到socket编程,大家可能会想起QQ和IE,没错。还也可能有众多网络工具如P2P、NetMeeting等在应用层达成的应用程序,也是用socket来贯彻的。Socket是八个网络编制程序接口,完结于互联网应用层,Windows Socket包涵了一套系统组件,丰硕利用了Microsoft Windows 新闻使得的特色。Socket标准1.1版是在一九九二年十二月发行的,并大规模用于以前面世的Windows9x操作系统中。Socket标准2.2版(其在Windows平台上的本子是Winsock2.2,也叫Winsock2)在 壹玖玖捌 年 5 月发行,Windows NT 5.0及未来版本的Windows系统辅助Winsock2,在Winsock第22中学,帮助多少个传输公约的原始套接字,重叠I/O模型、服务品质调整等。

  由于软件的主程序是用C#写的,C#中绝非提供具备相像DeviceIoControl函数功效的驱动装置调整函数,而NDIS Hook Driver技艺下的驱动程序是用DDK下的C语言写的,为了能够完毕主程序对驱动程序的支配和互相通讯,选用了以下解决方案:

 

VC++中首要性字符串类型为:LPST昂Cora,LPCSTCRUISER, LPCTSTCRUISER, string, CString, LPCWSTLX570, LPWST奥迪Q3等
但转为C#花色却不完全近似。

正文向我们介绍Windows Sockets的片段关于用C#落到实处的原始套接字(Raw SocketState of Qatar的编程,以致在那幼功上完结的互连网封包监视技艺。同Winsock1比照,Winsock2最刚强的就是永葆了Raw Socket套接字类型,使用Raw Socket,可把网卡设置成混杂情势,在这里种形式下,大家得以接收网络上的IP包,当然包罗指标不是本机的IP包,通过原始套接字,大家也足以特别应付裕如地决定Windows下的多样共谋,何况能够对互联网底层的传导体制进行调控。

  在以上方案中,需求七个担负主程序与NDIS Hook Driver驱动程序通讯与调节的模块DriverDll.dll,并用C#编写制定的一个卷入驱动程序中封包消息的模块,能够发送那几个驱动程序音信到主程序,主程序可识别并操作模块中的数据类型。

乘胜USB设备的推广,摆在开辟人士前面的驱动开发职分也是进一层艰巨了,极其是对此部分嵌入式开垦商家来说,由于设备所使用的操作系统不相同,相应的硬件接口也是区别的,开辟相关的USB驱动程序更是难乎其难。Windows CE.NET 是微软推出的功效强大的嵌入式操作系统,国内应用此操作系统的厂家已经重重了,本文就以windows ce.net为例,简介一下怎么支付windows ce.net下的USB驱动程序。

根本好似下两种转移:

在本文例子中,小编在nbyte.BasicClass命名空间达成了RawSocket类,它含有了大家落到实处数量包监视的主题技艺。在实现这几个类早前,须求先写一个IP头构造,来一时贮存一些有关互联网封包的新闻:

  在.NET应用程序使用驱动程序的标题上,面前境遇着多个难题:

 

将string转为IntPtr:IntPtr System.Runtime.InteropServices.Marshal.StringToCoTaskMemAuto(string)

[StructLayout(LayoutKind.Explicit)]
public struct IPHeader
{
[FieldOffset(0)] public byte ip_verlen; //I4位首院长度+4位IP版本号
[FieldOffset(1)] public byte ip_tos; //8位服务类型TOS
[FieldOffset(2)] public ushort ip_totallength; //十八位数据包总参谋长度(字节)
[FieldOffset(4)] public ushort ip_id; //16位标识
[FieldOffset(6)] public ushort ip_offset; //3位标识位
[FieldOffset(8)] public byte ip_ttl; //8位生存时间 TTL
[FieldOffset(9)] public byte ip_protocol; //8位协议(TCP, UDP, ICMP, Etc.)
[FieldOffset(10)] public ushort ip_checksum; //13位IP首部校验和
[FieldOffset(12)] public uint ip_srcaddr; //32位源IP地址
[FieldOffset(16)] public uint ip_destaddr; //32位目的IP地址
}

  1.怎样落到实处.NET应用程控驱动程序的职能?

先是要理解一些USB的基本概念,当然最棒把USB 1.1的情商看壹遍,(当然现在2。0的会谈都曾经有了)

将IntPtr转为string:string System.Runtime.InteropServices.MarshalPtrToStringAuto(IntPtr)

这么,当每二个封包到达时候,能够用压迫类型转变把包中的数据流转变为贰个个IPHeader对象。
下边就起始写RawSocket类了,一开头,先定义多少个参数,富含:
private bool error_occurred; //套接字在收到包时是否爆发错误
public bool KeepRunning; //是或不是一而再再而三开展
private static int len_receive_buf; //获得的数据流的尺寸
byte [] receive_buf_bytes; //收到的字节
private Socket socket = null; //证明套接字
还会有三个常量:
const int SIO_RCVALL = unchecked((int卡塔尔0x98000001State of Qatar;//监听全体的数码包

  2.怎样从驱动程序向.NET应用程序传递非托管的数据类型?

 

类别对照:

这里的SIO_RCVALL是提示RawSocket接纳全体的数据包,在随后的IOContrl函数中要用,在底下的布局函数中,达成了对部分变量参数的最初化:

  以下是我们就那么些主题材料的详细消除方法:

此间小编就不介绍USB的骨干公约了,假若客户已经深谙了USB设备的有些基本的概念,而且对Winows CE.NET的开支有自然的询问。

BSTR                      ---------            StringBuilder

public RawSocket(State of Qatar //布局函数
{
error_occurred=false;
len_receive_buf = 4096;
receive_buf_bytes = new byte[len_receive_buf];
}

  如何落实.NET应用程控驱动程序的作用?

 

LPCTSTR               ---------            StringBuilder

上边包车型客车函数达成了创办RawSocket,并把它与终结点(IPEndPoint:本机IP和端口)绑定:
public void CreateAndBindSocket(string IP卡塔尔 //创设并绑定套接字
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
socket.Blocking = false; //置socket非窒碍状态
socket.Bind(new IPEndPoint(IPAddress.Parse(IP卡塔尔(قطر‎, 0卡塔尔国卡塔尔(قطر‎; //绑定套接字

  使用托管C++编写的DriverDll.dll来落到实处对驱动程序的一向调整,而主程序通过调用此中的情势来实现对驱动程序的直接调节。比如在NByte.h文件中定义了START_IP_HOOK常数用来作为传给驱动程序用来拉开驱动程序封包过滤效果的参数,下边在托管C++模块中定义了IoCtrl托管类并定义了上面包车型地铁向缓冲区写入参数的艺术:

下边简略介绍一下Windows CE.NET中USB设备驱动开拓的一些底蕴知识。

LPCWSTR              ---------            IntPtr

if (SetSocketOption()==false) error_occurred=true;
}
在那之中,在开创套接字的一句socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IPState of Qatar;中有3个参数:

//向缓冲区写入数据。

 

handle                     ---------           IntPtr

先是个参数是设定地址族,MSDN上的陈述是“钦赐 Socket 实例用来深入分析地址的寻址方案”,当要把套接字绑定到终结点(IPEndPoint)时,需求运用InterNetwork成员,即利用IP版本4之处格式,那也是今后大多套接字编制程序所利用二个寻址方案(AddressFamily)。

DWORD WriteIo(DWORD code,PVOID buffer,DWORD count)

Windows CE.NET 的USB系统软件分为两层: USB Client设备驱动程序和尾巴部分的Windows CE完毕的函数层。USB设备驱动程序首要负担利用系统提供的平底接口配置设施,和装置开展报导。底层的函数提本身又由两局地组成,通用串行总线驱动程序(USBD)模块和异常低的主要调节制器驱动程序(HCD)模块。HCD担任最最尾部的管理,USBD模块实现较高的USBD函数接口。USB设备驱动主要采取USBD接口函数和他们的外围设备打交道。

hwnd                        -----------        IntPtr

其次个参数设置的套接字类型正是我们使用的Raw类型了,SocketType是四个枚举数据类型,Raw套接字类型援救对基本功传输左券的拜望。通过运用 SocketType.Raw,你既能行使传输调节合同(Tcp卡塔尔(قطر‎和客商数量报左券(Udp卡塔尔国进行通信,也得以选择网际新闻调节契约(Icmp卡塔尔(قطر‎ 和 Internet 组管理合同 (Igmp卡塔尔国来开展通讯。在殡葬时,您的应用程序必得提供全体的 IP 标头。所吸纳的多寡报在回去时会保持其 IP 标头和抉择不改变。

{

 

char *                        ----------         string

其八个参数设置公约项目,Socket 类使用 ProtocolType 枚举数据类型向 Windows Socket API 通告所哀告的商议。这里运用的是IP合同,所以要选拔ProtocolType.IP参数。

if(hDriverHandle == NULL)

USB设备驱动程序主要和USBD打交道,所以大家必需详细的问询USBD提供的函数。

int *                            -----------       ref int

在CreateAndBindSocket函数中有三个自定义的SetSocketOption函数,它和Socket类中的SetSocketOption差异,大家在那处定义的是持有IO调控机能的SetSocketOption,它的定义如下:

return ERROR_DRIVER_HANDLE;

 

int &                           -----------       ref int

private bool SetSocketOption() //设置raw socket
{
bool ret_value = true;
try
{
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, 1);
byte []IN = new byte[4]{1, 0, 0, 0};
byte []OUT = new byte[4];

DWORD bytesReturned;

表里相符的传输函数有:

void *                         ----------        IntPtr

//低档别操作方式,选取全体的数据包,这一步是主要,必需把socket设成raw和IP Level才可用SIO_RCVALL
int ret_code = socket.IOControl(SIO_RCVALL, IN, OUT);
ret_code = OUT[0] + OUT[1] + OUT[2] + OUT[3];//把4个8位字节合成三个三12人整数
if(ret_code != 0) ret_value = false;
}
catch(SocketException)
{
ret_value = false;
}
return ret_value;
}

BOOL returnCode = DeviceIoControl(hDriverHandle,

AbourtTransferIssueControlTransfer

unsigned char *      -----               ref byte

在那之中,设置套接字选项时必得使套接字包罗IP邢台,不然不可能填充IPHeader布局,也无从赢得数据包消息。
int ret_code = socket.IOControl(SIO_RCVALL, IN, OUT卡塔尔国;是函数中最入眼的一步了,因为,在windows中我们无法用Receive函数来选拔raw socket上的数量,那是因为,全部的IP包都以先递交给系统主题,然后再传输到客户程序,当发送四个raws socket包的时候(比如syn),宗旨并不知道,也尚无那几个数量被发送或然一而再创立的笔录,由此,当远端主机回应的时候,系统核心就把这个包都全体放弃,进而到持续应用程序上。所以,就不得不难地运用收取函数来抽出这几个数据报。要完成选取数据的指标,就亟须选用嗅探,接纳全部通过的数据包,然后开展挑选,留下切合我们必要的。能够通过安装SIO_RCVALL,表示收到全数互连网上的数据包。接下来介绍一下IOControl函数。MSDN解释它正是设置套接字为低档别操作方式,怎么低端别操作法?其实这几个函数与API中的WSAIoctl函数很相近。WSAIoctl函数定义如下:

code,

CloseTransfer IssueInterrupTransfer

 

int WSAIoctl(
SOCKET s, //三个钦赐的套接字
DWOEvoqueD dwIoControlCode, //调控操作码
LPVOID lpvInBuffer, //指向输入数据流的指针
DWORD cbInBuffer, //输入数据流的尺寸(字节数)
LPVOID lpvOutBuffer, // 指向输出数据流的指针
DWO途观D cbOutBuffer, //输出数据流的大大小小(字节数)
LPDWO阿斯顿·马丁DB11D lpcbBytesReturned, //指向输出字节流数目标实数值
LPWSAOVETiguanLAPPED lpOverlapped, //指向二个WSAOVE兰德酷路泽L应用程式ED构造
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine//指向操作实现时推行的例程
);

buffer,

GetIsochResultIssueIsochTransfer

Struct需要在C#里再一次定义三个Struct

C#的IOControl函数不像WSAIoctl函数那么复杂,此中只包罗内部的调节操作码、输入字节流、输出字节流四个参数,不过那四个参数已经足足了。大家看看函数中定义了三个字节数组:byte []IN = new byte[4]{1, 0, 0, 0}实际上它是二个值为1的DWOENCORED或是Int32,同样byte []OUT = new byte[4];也是,它整和了叁个int,作为WSAIoctl函数中参数lpcbBytesReturned指向的值。
因为安装套接字选项时或者会时有产生错误,必要用贰个值传递错误标识:

count,

GetTransferStatus IstransferComplete

CallBack回调函数须求封装在一个寄托里,delegate static extern int FunCallBack(string strState of Qatar;

public bool ErrorOccurred
{
get
{
return error_occurred;
}
}

NULL,

IssueBulkTransfer IssueVendorTransfer

只顾在各样函数的先头加上public static extern +重临的数据类型,纵然不加public ,函数默认为个人函数,调用就能出错。

下边包车型客车函数完成的数据包的接受:

0,

 

在C#调用C++ DLL封装库时会出现多个难点:

//剖析采用的数据包,产生PacketArrived伊芙ntArgs事件数据类对象,并引发PacketArrival事件
unsafe private void Receive(byte [] buf, int len)
{
byte temp_protocol=0;
uint temp_version=0;
uint temp_ip_srcaddr=0;
uint temp_ip_destaddr=0;
short temp_srcport=0;
short temp_dstport=0;
IPAddress temp_ip;

&bytesReturned,

重点的用于张开和关闭USBD和USB设备之间的通讯通道的函数有:

1. 数据类型转变难点
2. 指南针或地点参数字传送送难点

PacketArrivedEventArgs e=new PacketArrived伊夫ntArgs(卡塔尔(قطر‎;//新网络数据包消息事件

NULL);

AbortPipeTransfersClosePipe

率先是数据类型转变难题。因为C#是.NET语言,利用的是.NET的基本数据类型,所以实际是将C++的数据类型与.NET的着力数据类型进行对应。

fixed(byte *fixed_buf = buf)
{
IPHeader * head = (IPHeader *) fixed_buf;//把数据流整和为IPHeader布局
e.HeaderLength=(uint)(head->ip_verlen & 0x0F) << 2;

 

IsDefaultPipeHalted IsPipeHalted

诸如C++的庐山真面目函数是:

temp_protocol = head->ip_protocol;
switch(temp_protocol)//提取左券项目
{
case 1: e.Protocol="ICMP"; break;
case 2: e.Protocol="IGMP"; break;
case 6: e.Protocol="TCP"; break;
case 17: e.Protocol="UDP"; break;
default: e.Protocol= "UNKNOWN"; break;
}

if(!returnCode)

OpenPipeResetDefaultPipe

int __stdcall FunctionName(unsigned char param1, unsigned short param2)

temp_version =(uint)(head->ip_verlen & 0xF0卡塔尔国 >> 4;//提取IP左券版本
e.IPVersion = temp_version.ToString();

return ERROR_IO_CTRL;

ResetPipe

 

//以下语句提收取了PacketArrived伊夫ntArgs对象中的别的参数
temp_ip_srcaddr = head->ip_srcaddr;
temp_ip_destaddr = head->ip_destaddr;
temp_ip = new IPAddress(temp_ip_srcaddr);
e.OriginationAddress =temp_ip.ToString();
temp_ip = new IPAddress(temp_ip_destaddr);
e.DestinationAddress = temp_ip.ToString();

return SUCCESS;

 

当中的参数数据类型在C#中,必需转为对应的数据类型。如:

temp_srcport = *(short *)&fixed_buf[e.HeaderLength];
temp_dstport = *(short *)&fixed_buf[e.HeaderLength+2];
e.OriginationPort=IPAddress.NetworkToHostOrder(temp_srcport).ToString();
e.DestinationPort=IPAddress.NetworkToHostOrder(temp_dstport).ToString();

}

对应的打包函数接口有:

[DllImport(“ COM DLL path/file ”)]
extern static int FunctionName(byte param1, ushort param2)

e.PacketLength =(uint)len;
e.MessageLength =(uint)len - e.HeaderLength;

  当然平昔利用那个法子不太平价,所以定义一个国有函数,用来提需要主程序调用:

GetFrameLengthGetFrameNumberReleaseFrameLengthControl

 

e.ReceiveBuffer=buf;
//把buf中的IP头赋给PacketArrivedEventArgs中的IPHeaderBuffer
Array.Copy(buf,0,e.IPHeaderBuffer,0,(int)e.HeaderLength);
//把buf中的包中内容赋给PacketArrived伊夫ntArgs中的MessageBuffer
Array.Copy(buf,(int)e.HeaderLength,e.MessageBuffer,0,(int)e.MessageLength);
}
//引发PacketArrival事件
OnPacketArrival(e);
}

//早前行行封包过滤

SetFrameLengthTakeFrameLengthControl

因为调用的是__stdcall函数,所以使用了P/Invoke的调用方法。当中的方法FunctionName必得评释为静态外界函数,即加上extern static证明头。大家能够见到,在调用的经过中,unsigned char变为了byte,unsigned short变为了ushort。转换后,参数的数据类型不改变,只是证明情势必需改为.NET语言的行业内部。

大家只顾到了,在地方的函数中,大家利用了指针这种所谓的不安全代码,可以见到在C#中指针和平运动动运算这几个本来操作也足以给程序员带给编制程序上的方便。在函数中声称PacketArrived伊夫ntArgs类对象,以便通过OnPacketArrival(eState of Qatar函数通过事件把多少包新闻传递出去。此中PacketArrived伊夫ntArgs类是RawSocket类中的嵌套类,它一而再了系统事件(Event)类,封装了数据包的IP、端口、公约等任何数据扬州中带有的音信。在开发银行接收数据包的函数中,大家使用了异步操作的形式,以下函数开启了异步监听的接口:

bool StartIpHook()

 

大家得以经过下表来扩充这种转移:

public void Run(卡塔尔国 //开首监听
{
IAsyncResult ar = socket.BeginReceive(receive_buf_bytes, 0, len_receive_buf, SocketFlags.None, new AsyncCallback(CallReceive), this);
}

{
 return (WriteIo(START_IP_HOOK, NULL, 0)==SUCCESS);
}

获得设置设备配备函数:

Win32 Types

Socket.BeginReceive函数重临了八个异步操作的接口,并在那接口的生成函数BeginReceive中评释了异步回调函数CallReceive,并把选择到的互联网数据流传给receive_buf_bytes,那样就可用四个满含异步操作的接口参数的异步回调函数不断地选择数据包:

  这样,只要在主程序中声称IoCtrl的对象ic,就能够通过ic.StartIpHook(卡塔尔就足以兑现对驱动程序过滤效果的敞开,用同一的艺术也足以达成对驱动程序进行其余操作,例如增多、修正封包过滤法则等。

ClearFeature SetDescriptor


private void CallReceive(IAsyncResult arState of Qatar//异步回调
{
int received_bytes;
received_bytes = socket.EndReceive(ar);
Receive(receive_buf_bytes, received_bytes);
if (KeepRunning) Run();
}

  怎么着从驱动程序向.NET应用程序传递非托管的数据类型?

GetDescriptorSetFeature

CLR Type

此函数当挂起或终止异步读取后去选用一个新的数据包,那样能担保让每一个数额包都能够被前后相继探测到。
下边通过声宋代总管件句柄来达成和外面包车型地铁通讯:

  为了能够出口安整日志,必需让主程序取得驱动程序中的封包音信。使用时限信号量机制得以很便利的贯彻驱动程序和非托管代码间的音讯传送,那么对托管代码呢?那亟需向.NET应用程序传递非托管的数据类型ACCESS_INFO。在NByte.h中,是那般定义那几个ACCESS_INFO结构的:

GetInterface SetInterface

 

public delegate void PacketArrivedEventHandler(Object sender, PacketArrivedEventArgs args);
//事件句柄:包达到时引发平地风波
public event PacketArrived伊芙ntHandler PacketArrival;//注明时间句柄函数

typedef struct _ACCESS_INFO

GetStatusSyncFrame

 

那样就足以兑现对数据包新闻的获得,选用异步回调函数,能够巩固选取数据包的效用,并经过代监护人件把封包消息传递到外边。既然能把装有的封包新闻传送出去,就足以达成对数据包的解析了:)不过RawSocket的天职尚未曾完,最终不要望了关闭套接字啊:

{
 USHORT protocol;
 ULONG sourceIp;
 ULONG destinationIp;
 USHORT sourcePort;
 USHORT destinationPort;
}ACCESS_INFO;

 

char, INT8, SBYTE, CHAR
System.SByte

public void Shutdown() //关闭raw socket
{
if(socket != null)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}

  分明,直接传送非托管数据类型是不得以的,供给转移一下。首先,在IoCtrl类中定义了多少个要传递的封包音讯参数:

与USB举办互相的达成形式有关的多任务函数:

 

上述介绍了RawSocket类经过构造IP头获取了包中的音信,并由此异步回调函数实现了数据包的抽取,并运用时间代理句柄和自定义的数量包音信事件类把数量包消息发送出去,进而完毕了互联网数据包的监视,那样大家就足以在外界增多一些函数对数码包举办解析了。

public __gc class IoCtrl
{
 public:
  USHORT protocol; //网际左券项目
  ULONG sourceIp; //源IP地址
  ULONG destinationIp; //目的IP地址
  USHORT sourcePort; //源端口
  USHORT destinationPort; //目标端口
  ………………
}

FindInterfaceRegisterClientDeviceId

short, short int, INT16, SHORT
System.Int16

  然后,在GetAccessInfo(卡塔尔函数中来给那一个参数赋值:

GetDeviceInfoRegisterClientSettings

 

void GetAccessInfo()
{
 ACCESS_INFO ai;
 bool result=(ReadIo(GET_INFO,&ai,sizeof(ai))==SUCCESS);
 this->protocol=ai.protocol;
 this->sourceIp=ai.sourceIp;
 this->destinationIp=ai.destinationIp;
 this->sourcePort=ai.sourcePort;
 this->destinationPort=ai.destinationPort;

GetUSBDVersion RegisterNotificationRoutine

int, long, long int, INT32, LONG32, BOOL , INT
System.Int32

  既然在IoCtrl类中得到了这个音信,不过急需把它们封装成主程序轻易管理的数据类型,那样,用C#完成了InfoEvent类用来封装那么些消息:

LoadGenericInterfaceDriver TranslateStringDescr

 

//本类封装了数据包的详细音信,能够经过事件达成对它的模块间传递。

OpenClientRegisterKeyUnRegisterNotificationRoutine

__int64, INT64, LONGLONG
System.Int64

public class InfoEvent:EventArgs
{
 string sInfo; //用来寄存输出消息的私人民居房成员
 public int pLength; //CommonFunction.sPort数组的长度
 public ushort protocol; //网络通讯公约类型
 public uint sourceIp; //数据包的源IP
 public uint destinationIp; //数据包的目的IP
 public ushort sourcePort; //数据包的源端口
 public ushort destinationPort; //数据包的指标端口
 ………………………………
}

广阔的Windows CE.NET下USB的设施驱动程序的编排有以下三种艺术:

 

  上边在用托管C++达成的InfoProvider驱动程序音讯提供者类中把个Info伊夫nt类的目的传递给主程序,要求采纳叁个委托生成一个平地风波:

 

unsigned char, UINT8, UCHAR , BYTE
System.Byte

//注解委托事件,用来向主程序传递数据。

● 流式接口函数

 

__delegate void DriverInfo(Object* sender, InfoEvent* e);

这种驱动程序首要表现流式函数接口,首要输出XXX_Init,XXX_Deinit,XXX_Open,XXX_Close,XXX_Open,XXX_Close,XXX_Read,XXX_Write,

unsigned short, UINT16, USHORT, WORD, ATOM, WCHAR , __wchar_t
System.UInt16

//表明响应事件函数。

XXX_Seek,XXX_IOControl,XXX_PowerUp,XXX_PowerDown等流式接口,注意上述的多少个接口一定都要出口,此外XXX必得为多个字符,不然会出错。可是此类的驱动程序不是透过设备管理接口来加载的,所以必得手工业的调用RegisterDevice()和DeregisterDevice()函数来加载和卸载驱动程序。顾客能够将此类的配备作为标准的文书来操作,只要调用相应的文本操作就能够和驱动程序打交道。

 

__event DriverInfo* OnDriverInfo;

 

unsigned, unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT
System.UInt32

  然后在InfoProvider驱动程序音讯提供者类中定义一个艺术,在主程序中以线程的法子运转这几个艺术,在此个艺术中动用了风云函数OnDriverInfo:

● 使用现存的Window CE.NET的应用程序接口

 

//用来获取驱动程序新闻的历程,在主程序校官开启该进度。

此类设备首倘使接纳Windows CE.NET中一度有了现存的函数接口,举例USB Mass Storage Disk,它首要采纳现存的Windows CE.Net中曾经某个可安装文件系统接口,显示给系统可用的文件系统,对于客商来说,它是晶莹剔透的,客商独有感觉在操作二个文件夹。

unsigned __int64, UINT64, DWORDLONG, ULONGLONG
System.UInt64

void GetInfoThreadProc()
{
 this->hEvent=OpenEvent(SYNCHRONIZE,FALSE,"NBEvent");
 if(!ic->GetDriverHandle())
 {
  return;
 }

 

 

 while(true)
 {
  f(!hEvent)
  ExitThread(0);
  WaitForSingleObject(this->hEvent,INFINITE);
  nPackets++;
  ic->GetAccessInfo();
  ic->ResetEvent();
  //定义三个主程序能够辨别的目标,通过OnDriverInfo传给主程序。
  InfoEvent*ie=new InfoEvent(ic->protocol,ic->sourceIp,ic->destinationIp,ic->sourcePort,ic->destinationPort);

● 成立钦命到一定的USBD的客商钦命的API

float, FLOAT
System.Single

  OnDriverInfo(this,ie);
 }

这种方法在USBD显示设备时无需其余约束,首倘诺特制的提供API给客户,平时不太布满。

 

 ic->CloseDriverHandle();
 return;
}

 

double, long double, DOUBLE
System.Double

  在主程序中,会展开这么些历程并定义了OnDriverInfo的管理函数DealWithInfo:

 

今后再将CLXC60的数据类型表示方法调换为C#的代表方法。那样一来,函数的参数类型难点就能够消除了。

pInfo=new InfoProvider();

USB设备驱动程序必得输出的函数有:

几这段日子,大家再来思索下二个标题,假若要调用的函数参数是指针大概地址变量,如何做?

//开启与驱动交流音讯的长河

● USBDeviecAttach

对此这种地方能够使用C#提供的非安全代码来举行减轻,但是,究竟是非托管代码,垃圾能源管理糟糕的话对应用程序是特别不利于的。所以照旧使用C#提供的ref甚至out修饰字相比好。

FilterThread=new Thread(new ThreadStart(pInfo.GetInfoThreadProc));
FilterThread.IsBackground=true;
FilterThread.Start();
pInfo.OnDriverInfo+=new InfoProvider.DriverInfo(DealWithInfo); 

当USB设备连接到Computer上时,USBD模块就能够调用此函数,那一个函数主要用来开首化USB设备,得到USB设备音信,配置USB设备,而且申请务必的财富。

同地点雷同,大家也举二个事例:

  那样主程序就足以在DealWithInfo函数中参加对InfoEvent对象的拍卖了。可以预知,通过中间模块IoCtrl的转移,便达成了.NET主程序对驱动程序中国和欧洲托管数据类型的收获和拍卖。

● USBInstallDriver

int __stdcall FunctionName(unsigned char &param1, unsigned char *param2)

 

注重用以创建二个驱动程序加载所需的注册表消息,比如读写超时,设备名称等。

 

 

● USBUninstallDriver

在C#中对其进行调用的主意是:

<> <>

重中之重用于释放驱动程序所据有的资源,以至去除USBInstallDriver函数成立的注册表等。

[DllImport(“ file ”)]
extern static int FunctionName(ref byte param1, ref byte param2)

上述的四个函数接口是具备的USB驱动程序必需提供的,一个都不能少。

 

除此以外比较重大的是USB设备驱动程序的注册表配置,经常的USB设备驱动程序的注册表配置在HKEY_LOCAL_MACHINEDriversUSBLoadClients下,每种驱动程序的子键都有Group1_IDGroup2_IDGroup3_IDDriverName格式,若是注册表新闻与USB设备音信切合,USBD就能够加载此驱动程序。否则设备的子键应该由中间商,设备类和切磋音信通过下划线组成。

总的来看那,恐怕有人会问,&是取地址,*是传递指针,为何都只用ref就足以了呢?一种大概的演说是ref是五个持有重载天性的修饰符,会自动识别是取地址依然传送指针。

实际的安顿举例:

在实际的状态中,大家利用参数传递地址越多依旧用在传递数组首地址上。
如:byte[] param1 = new param1(6);

比方你有个PDA设备,它有着四个USB接口,它的供应厂家ID假设为0x0888,设备ID为0x0999,未有行使特别的议和,那么它的加载注册表应该写为:

在这里边大家注明了二个数组,现在要将其的首地址传送过去,只要将param1数组的率先个要素用ref修饰。具体如下:

[HKEY_LOCAL_MACHINEDriversUSBLoadClients2184_2457DefaultDefaultPDA] "DLL"="pdausb.dll" 

[DllImport("file")]
extern static int FunctionName(ref byte param1[1], ref byte param2)

急需注意的是挂号表构成都以十进制数值来标记的,注意一下十进制和十九进制的调换。 

 

再举个USB鼠标的例证,USB鼠标是正统的HID设备,它的商谈为:InterfaceClassCode为3(HID类),InterfaceSubclassCode为1(指点接口类),InterfaceProtocolCode为2(鼠标公约类),所以它的挂号如下:

 

[HKEY_LOCAL_MACHINEDriversUSBLoadClientsDefaultDefault3_1_2USBMouse] "DLL"="usbmouse.dll" 

 

到此截止,大家能够看看,其实驱动开拓无非做两件业务,一件是和硬件打交道,别的一件是和操作系统打交道。举个轻便的事例,举个例子:我们须求付出四个USB鼠标驱动程序,大家就须求了然USB鼠标硬件上是怎么发送数据的?操作系统怎么本事博取鼠标的垄断(monopoly卡塔尔国事件?其实USB鼠标是有叁个暂停PIPE的,用于传送鼠标发生的数据,Windwos CE.NET中有个接口函数叫做mouse_event(卡塔尔(قطر‎,特地用于发生鼠标事件,可是它是不关切具体怎么样硬件的,以至大家协和在应用程序中调用这么些函数都足以兑现模拟鼠标,对应的有个keybd_event(),用于发生键盘事件,知道了这一个就好办多了,只要将相应的数量转变一下,调用一下mouse_event()即可。

 

 

 

上述讲了堆理论,或许读者脑袋都已大了,为此,大家举个简单的例证来详细说多美滋下驱动程序的支付进程。

 

诸如大家有个USB Mouse设备,设备音信描述如下:

Device Descriptor:

bcdUSB: 0x0100

bDeviceClass: 0x00

bDeviceSubClass: 0x00

bDeviceProtocol: 0x00

bMaxPacketSize0: 0x08 (8)

idVendor: 0x05E3 (Genesys Logic Inc.)

idProduct: 0x0001

bcdDevice: 0x0101

iManufacturer: 0x00

iProduct: 0x01

iSerialNumber: 0x00

bNumConfigurations: 0x01

 

ConnectionStatus: DeviceConnected

Current Config Value: 0x01

Device Bus Speed: Low

Device Address: 0x02

Open Pipes: 1

 

Endpoint Descriptor:

bEndpointAddress: 0x81

Transfer Type: Interrupt

wMaxPacketSize: 0x0003 (3)

bInterval: 0x0A

 

能够看出上述设施有两个暂停PIPE,包的最大值为3。恐怕有人问上述的值怎么获得的,win2k 的DDK中有个usbview的例程,编写翻译一下,将你的USB设备插到PC机的USB口中,运营usbview.exe就可以看得相应的装置音讯。

 

有了那个骨干音信,就能够编写USB设备了,首先声贝因美下,下边包车型地铁代码取自微软的USB鼠标准样板本程序,版权归微软具备,此处仅仅借用来说述一下USB鼠标驱动的开支过程,读者如要求引用此代码,必要取得微软的允许。

 

第一,必得输出USBD要求调用的三个函数,首先到设备插入到USB端口时,USBD会调用USBDeviceAttach(卡塔尔国函数,相应的代码如下:

extern "C" BOOL 

USBDeviceAttach(

USB_HANDLE hDevice, // USB设备句柄

LPCUSB_FUNCS lpUsbFuncs, // USBDI的函数集结

LPCUSB_INTE奥迪Q5FACE lpInterface, // 设备接口描述音信

LPCWST景逸SUV szUniqueDriverId, // 设备ID描述字符串。

LPBOOL fAcceptControl, // 再次来到TRUE,标识咱们能够操纵此设备,反之表示不能够说了算

DWORD dwUnused) 

{

*fAcceptControl = FALSE;

// 大家的鼠标设备有特定的陈说消息,要检验是还是不是是我们的配备。

if (lpInterface == NULL) 

return FALSE;

// 打字与印刷相关的USB设备接口描述音讯。

DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: DeviceAttach, IF %u, #EP:%u, Class:%u, Sub:%u,Prot:%urn"), lpInterface->Descriptor.bInterfaceNumber,lpInterface->Descriptor.bNumEndpoints, lpInterface->Descriptor.bInterfaceClass,lpInterface->Descriptor.bInterfaceSubClass,lpInterface->Descriptor.bInterfaceProtocol));

// 初试数据USB鼠标类,产生三个收受USB鼠标数据的线程

CMouse * pMouse = new CMouse(hDevice, lpUsbFuncs, lpInterface);

if (pMouse == NULL)

return FALSE;

 

if (!pMouse->Initialize()) 

{

delete pMouse;

return FALSE;

}

 

// 注册三个监察和控制USB设备事件的回调函数,用于监察和控制USB设备是还是不是曾经拔掉。

(*lpUsbFuncs->lpRegisterNotificationRoutine)(hDevice,

USBDeviceNotifications, pMouse);

 

*fAcceptControl = TRUE;

return TRUE;

}

 

其次个函数是 USBInstallDriver()函数,

部分着力概念如下:

const WCHAR gcszRegisterClientDriverId[] = L"RegisterClientDriverID";

const WCHAR gcszRegisterClientSettings[] = L"RegisterClientSettings";

const WCHAR gcszUnRegisterClientDriverId[] = L"UnRegisterClientDriverID";

const WCHAR gcszUnRegisterClientSettings[] = L"UnRegisterClientSettings";

const WCHAR gcszMouseDriverId[] = L"Generic_Sample_Mouse_Driver";

 

函数接口如下:

extern "C" BOOL 

USBInstallDriver(

LPCWSTR szDriverLibFile) // @parm [IN] - Contains client driver DLL name

{

BOOL fRet = FALSE;

HINSTANCE hInst = LoadLibrary(L"USBD.DLL");

 

// 注册USB设备新闻

if(hInst)

{

LPREGISTER_CLIENT_DRIVER_ID pRegisterId = (LPREGISTER_CLIENT_DRIVER_ID)

GetProcAddress(hInst, gcszRegisterClientDriverId);

 

LPREGISTER_CLIENT_SETTINGS pRegisterSettings =

(LPREGISTER_CLIENT_SETTINGS) GetProcAddress(hInst,

gcszRegisterClientSettings);

 

if(pRegisterId && pRegisterSettings)

{

USB_DRIVER_SETTINGS DriverSettings;

 

DriverSettings.dwCount = sizeof(DriverSettings);

 

// 设置咱们的特定的新闻。

DriverSettings.dwVendorId = USB_NO_INFO;

DriverSettings.dwProductId = USB_NO_INFO;

DriverSettings.dwReleaseNumber = USB_NO_INFO;

 

DriverSettings.dwDeviceClass = USB_NO_INFO;

DriverSettings.dwDeviceSubClass = USB_NO_INFO;

DriverSettings.dwDeviceProtocol = USB_NO_INFO;

 

DriverSettings.dwInterfaceClass = 0x03; // HID

DriverSettings.dwInterfaceSubClass = 0x01; // boot device

DriverSettings.dwInterfaceProtocol = 0x02; // mouse

 

fRet = (*pRegisterId)(gcszMouseDriverId);

 

if(fRet)

{

fRet = (*pRegisterSettings)(szDriverLibFile,

gcszMouseDriverId, NULL, &DriverSettings);

 

if(!fRet)

{

//BUGBUG unregister the Client Driver's ID

}

}

}

else 

{

RETAILMSG(1,(TEXT("!USBMouse: Error getting USBD function pointersrn")));

}

FreeLibrary(hInst);

}

return fRet;

}

上述代码主要用以产生USB设备驱动程序须求的注册表新闻,要求留意的是:USB设备驱动程序不接纳标准的注册表函数,而是选择RegisterClientDriverID()和RegisterClientSettings来注册相应的设备消息。

 

除此以外二个函数是USBUninstallDriver(卡塔尔函数,具体代码如下:

extern "C" BOOL 

USBUnInstallDriver()

{

BOOL fRet = FALSE;

HINSTANCE hInst = LoadLibrary(L"USBD.DLL");

 

if(hInst)

{

LPUN_REGISTER_CLIENT_DRIVER_ID pUnRegisterId =

(LPUN_REGISTER_CLIENT_DRIVER_ID)

GetProcAddress(hInst, gcszUnRegisterClientDriverId);

 

LPUN_REGISTER_CLIENT_SETTINGS pUnRegisterSettings =

(LPUN_REGISTER_CLIENT_SETTINGS) GetProcAddress(hInst,

gcszUnRegisterClientSettings);

 

if(pUnRegisterSettings)

{

USB_DRIVER_SETTINGS DriverSettings;

 

DriverSettings.dwCount = sizeof(DriverSettings);

// 必得填入与登记时同样的新闻。

DriverSettings.dwVendorId = USB_NO_INFO;

DriverSettings.dwProductId = USB_NO_INFO;

DriverSettings.dwReleaseNumber = USB_NO_INFO;

 

DriverSettings.dwDeviceClass = USB_NO_INFO;

DriverSettings.dwDeviceSubClass = USB_NO_INFO;

DriverSettings.dwDeviceProtocol = USB_NO_INFO;

 

DriverSettings.dwInterfaceClass = 0x03; // HID

DriverSettings.dwInterfaceSubClass = 0x01; // boot device

DriverSettings.dwInterfaceProtocol = 0x02; // mouse

 

fRet = (*pUnRegisterSettings)(gcszMouseDriverId, NULL,

&DriverSettings);

}

 

if(pUnRegisterId)

{

BOOL fRetTemp = (*pUnRegisterId)(gcszMouseDriverId);

fRet = fRet ? fRetTemp : fRet;

}

FreeLibrary(hInst);

}

return fRet;

}

此函数根本用来删除USBInstallDriver(卡塔尔国时创制的注册表消息,相仿的它利用本身的函数接口UnRegisterClientDriverID()和UnRegisterClientSettings()来做相应的管理。

 

其余二个亟待管理的挂号的监察和控制通知函数USBDeviceNotifications():

extern "C" BOOL USBDeviceNotifications(LPVOID lpvNotifyParameter, DWORD dwCode,

LPDWORD * dwInfo1, LPDWORD * dwInfo2, LPDWORD * dwInfo3,

LPDWORD * dwInfo4)

{

CMouse * pMouse = (CMouse *)lpvNotifyParameter;

 

switch(dwCode)

{

case USB_CLOSE_DEVICE:

//删除相关的财富。

delete pMouse;

return TRUE;

}

return FALSE;

}

 

 

USB鼠标的类的定义如下:

class CMouse

{

public:

CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,

LPCUSB_INTERFACE lpInterface);

~CMouse();

 

BOOL Initialize();

private:

// 传输结束调用的回调函数

static DWORD CALLBACK MouseTransferCompleteStub(LPVOID lpvNotifyParameter);

// 中断管理函数

static ULONG CALLBACK CMouse::MouseThreadStub(PVOID context);

DWORD MouseTransferComplete();

DWORD MouseThread();

 

BOOL SubmitInterrupt();

BOOL HandleInterrupt();

 

BOOL m_fClosing;

BOOL m_fReadyForMouseEvents;

 

HANDLE m_hEvent;

HANDLE m_hThread;

 

USB_HANDLE m_hDevice;

USB_PIPE m_hInterruptPipe;

USB_TRANSFER m_hInterruptTransfer;

 

LPCUSB_FUNCS m_lpUsbFuncs;

LPCUSB_INTERFACE m_pInterface;

 

BOOL m_fPrevButton1;

BOOL m_fPrevButton2;

BOOL m_fPrevButton3;

 

// 数据选用缓冲区。

BYTE m_pbDataBuffer[8];

};

 

现实完毕如下:

 

// 布局函数,伊始化时调用

CMouse::CMouse(USB_HANDLE hDevice, LPCUSB_FUNCS lpUsbFuncs,

LPCUSB_INTERFACE lpInterface)

{

m_fClosing = FALSE;

m_fReadyForMouseEvents = FALSE;

m_hEvent = NULL;

m_hThread = NULL;

 

m_hDevice = hDevice;

m_hInterruptPipe = NULL;

m_hInterruptTransfer = NULL;

 

m_lpUsbFuncs = lpUsbFuncs;

m_pInterface = lpInterface;

 

m_fPrevButton1 = FALSE;

m_fPrevButton2 = FALSE;

m_fPrevButton3 = FALSE;

 

memset(m_pbDataBuffer, 0, sizeof(m_pbDataBuffer));

}

 

// 析构函数,用于破除申请的能源。

CMouse::~CMouse()

{

// 文告系统去关闭相关的函数接口。

m_fClosing = TRUE;

 

// Wake up the connection thread again and give it time to die.

if (m_hEvent != NULL)

{

// 布告关闭数据肩负线程。

SetEvent(m_hEvent);

 

if (m_hThread != NULL)

{

DWORD dwWaitReturn;

 

dwWaitReturn = WaitForSingleObject(m_hThread, 1000);

if (dwWaitReturn != WAIT_OBJECT_0)

{

TerminateThread(m_hThread, DWORD(-1));

}

CloseHandle(m_hThread);

m_hThread = NULL;

}

CloseHandle(m_hEvent);

m_hEvent = NULL;

}

 

if(m_hInterruptTransfer)

(*m_lpUsbFuncs->lpCloseTransfer)(m_hInterruptTransfer);

 

if(m_hInterruptPipe)

(*m_lpUsbFuncs->lpClosePipe)(m_hInterruptPipe);

}

 

 

// 初步化USB鼠标驱动程序

BOOL CMouse::Initialize()

{

LPCUSB_DEVICE lpDeviceInfo = (*m_lpUsbFuncs->lpGetDeviceInfo)(m_hDevice);

 

// 检查测验配置:USB鼠标应该唯有两个间断管道

if ((m_pInterface->lpEndpoints[0].Descriptor.bmAttributes & USB_ENDPOINT_TYPE_MASK) != USB_ENDPOINT_TYPE_INTERRUPT)

{

RETAILMSG(1,(TEXT("!USBMouse: EP 0 wrong type (%u)!rn"),

m_pInterface->lpEndpoints[0].Descriptor.bmAttributes));

return FALSE;

}

DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: EP 0:MaxPacket: %u, Interval: %urn"),

m_pInterface->lpEndpoints[0].Descriptor.wMaxPacketSize, 

m_pInterface->lpEndpoints[0].Descriptor.bInterval));

 

m_hInterruptPipe = (*m_lpUsbFuncs->lpOpenPipe)(m_hDevice,

&m_pInterface->lpEndpoints[0].Descriptor);

 

if (m_hInterruptPipe == NULL) {

RETAILMSG(1,(TEXT("Mouse: Error opening interrupt pipern")));

return (FALSE);

}

m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

if (m_hEvent == NULL)

{

RETAILMSG(1,(TEXT("USBMouse: Error on CreateEvent for connect eventrn")));

return(FALSE);

}

// 创造数量接收线程

m_hThread = CreateThread(0, 0, MouseThreadStub, this, 0, NULL);

if (m_hThread == NULL)

{

RETAILMSG(1,(TEXT("USBMouse: Error on CreateThreadrn")));

return(FALSE);

}

 

return(TRUE);

}

 

// 从USB鼠标设备中读出多少,爆发相应的鼠标事件。

BOOL CMouse::SubmitInterrupt()

{

if(m_hInterruptTransfer)

(*m_lpUsbFuncs->lpCloseTransfer)(m_hInterruptTransfer);

 

// 从USB鼠标PIPE中读数据

m_hInterruptTransfer = (*m_lpUsbFuncs->lpIssueInterruptTransfer)

(m_hInterruptPipe, MouseTransferCompleteStub, this,

USB_IN_TRANSFER | USB_SHORT_TRANSFER_OK, // 表示读数据

min(m_pInterface->lpEndpoints[0].Descriptor.wMaxPacketSize, 

sizeof(m_pbDataBuffer)),

m_pbDataBuffer, 

NULL);

 

if (m_hInterruptTransfer == NULL)

{

DEBUGMSG(ZONE_ERROR,(L "!USBMouse: Error in IssueInterruptTransferrn"));

return FALSE;

}

else

{

DEBUGMSG(ZONE_TRANSFER,(L"USBMouse::SubmitInterrupt,Transfer:0x%Xrn",

m_hInterruptTransfer));

}

return TRUE;

}

 

// 管理鼠标中断传输的数额

BOOL CMouse::HandleInterrupt()

{

DWORD dwError;

DWORD dwBytes;

 

DWORD dwFlags = 0;

INT dx = (signed char)m_pbDataBuffer[1];

INT dy = (signed char)m_pbDataBuffer[2];

 

BOOL fButton1 = m_pbDataBuffer[0] & 0x01 ? TRUE : FALSE;

BOOL fButton2 = m_pbDataBuffer[0] & 0x02 ? TRUE : FALSE;

BOOL fButton3 = m_pbDataBuffer[0] & 0x04 ? TRUE : FALSE;

 

if (!(*m_lpUsbFuncs->lpGetTransferStatus)(m_hInterruptTransfer, &dwBytes,&dwError))

{

DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error in GetTransferStatus(0x%X)rn"),

m_hInterruptTransfer));

return FALSE;

}

else

{

DEBUGMSG(ZONE_TRANSFER,(TEXT("USBMouse::HandleInterrupt, hTransfer 0x%X complete (%u bytes, Error:%X)rn"),

m_hInterruptTransfer,dwBytes,dwError));

}

 

if (!SubmitInterrupt())

return FALSE;

 

if(dwError != USB_NO_ERROR)

{

DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Error 0x%X in interrupt transferrn"),dwError));

return TRUE;

}

 

if(dwBytes < 3)

{

DEBUGMSG(ZONE_ERROR,(TEXT("!USBMouse: Invalid byte cnt %u from interrupt transferrn"),dwBytes));

return TRUE;

}

 

if(dx || dy)

dwFlags |= MOUSEEVENTF_MOVE;

 

if(fButton1 != m_fPrevButton1)

{

if(fButton1) 

dwFlags |= MOUSEEVENTF_LEFTDOWN;

else

dwFlags |= MOUSEEVENTF_LEFTUP;

}

 

if(fButton2 != m_fPrevButton2)

{

if(fButton2)

dwFlags |= MOUSEEVENTF_RIGHTDOWN;

else

dwFlags |= MOUSEEVENTF_RIGHTUP;

}

 

if(fButton3 != m_fPrevButton3)

{

if(fButton3)

dwFlags |= MOUSEEVENTF_MIDDLEDOWN;

else

dwFlags |= MOUSEEVENTF_MIDDLEUP;

}

 

m_fPrevButton1 = fButton1;

m_fPrevButton2 = fButton2;

m_fPrevButton3 = fButton3;

 

DEBUGMSG(ZONE_EVENTS,

(TEXT("USBMouse event: dx:%d, dy:%d, dwFlags:0x%X (B1:%u, B2:%u, B3:%u)rn"),

dx,dy,dwFlags,fButton1,fButton2,fButton3));

 

// 公告系统暴发鼠标事件

if (m_fReadyForMouseEvents)

mouse_event(dwFlags, dx, dy, 0, 0);

else

m_fReadyForMouseEvents = IsAPIReady(SH_WMGR);

 

return TRUE;

}

 

 

DWORD CALLBACK CMouse::MouseTransferCompleteStub(LPVOID lpvNotifyParameter)

{

CMouse * pMouse = (CMouse *)lpvNotifyParameter;

return(pMouse->MouseTransferComplete());

}

 

// 数据传输截至回调函数

DWORD CMouse::MouseTransferComplete()

{

if (m_hEvent)

SetEvent(m_hEvent);

return 0;

}

 

 

ULONG CALLBACK CMouse::MouseThreadStub(PVOID context)

{

CMouse * pMouse = (CMouse *)context;

return(pMouse->MouseThread());

}

 

// USB鼠标线程

DWORD CMouse::MouseThread()

{

DEBUGMSG(ZONE_INIT,(TEXT("USBMouse: Worker thread startedrn")));

SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);

 

if (SubmitInterrupt())

{

while (!m_fClosing)

{

WaitForSingleObject(m_hEvent, INFINITE);

 

if (m_fClosing)

break;

 

if ((*m_lpUsbFuncs->lpIsTransferComplete)(m_hInterruptTransfer))

{

if (!HandleInterrupt())

break;

}

else

{

RETAILMSG(1,(TEXT("!USBMouse: Event signalled, but transfer not completern")));

// The only time this should happen is if we get an error on the transfer

ASSERT(m_fClosing || (m_hInterruptTransfer == NULL));

break;

}

}

}

RETAILMSG(1,(TEXT("USBMouse: Worker thread exitingrn")));

return(0);

}

 

探访了未有,其实USB的驱动程序编写就这么轻巧,相符的任何设施,比如打字与印刷机设备,就有Bulk OUT PIPE,须要Bulk传输,那就供给领会一下IssueBulkTransfer()的运用。当然要是是开垦USB Mass Storage Disk的驱动,那就要求精通更加的多的合计,举个例子Bulk-Only Transport左券等。

 

微软的Windows CE.NET的Platform Build中曾经富含USB Printer和USB Mass Storage Disk的驱动的源代码了,好好钻研一下,你一定回收益非浅的。

 

 

2 PB的编写翻译进程 

 

施行cebuild.bat批管理公事。

cebuild.bat调用sysgen.bat批管理公事。

sysgen.bat调用cesysgen.bat批管理文件,cesysgen.bat担任在*.wce文件中搜索顾客筛选的性状,然后形成一美妙绝伦景况变量。之后PB会呈现那几个变量,下边多少个步骤就是显示搜集的变量。

发出SYSGEN变量。每一个SYSGEN变量对应一个特征。

产生CE_MODULE、COREDLL_COMPONENTS、FILESYS_COMPONENTS、DEVICE_COMPONENTS、GWE*_COMPONENTS、DCOM_MODULES、FONTS_COMPONENTS等意况变量。此中每一个意况变量蕴涵某贰个风味具体的剧情。从蒙受变量名称就能够看出来是哪个种类特色。

对_DEPTREES境况变量钦命的各种目录分别实施sysgen.bat批处理。_DEPTREES那么些变量的值是部分目录名(举例DCOM、IE、SECRUISERVE揽胜极光S、DIRECTX、WCESHELLFE等),这么些目录名坐落于%WINCEROOT%public。若是设置PB v4.1时私下认可安装路线,那么此目录路线为C:WINCE410Public。

编写翻译BSP。因为大家接收的BSP是Emulator,所以PB会编写翻译%WINCEROOT%PlatformEmulator目录下八个子目录KEHighlanderNEL、DTiggoIVE智跑S、GWE中的源码文件。

清除_FLATRELEASEDIENVISION情状变量内定的目录下的装有文件、子目录。若是我们定制的平台路线为C:Emulator,那么那几个意况变量的值为C:EmulatorRelDirEmulator_X86Release。

复制%_PROJECTROOT%负有文件到_FLATRELEASEDIR。

基于地点地区景况变量,找出具备与当地语言相关的*.str文件复制到_FLATRELEASEDIR中。*.str文件中满含了字符串能源,将字符串与ID关联。在_FLATRELEASEDIKuga目录下您能够见到以地区码为目录名的子目录。

拍卖NLS(国家语言援助)数据。

举办fmerge.exe。合併全数*.bib文件为四个文本ce.bib,归拢全体*.reg文件为多个文本reginit.ini。

进行cebuild.bat批管理文件。

实行fmerge.exe。合併全部*.db文件为贰个文件initdb.int,归并全体*.dat文件为多个文件initobj.dat。

运行regcomp.exe压缩reginit.ini。

运转txt2ucde.exe。将全部CE平台涉及到的拥有字符串转成unicode码。

运行res2exe.exe。将所有*.dll、*.exe、*.cpl文件中的能源纠正。能源立异部分首要和言语相关。

运维Romimage.exe。将兼具文件归并压缩成二个文书nk.bin(暗中同意文件名)。

  整个编写翻译进度被调用的批管理公事和EXE文件注重不外乎:cebuild.bat、sysgen.bat、cesysgen.bat、nmake.exe、txt2ucde.exe、makeimg.exe、fmerge.exe、regcomp.exe、res2exe.exe、romimage.exe、build.exe。在那间声Bellamy点,作者不保障所呈报的PB的编写翻译进度一定是正确科学的。从总体上讲PB所做的劳作正是如此。

 

3 何以读取和设置情况变量 

 

二个环境变量包涵了贰个CE操作系统某一方面的新闻。比如三个驱动程序、二个路线、八个布局文件、一个天性等。当PB编写翻译CE平台时,先做的办事就是搜集全数的情状变量供编写翻译器使用。

读取和装置境况变量的最棒格局是单击PB菜单"Build"-"Open Build Release Directory",PB会弹出三个垄断台窗口,相当于命令行外壳。键入"set"命令,当前平台具备的情状变量就呈现出来了,但是要多屏呈现。为了看通晓各样变量的值,能够键入"set |more",那样就足以分屏查看了。还足以将享有遇到变量消息保存到硬盘上,举个例子键入"set >C:envi.txt"。要翻看单个碰到变量值,键入"set 情状变量名"。要纠正原情况变量的值键入"set 境况变量名=值"。有些情况变量无需键入值就足以达成改进指标。比方前缀为"BSP_"和"SYSGEN_"的变量,键入"set 景况变量名="就打消了那一个遭遇变量。

在IDE中也足以改正境况变量,"platform"-"Settings",在"Environment"选项卡中添加、修正碰到变量。

利用情形变量也得以加上和删除特征,如BSP变量。BSP变量分二种,一种以BSP_NO为为前缀,一种以BSP为前缀。以BSP_NO为前缀表示方今平台不扶持某一特点,以BSP为前缀表示帮忙这一天性。举例BSP_SE景逸SUVIAL2代表此CE平台帮衬串口2;BSP_NOSEMuranoIAL表示此CE平台不帮忙串口。若是在PB的"catalog"中找不到要加上的表征,可以经过设置BSP变量来落到实处。具体BSP遇到变量参见CE扶助文档

4 Windows CE中的中断服务介绍

Windows CE在拍卖搁浅的进度中会发生一雨后春笋具体的平地风波,客户应该为温馨的里边设施驱动程序写好脚刹踏板服务例路程序和脚刹踏板服务线程,写的时候应该小心以下多少个难题:

(1)中断发生时,主旨跳至例外处理程序。

(2)例外管理程序使具备中断无效,然后调用合适的间歇服务例路程序筹划物理中断线。

(3)中断服务例路程序以中止标志符的花样重临逻辑中断。

(4)中断管理程序重新起动除当前半上落下以外的装有中断,并把实信号传递给方便的间歇服务线程。

(5)中断服务线程调用重视平台的驱动程序来寻访硬件和产生逻辑中断的拍卖。

(6)中断服务线程调用InterruptDone函数

(7)中断管理程序重新起动当前暂停,并在OAL中调用OEMInterruptDone函数。

 

5 windows ce开机运转钦赐的程序

若是standard shell,在%_winceroot%publicshelloakfilesshell.reg中

    若是taskman shell,在%_winceroot%publicwceshellfeoakfileswceshell.reg中

  [HKEY_LOCAL_MACHINEinit]下加入:

  “launch100”=“myapp.exe”

  “depend100”=hex: 14,00,1E,00

就能够。当然也得以在project.reg中充分。

倘使将“launch50”=“explorer.exe”换到本身的顺序则系统还没explorer,也一贯不桌面等内容了。

 

6 Windows ce 桌面定制小结

一、采用standard shell,  

去掉任务栏           代码%_winceroot%publicshelloakhpc

自己尝试了以下二种办法:

1、在taskbar.cpp上将函数BOOL CTaskBar::Register(State of Qatar的从头到尾的经过总体剔除,直接return TRUE;

2、在explorer.cpp大校函数DWOSportageD WINAPI CreatTaskBar(卡塔尔(قطر‎的内容删除,直接return 0;

二种方法都得以兑现,只是不老子@楚哪些方法更节省时间和空中。个人以为首个法子对比好。

删除桌面“笔者的Computer”“回笼站”的Logo

代码%_winceroot%publicshelloakfiles

在shell.reg文件中找到那八个键值,它们对应着桌面上的自己的Computer和回笼站,删除那八个键值:

[HKEY_LOCAL_MACHINEExplorerDesktop]
"{000214A0-0000-0000-C000-000000000046}"="My Computer"
"{000214A1-0000-0000-C000-000000000046}"="Recycle Bin"

注:也可只改正项目release目录下的shell.reg.之后只要make image就能够了。

 

二、选择taskman shell,需安装情形变量__SYSGEN_TASKMAN=1.。

taskman shell未有义务栏、初始菜单和桌面Logo,但有桌面背景观。

代码%_winceroot%publicwceshellfeoaktaskman

改善桌面背景观

mindeskt.cpp中的void Desktop_OnPaintBkgnd(卡塔尔(قطر‎函数,纠正当中的brush的颜色就能够。

即将HBRUSH hBkBrush = CreateSolidBrush(GetSysColor(COLOR_BACKGROUND));

改进HBRUSH hBkBrush = CreateSolidBrush(EscortGB(123,230,123卡塔尔国State of Qatar;就能够兑现背景象的变动

7怎么样将现存文件参预到nk.bin 

Platform Builder.

在project.bin文件中,在尤为重要词“FILE”下边,按Name, Path, Memory Type格式增多。

其中:

Name: 所增多的文书在Target文件系统中的文件名,在windows目录下。

Path: 所要加多的文件在host中的文件名(含路线)

Memory Type: 存款和储蓄类型,平常写NK。

譬喻说增多如下:

test.exe            d:evcpromytestrelmytest.exe          nk

则将host上的mytest.exe加入nk.bin, 在Target上会在windows目录下有个文本test.exe.

 

另,将EVC项指标 pbp文件增多到wince项目中,也可达成。

platform-----insert------user feature

 

8 nk.bin文件格式

起来7个字节为 42 30 30 30 46 46 0A 即“B000FFx0A”,以次来识别文件类型。

接下去4字节(DWOGL450D)表示ImageStart, 4字节表示ImageLength

如7字节后的8字节各自为:00 00 00 60 9C FA 33 01

则表示ImageStart=0x60000000, ImageLength=0x0133FA9C

接下去按Record格式:4字节start, 4 字节Length, 4字节CheckSum, Length字节的多少

从Record[0]一直到Record[n].

末尾一条Record的start+Length = ImageStart+ImageLength

 

本文由10bet手机官网发布于高并发,转载请注明出处:开发网络防火墙技术分析,Socket编程实现网络封包监视

上一篇:没有了 下一篇:没有了
猜你喜欢
热门排行
精彩图文