当我们把网线插到计算机上时,WINDOWS任务栏的托盘图标都会更改相应的网络图标,拔掉也会有相应的处理。一直都对这个机制感兴趣,却不知道如何做,而且公司的某个产品也需要这么一个功能。昨天在家测试某个程序的时候,发现了其中一个线程的栈中有一个叫wininet!CheckForNetworkChange的函数,IDA分析了WINNETDLL后,有了本文。
微软在WINDOWS VISTA之后提供了一个叫NLA(Network List Manager API)的接口,用于获取网络状态变化通知的一个接口。以COM技术实现。
主要导出的COM接口如下:
IEnumNetworkConnections
IEnumNetworks
INetwork
INetworkConnection
INetworkConnectionEvents
INetworkEvents
INetworkListManager
INetworkListManagerEvents
其中INetworkListManager是一个根对象,可以获取计算机是否连接到因特网(INetworkListManager->get_IsConnectedToInternet)。还可以查询有哪些可用的网络和连接更关键的是INetworkListManagerEvents和INetworkEvents两个类。这两个类在MSDN文档里的描述如下:
is a message sink interface that a client implements to get overall machine state related events
也就是说我们要自己实现这两个类。而回调的方式是通过COM技术中特有的机制IConnectionPoint来搞定。实现方式如下:
001 class CNetworkListManagerEvent : public INetworkListManagerEvents
002 {
003 public:
004 CNetworkListManagerEvent() : m_ref(1)
005 {
006
007 }
008
009 ~CNetworkListManagerEvent()
010 {
011
012 }
013
014 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ppvObject)
015 {
016 HRESULT Result = S_OK;
017 if (IsEqualIID(riid, IID_IUnknown))
018 {
019 ppvObject = (IUnknown )this;
020 }
021 else if (IsEqualIID(riid ,IID_INetworkListManagerEvents))
022 {
023 ppvObject = (INetworkListManagerEvents )this;
024 }
025 else
026 {
027 Result = E_NOINTERFACE;
028 }
029
030 return Result;
031 }
032
033 ULONG STDMETHODCALLTYPE AddRef()
034 {
035 return (ULONG)InterlockedIncrement(&m_ref);
036 }
037
038 ULONG STDMETHODCALLTYPE Release()
039 {
040 LONG Result = InterlockedDecrement(&m_ref);
041 if (Result == 0)
042 delete this;
043 return (ULONG)Result;
044 }
045
046 virtual HRESULT STDMETHODCALLTYPE ConnectivityChanged(
047 / [in] / NLM_CONNECTIVITY newConnectivity)
048 {
049 return S_OK;
050 }
051
052 private:
053
054 LONG m_ref;
055 };
056
057 int _tmain(int argc, TCHAR argv, TCHAR Env)
058 {
059 CoInitialize(NULL);
060
061 //
062 // 通过NLA接口获取网络状态
063 //
064 IUnknown pUnknown = NULL;
065
066 HRESULT Result = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, IID_IUnknown, (void )&pUnknown);
067 if (SUCCEEDED(Result))
068 {
069 INetworkListManager pNetworkListManager = NULL;
070 Result = pUnknown->QueryInterface(IID_INetworkListManager, (void )&pNetworkListManager);
071 if (SUCCEEDED(Result))
072 {
073 VARIANT_BOOL IsConnect = VARIANT_FALSE;
074 Result = pNetworkListManager->get_IsConnectedToInternet(&IsConnect);
075 if (SUCCEEDED(Result))
076 {
077 printf("IsConnect Result %s\n", IsConnect == VARIANT_TRUE "TRUE" : "FALSE");
078 }
079
080 IConnectionPointContainer pCPContainer = NULL;
081 Result = pNetworkListManager->QueryInterface(IID_IConnectionPointContainer, (void )&pCPContainer);
082 if (SUCCEEDED(Result))
083 {
084 IConnectionPoint pConnectPoint = NULL;
085 Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint);
086 if(SUCCEEDED(Result))
087 {
088 DWORD Cookie = NULL;
089 CNetworkListManagerEvent NetEvent = new CNetworkListManagerEvent;
090 Result = pConnectPoint->Advise((IUnknown )NetEvent, &Cookie);
091 if (SUCCEEDED(Result))
092 {
093 printf("Loop Message\n");
094 MSG msg;
095 while(GetMessage(&msg, NULL, 0, 0))
096 {
097 TranslateMessage(&msg);
098 DispatchMessage(&msg);
099
100 if (msgmessage == WM_QUIT)
101 {
102 break;
103 }
104 }
105
106 pConnectPoint->Unadvise(Cookie);
107
108 pConnectPoint->Release();
109 }
110 }
111
112 pCPContainer->Release();
113 }
114
115 pNetworkListManager->Release();
116 }
117
118 pUnknown->Release();
119 }
120
121 CoUninitialize();
122 return 1;
123 }
因为NLA API是WINDOWS VISTA之后才有的,对于WINDOWS XP是不兼容的,但是WINDOWS XP下有一个方法可以达到同样的效果,可以参考文章Network Awareness in Windows XP,这个文章里的代码是C#的,其中关键的代码转换成C++
01 void WaitForNetworkChnages()
02 {
03 WSAQUERYSET querySet = {0};
04 querySetdwSize = sizeof(WSAQUERYSET);
05 querySetdwNameSpace = NS_NLA;
06
07 HANDLE LookupHandle = NULL;
08 WSALookupServiceBegin(&querySet, LUP_RETURN_ALL, &LookupHandle);
09 DWORD BytesReturned = 0;
10 WSANSPIoctl(LookupHandle, SIO_NSP_NOTIFY_CHANGE, NULL, 0, NULL, 0, &BytesReturned, NULL);
11 WSALookupServiceEnd(LookupHandle);
12 }
13
14 void Test()
15 {
16 WSAData data = {0};
17 WSAStartup(MAKEWORD(2, 0), &data);
18 int i = 0;
19 while(1)
20 {
21 printf("BeginWait %d\n", i++);
22 WaitForNetworkChnages();
23 printf("EndWait\n");
24 }
25
26 WSACleanup();
27 }
手动设置ip以及dns或是看下面:
1、如果是windows *** 作系统,开始-->运行-->输入"cmd",在打开的console中输入"ipconfig", 看看你的ip地址有没有正确配置。如果正确连接上,你看看新浪能不能ping通。在打开的console中输入 “ping >
2、您是否连接的是自己的无线信号? 通过有线登陆路由器管理界面,在“运行状态”-“无线状态”中查看一下SSID号。如果SSID号不是无线连接的网络名称,则请将无线网卡正确连接到自己的这个无线网络上。
3 无线路由器中是否设置了无线MAC地址过滤? 通过有线登陆路由器管理界面,“无线参数(无线设置)”-“MAC地址过滤”,确认其为关闭状态。
4 确认您的安全类型和密钥。 通过有线登陆路由器管理界面,“无线参数(无线设置)”中查看路由器设置的是哪种安全类型,并记住密钥。可以重新修改密钥,断开后重新连接。 5、可能是DNS的问题,把路由器断一下电,重新加电,电脑重启。
6、排除一下是否有ARP病毒,进行查杀。
7、运行:“Servicesmsc”,把“Wireless Zero Configuration” 设为自动启用。 8、信号很强但就是上不了网,解决的办法是,在地址栏时输入“19216811”,进入无线路由设置页面,在系统工具中点恢复出厂设置,然后再重新进行有关参数设置,重启路由器后就恢复正常,可以上网了。
开始---程序---命令提示符--ipconfig空格/all回车。网上邻居--右键属性--无线网络连接属性--Internet 协议(TCP/IP)属性--选择使用下面的IP地址,IP地址:1921681111,子网掩码:2552552550,默认网关:19216811
选择使用下面的DNS解析服务器地址:下面两项请根据刚才打开命令提示符里的DNS Servers后面的IP输入就可以了。
以上就是关于如何自动获取网络变化通知全部的内容,包括:如何自动获取网络变化通知、无线网络连接状态一直显示“正在获取网络地址” 但可以上网是怎么回事、等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)