用C#开发.NET CF 蓝牙通信模块(2)

四. 监听服务

   监听服务调用的是非托管API WSASetService,其原型是

INT WSASetService(

LPWSAQUERYSET lpqsRegInfo,

WSAESETSERVICEOP essoperation,

DWORD dwControlFlags

);

   可以看到关键也是第一个参数,lpqsRegInfo,这也是一个struct,我们的包装方法与前面的发现设备采用的方法类似,做蓝牙通信时要注意其成员要如下设置:

lpqsRegInfodwSizesizeof(WSAQUERYSET)
lpszServiceInstanceNameNot supported on Windows CE. Set to 0.
lpServiceClassIdNot supported on Windows CE. Set to 0.
dwNameSpaceNS_BTH.
dwNumberOfCsAddrsNot supported on Windows CE. Set to 0.
IpcsaBufferNot supported on Windows CE. Set to 0.
lpBlobPoints to a BTHNS_SETBLOB structure, containing information about the service to be added.
*
All other WSAQUERYSET fields are ignored.



   五. 连接

   我们知道,IrDA中连接远程服务是使用方法System.Net.Sockets.IrDAClient类中的Connect方法。而这个方法又是调用的Socket类中的Connect方法。而Socket类是一个比较抽象的类,它并不绑定某个具体的地址族、SocketType和protocolType,所以在实例化的时候,需要指定这三个参数。我们也知道,在IrDA中,这三个参数分别是AddressFamily.Irda, SocketType.Stream,和ProtocolType.IP,那么在蓝牙中这三个参数分别是什么呢?我们好像找不到。

   且慢,真是这样吗?

   我们知道在.net中,这三个参数都是枚举值,而枚举在默认情况下,你可以认为就是int值的替代表现。

   我们该如何知道这三个参数到底是什么呢?

   还是先看Socket类的Connect方法。

   我们查查有关资料,可以知道这个方法实际上是调用的一个非托管函数:

[DllImport("mscoree", EntryPoint="@339")]

public static extern int connect(int s, byte[] name, int namelen);

   也就是非托管的Socket API。

   我们看Windows CE 4.2的SDK,可以看到,在使用蓝牙进行连接的时候,需要使用WinSock扩展。我们还可以看到,在使用蓝牙进行连接的时候,三个参数分别应当是AF_BTH、SOCK_STREAM和BTHPROTO_RFCOMM,至于这三个参数分别代表什么,我们就要查看相关的头文件了。

   我们找到ws2bth.h头文件,可以看到AF_BTH代表十进制数32,而BTHPROTO_RFCOMM代表十六进制数0x0003,恰好和ProtocolType.Ggp代表的数值是一致的。所以,我们在实例化Socket时是这么写的:

new Socket((AddressFamily) 0x20, SocketType.Stream, ProtocolType.Ggp);
   Socket实例化出来了,其他的当然就都好说了,这里不再赘述。

   六. 蓝牙的安全设置

   蓝牙比红外多了安全方面的设置,所以就需要多一些代码来处理这些。具体也就不多说了,其实也就是一些非托管代码的包装调用,这些API在Btdrt.dll中:

   获取配对码请求:

[DllImport("Btdrt.dll", SetLastError=true)]

public static extern int BthGetPINRequest(byte[] pba);

   设置配对码:

[DllImport("btdrt.dll", SetLastError=true)]

public static extern int BthSetPIN(byte[] pba, int cPinLength, byte[] ppin);

   比较麻烦点的是配对,总共有三步操作:

   首先是创建ACL连接:

[DllImport("Btdrt.dll", SetLastError=true)]

public static extern int BthCreateACLConnection(byte[] pbt, ref ushort phandle);

   然后是配对码验证:

[DllImport("Btdrt.dll", SetLastError=true)]

public static extern int BthAuthenticate(byte[] pbt);

   然后一定要关闭连接:

[DllImport("Btdrt.dll", SetLastError=true)]

public static extern int BthCloseConnection(ushort handle);

  
七. 设置蓝牙无线电状态

   我们知道,蓝牙无线电有打开、关闭、可发现三种状态,那么我们如何实现编程控制呢?

   我想这个一定大家都知道了,因为网上有很多关于这个的文章:

   先写一个枚举:

public enum RadioMode
{
  Connectable = 1,
  Discoverable = 2,
  PowerOff = 0
}

   然后写一个函数调用非托管代码即可:

[DllImport("BthUtil.dll", SetLastError=true)]

public static extern int BthSetMode(RadioMode dwMode);

   获取无线电状态的话就用下面的函数:

[DllImport("BthUtil.dll", SetLastError=true)]

public static extern int BthGetMode(ref RadioMode dwMode);

   八. 已知的问题

   可能是因为蓝牙控制软件还没有实现标准化或者还是其他的问题,我们发现根据Windows CE 4.2 SDK 使用Winsock 扩展做的蓝牙开发有一个问题,而且不论是本文中所述的托管代码还是其他的非托管代码,只要是用的这种思路用Winsock 2做的开发都会存在这样一个问题,那就是不是在所有的Windows Mobile设备上都能正常运行。经过我的测试,我发现在很多使用另行开发的蓝牙控制软件的设备上,如联想ET560、华硕MyPAL A730上都无法运行,而在没有另行开发蓝牙控制软件的设备上是可以正常运行的,我不知道这是什么原因,初步推测可能是厂商另行开发的蓝牙控制软件屏蔽了微软的API的缘故,到底是不是这样,还得请高人指点。

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/metababy/article/details/565636
个人分类: c#
上一篇用C#开发.NET CF 蓝牙通信模块(1)
下一篇C#设计模式编程之抽象工厂模式新解(1)
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭