代码改变世界

关于OpenNETCF.Net.NetworkInformation命名空间的WirelessNetworkInterface类的Connect函数问题

2010-07-27 23:30  Aga.J  阅读(1799)  评论(2编辑  收藏  举报

   今天难得jack在线,而且回了我的问题,我赶紧抓住机会问了他好多好多和我现在头痛的事由关的问题(^ ^ 哈哈),这个问题就是和OpenNETCF.Net.NetworkInformation这个命名空间里的WirelessNetworkInterface类的Connect函数的参数String SSID 具体是传入什么有关,一开始我传入的是access point的名字,结果程序运行到这里就会死机,所以觉得不是传入名字,所以就问了jack,然后聊着聊着,聊了好多,他说看源码就知道怎么了,焕然大悟啊,我马上下载了个reflector(jack推荐的),然后把OpenNETCF.Net.NetworkInformation.dll的源码进行了详读,发现了下面的东西:

  假设使用Connect函数的无参版的重载函数,如果不传入参数(默认为连接到preferred access point),则调用Conenct(""),然后该函数调用NDISUIO.SetOID(NDIS_OID.SSID, base.Name, Encoding.ASCII.GetBytes(SSID)),

所以这时候最后一个参数为长度为0的byte数组,然后SerOID函数里又使用这个数组初始化NDISQueryOid对象 

NDISQueryOid queryOID = new NDISQueryOid(data.Length);

    queryOID.Data = data;

/*

其中Data的set是这样的

    set

    {

        this.ourSize = 8 + value.Length;

        this.m_data = new byte[this.ourSize];

        Buffer.BlockCopy(value, 0, this.m_data, 8, value.Length);

    }

所以在长度为0的byte数组的情况下,m_data只有8字节长。这个时候还不知道保存了什么信息!!

*/

    return SetOID(oid, adapterName, queryOID);

/*

SerOID具体实现是

    fixed (byte* numRef = Encoding.Unicode.GetBytes(adapterName + '\0'))

    {

        queryOID.ptcDeviceName = numRef;                //这里继续初始化queryOID的成员

              /*

              ptcDeviceName的set如下

                  set

                         {

                      Buffer.BlockCopy(BitConverter.GetBytes((uint) value), 0, this.m_data, 4, 4);

                         }

              //所以得到结论是m_data的后四个字节保存的是adapterName的字节串

*/

        queryOID.Oid = (uint) oid;                               //同上

/*

Oid的set如下:

    set

    {

        Buffer.BlockCopy(BitConverter.GetBytes(value), 0, this.m_data, 0, 4);

    }

//所以前四个字节保存的是oid,在这里是个常量,是SSID = 0xd010102

//具体不清楚是什么,或者和preferred access point有关,因为这个connect()无参的//重载函数是连接到preferred access point 用的

*/

        try

        {

            ndisuio.Open(FileAccess.ReadWrite, FileShare.ReadWrite);

        }

        catch

        {

            throw new NetworkInformationException(Marshal.GetLastWin32Error());

        }

        try

        {

            ndisuio.DeviceIoControl(0x120814, queryOID.getBytes(), queryOID.getBytes());

//最后应该在这个函数进行操作(msdn上说这个函数causing the corresponding device to perform the specified operation),所以所有必要的信息都应该有,所以需要适配器名字,和access point的必要信息,所以如果connect函数是有参的那个重载函数的话,那么会先将传入的SSID串变为字节数组,复制给m_data的第8个字节开始的那部分字节子数组。

        }

        catch (Exception)

        {

            return false;

        }

    }

}

接下来入正题了,SSID是什么呢?

利用

public virtual string AssociatedAccessPoint

{

    get

    {

        string str = "";

        byte[] buffer = null;

        try

        {

            buffer = NDISUIO.QueryOID(NDIS_OID.SSID, base.Name);

                     /*

                     这里的base.Name是适配器的名字,根据适配器和常量SSID = 0xd010102

QueryOID会ndisuio.DeviceIoControl的查询操作,但是这次传入的第一个参数是0x120804而前面使用这个函数时传入的参数是0x120814,使用这个函数的目的是为了得到适配器上的所有信息,然后保存在oid变量里,然后就把oid变量(包含了适配器名字,SSID = 0xd010102,和已连接的access point的信息)转换为buffer

*/

        }

        catch

        {

            return null;

        }

        int count = BitConverter.ToInt32(buffer, 0);

        if (count > 0)

        {

            str = Encoding.ASCII.GetString(buffer, 4, count);

                     /*

                     这里将buffer从第4个字节开始转换为串,前四个字节保存的是什么就不知道了,估计也是适配器的名字

*/

        }

        return str;                     //返回串!

    }

}

然后写一些测试代码

    private void button1_Click(object sender, EventArgs e)

    {

        MessageBox.Show(this.m_wzc.AssociatedAccessPoint);

    }

我们得到的是目前适配器所连接的AP的名字!即上面的str = Encoding.ASCII.GetString(buffer, 4, count);返回的是当前连接的ap的名字

查看connect函数,里面的实现是NDISUIO.SetOID(NDIS_OID.SSID, base.Name, Encoding.ASCII.GetBytes(SSID),这样一来,我们就直接传进将要连接的ap的名字就行了。

至于为什么我的机子会死机,可能是因为山寨机的问题,也可能是因为这个类库适用性不是那么广吧,还要继续搞到能连接为止啊。上面只是记录了大概的过程,具体还有很多,我没写下来。