原文:http://www.cnblogs.com/aga-j/archive/2010/08/09/1795375.html
最近接到任务,基本要求是开发一个windows mobile平台上的wifi交互程序,一开始上面的人把需求定义错了,结果我做的东西全部从头来过,而最终的要求就是要程序能在后台运行,然后自动打开wifi,自动选择接入点进行连接。
google得知可以使用OpenNetCF的OpenNETCF.Net.NetworkInformation命名空间里的WirelessZeroConfigNetworkInterface和AccessPoint来完成。然而不管是在OpenNetCF还是在其他牛人的blog里,都只有使用这个类库来进行搜索周围的热点信息,没有提供connect上热点的信息。一开始在使用WirelessZeroConfigNetworkInterface的connect(stringSSID)时总是出错,所以就怀疑参数传入是不是Access Point的名字,最后经过考证也就是我前面这篇文章关于OpenNETCF.Net.NetworkInformation命名空间的WirelessNetworkInterface类的Connect函数问题介绍的,的确是传入AccessPoint的Name。connect耽搁了我一段时间,我始终搞不懂为什么会出错,所以不尝试通过其他办法来完成connect,知道研究生师兄叫我跟他一起研究,他把我的程序和我给他的OpenNetCF的类库网址拿去研究后,过了两三天就跟我说能连上了,我感觉真是太厉害了,问了他怎么做,他说不用connect函数,用另一个函数叫做ConnectToPreferredNetwork,既然这里是用preferredNetwork,那么要使用这个函数前就要把找到的accesspoint加到preferredNetwork里面,我按着这样的思路做了,结果也可以,其实本来我也想过这样做,但是就是搞不明白为什么connect不能用,所以也没继续研究能不能这样做,知道这样可以连接后,我仍然想知道为什么connect不行,看了OpenNetCF的函数的简要介绍,
http://www.opennetcf.com/library/sdf/
注意到connect是连接到access point
而ConnectToPreferredNetwork是连接到一个已经配置好的无线网络
熟悉无线网络方面的人应该很清楚我之前错在哪里,而我直到我完成了程序后才知道原来接入无线网络前要对无线热点先进行一些配置,这些在后面的程序中会提到。
好了,说了这么多废话,现在就开始建一个在windows mobile上操作wifi的程序吧。
1 首先建个智能设备项目的工程,然后往里面引用这四个外部引用,这些dll是OpenNETCF 2.3版里面的dll,要使用的话可以去免费下载Download the Community Edition (Free)
安装后找找dll就行了。这4个dll其实在编码中只会用到OpenNetCF.NET中的NetworkInformation命名空间
2 先讲讲怎么打开wifi吧,网络上流传着好多打开wifi的通用代码,我也copy了一份,
001 |
static private string keyValue = null ; |
003 |
public enum CEDEVICE_POWER_STATE |
007 |
PwrDeviceUnspecified = -1, |
033 |
[DllImport( "coredll.dll" )] |
035 |
public static extern int DevicePowerNotify( string device, CEDEVICE_POWER_STATE state, int flags); |
037 |
[DllImport( "coredll.dll" )] |
039 |
public static extern int SetDevicePower( string pvDevice, int df, CEDEVICE_POWER_STATE ds); |
041 |
[DllImport( "coredll.dll" )] |
043 |
unsafe public static extern int GetDevicePower( string pvDevice, int df, CEDEVICE_POWER_STATE* pds); |
045 |
static private void setKeyValue() |
049 |
string wifiGUID = "{98C5250D-C29A-4985-AE5F-AFE5367E5006}" ; |
051 |
string keyName = "System\\CurrentControlSet\\Control\\POWER\\State" ; |
053 |
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(keyName); |
055 |
foreach ( string val in registryKey.GetValueNames()) |
059 |
if (val.IndexOf(wifiGUID) != -1) |
077 |
/// "{98C5250D-C29A-4985-AE5F-AFE5367E5006}\\TNETWLN1" |
081 |
static unsafe public void wifi_power_on() |
089 |
if (keyValue != null ) |
093 |
DevicePowerNotify(keyValue, CEDEVICE_POWER_STATE.FullOn, 1); |
095 |
SetDevicePower(keyValue, 1, CEDEVICE_POWER_STATE.FullOn); |
主要是利用了DevicePowerNotify和SetDevicePower这两个Windows CE 5.0里面的API,然后传入设备名,而wifi设备名则是通过在注册表里面获得。还有一个关闭wifi的,这里就不赘述了,而打开wifi差不多
3来到这里,我们就可以自己试下调用这个函数,然后看看wifi有没有被打开,然后接下来就是connect的问题了。WirelessZeroConfigNetworkInterface对象有个PreferredAccessPoints的字段,这个字段保存的就是你之前所使用过的wifi接入点,注意是连接过的,而不是你找到的,因为找到了accesspoint后如果没有进行连接,是不会存放到PreferredAccessPoints字段里面,所以我们可以直接使用PreferredAccessPoints里面的accesspoint的名字作为参数传入前面说的ConnectToPreferredNetwork(因为满足了already-configured的要求),而如果仅仅将找到的热点(不在PreferredAccessPoints或者说没经过连接的,直接传入ConnectToPreferredNetwork,那就会报错),所以从这里我们可以看出,要连接上某个无线网络,实际上要经过一层configure的。而我们要把找到的热点链接上那怎么办的,那就要依靠WirelessZeroConfigNetworkInterface对象的AddPreferredNetwork函数了,把找到的未配置或者已经配置的accesspoint通过AddPreferredNetwork加入到PreferredNetwork里面,然后再调用ConnectToPreferredNetwork,就可以完成连接了。
05 |
collection = m_wzc.NearbyAccessPoints; |
07 |
count = collection.Count; |
11 |
MessageBox.Show(count.ToString()); |
13 |
foreach (AccessPoint ap in collection) |
17 |
if (ap.AuthenticationMode == AuthenticationMode.Open) |
21 |
MessageBox.Show( m_wzc.AddPreferredNetwork(ap).ToString()); |
可以看到,上面的代码,我用了一个while来才NearbyAccessPoints的查找,这是因为OpenNetCF里这个字段有个bug,不一定每次m_wzc.NearbyAccessPoints都能返回accesspoint的集合,而且如果你仅仅靠判断NearbyAccessPoints是否为空也是不行的,
while (collection == null)
{
collection = m_wzc.NearbyAccessPoints;
}
它会返回一个不会null的集合对象,但是里面其实是空的。结果你拿不到半个access point
4 最后,这个命名空间,这些类还有好多功能可以实现,比如获得access point的信号状态啊,有无使用加密啊什么的,这些有兴趣或者需要的话就自己研究了,下面附上一个简单的程序。 testWifi.rar