C++程序中使用Windows系统Native Wifi API的基本教程

Windows应用想要实现连接wifi,监听wifi信号,断开连接等功能,用NativeWifi API是个不错的选择。

打开MSDN,搜索NativeWifi Api,找到Native Wifi页。在这里

信息量很大,如果像我着急实现上述功能,看海量的文档有些来不及。如果直接给我例子,在运行中调试,阅读代码,效率会更高。
但是,我并没有成功。首先,Sample在SDK中,参见这里。我下载几次都失败了,最后放弃这条路。后来同事给了我一份Sample,我不敢确定是否就是这个,但是代码写的也是很晦涩。我的初衷是简单的使用这些API的例子。

看来还是自己动手吧。看相关API,如果不懂,就找有经验人的例子。

几经周折,终于实现我的需求。让我慢慢道来。
1.获得可用AP列表
参见WlanGetAvailableNetworkList的官方文档,下面有例子。

DWORD WINAPI WlanGetAvailableNetworkList(
 _In_  HANDLE hClientHandle,
 _In_  const GUID *pInterfaceGuid,
 _In_  DWORD dwFlags,
 _Reserved_ PVOID pReserved,
 _Out_  PWLAN_AVAILABLE_NETWORK_LIST *ppAvailableNetworkList
);

由可用列表便可以找到当前哪个AP正在连接,并显示信号强度。
2.监听当前连接
在获得可用AP列表的基础上,遍历当前AP,看谁正在连接,并取得它的信号。代码片段如下:

bool isConnect = false;
int numberOfItems = pWLAN_AVAILABLE_NETWORK_LIST->dwNumberOfItems;
  for(int i = 0; i <= numberOfItems; i++)
  {
   WLAN_AVAILABLE_NETWORK wlanAN = pWLAN_AVAILABLE_NETWORK_LIST->Network[i];
   if(wlanAN.dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED)
   {
    Wprintf(WLAN signal is %s:%d\n", wlanAN.strProfileName, wlanAN.wlanSignalQuality);
    isConnect = true;
   }
  }
  if(!isConnect){
 wprintf("Wifi is disconnected!\n");}

3.断开连接
如果wifi处于连接状态,将其断开。WlanDisconnect还是容易使用的。原型如下:

DWORD WINAPI WlanDisconnect(
 _In_  HANDLE hClientHandle,
 _In_  const GUID *pInterfaceGuid,
 _Reserved_ PVOID pReserved
);

代码演示在后面。
4.连接一个有profile的AP(已保存过密码)
这是本文的重点。
虽然连接函数WlanConnect原型很简单:

DWORD WINAPI WlanConnect(
 _In_  HANDLE hClientHandle,
 _In_  const GUID *pInterfaceGuid,
 _In_  const PWLAN_CONNECTION_PARAMETERS pConnectionParameters,
 _Reserved_ PVOID pReserved
);

但参数PWLAN_CONNECTION_PARAMETERS却是很复杂,只要有一个配错,连接就会失败。
还好我的需求还是蛮简单的,只要连接已有的profile的AP。那么我的工作就会有针对性的开展。挫折了好多天,每次都连接失败,原因是ERROR_INVALID_PARAMETER。
就在今天,我终于成功了。真是会者不难,难者不会啊。
看看连接参数的结构体:

typedef struct _WLAN_CONNECTION_PARAMETERS {
 WLAN_CONNECTION_MODE wlanConnectionMode;
 LPCWSTR    strProfile;
 PDOT11_SSID   pDot11Ssid;
 PDOT11_BSSID_LIST pDesiredBssidList;
 DOT11_BSS_TYPE  dot11BssType;
 DWORD    dwFlags;
} WLAN_CONNECTION_PARAMETERS, *PWLAN_CONNECTION_PARAMETERS;

为了实现我的要求,可以这样赋值:
wlanConnectionMode这里设成wlan_connection_mode_profile;
strProfile写上你要连接ap的名称(通常是profile名称);
pDot11Ssid用不上,设置NULL;
pDesiredBssidList同样置成NULL;
dot11BssType我给设成dot11_BSS_type_infrastructure(基础设施?);
dwFlags设置为WLAN_CONNECTION_HIDDEN_NETWORK。
确实是工作了,strProfile如何获取呢?参见监听连接信号中对可用AP列表中第一个profile的获取。
完整代码如下:

//
#include "stdafx.h"
#include <windows.h>
#include <wlanapi.h>
#include <objbase.h>
#include <wtypes.h>
#include <string>
#include <stdio.h>
#include <stdlib.h> 

// Need to link with Wlanapi.lib and Ole32.lib
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "ole32.lib") 

using namespace std; 

int listenStatus()
{
 HANDLE hClient = NULL;
 DWORD dwMaxClient = 2;
 DWORD dwCurVersion = 0;
 DWORD dwResult = 0;
 DWORD dwRetVal = 0;
 int iRet = 0; 

 WCHAR GuidString[39] = {0};
 //Listen the status of the AP you connected.
 while(1){
  Sleep(5000);
  PWLAN_INTERFACE_INFO_LIST pIfList = NULL;//I think wlan interface means network card
  PWLAN_INTERFACE_INFO pIfInfo = NULL; 

  DWORD dwFlags = 0;   

  dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);
  if (dwResult != ERROR_SUCCESS) {
   wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
   return 1;
  } 

  dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList);
  if (dwResult != ERROR_SUCCESS) {
   wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);
   return 1;
  } else { 

   wprintf(L"WLAN_INTERFACE_INFO_LIST for this system\n"); 

   wprintf(L"Num Entries: %lu\n", pIfList->dwNumberOfItems);
   wprintf(L"Current Index: %lu\n\n", pIfList->dwIndex);
   int i;
   for (i = 0; i < (int) pIfList->dwNumberOfItems; i++) {
    pIfInfo = (WLAN_INTERFACE_INFO *) &pIfList->InterfaceInfo[i];
    wprintf(L" Interface Index[%u]:\t %lu\n", i, i);
    iRet = StringFromGUID2(pIfInfo->InterfaceGuid, (LPOLESTR) &GuidString,
     sizeof(GuidString)/sizeof(*GuidString)); 

    if (iRet == 0)
     wprintf(L"StringFromGUID2 failed\n");
    else {
     wprintf(L" InterfaceGUID[%d]: %ws\n",i, GuidString);
    }
    wprintf(L" Interface Description[%d]: %ws", i,
     pIfInfo->strInterfaceDescription);
    wprintf(L"\n"); 

    wprintf(L" Interface State[%d]:\t ", i);
    switch (pIfInfo->isState) {
    case wlan_interface_state_not_ready:
     wprintf(L"Not ready\n");
     break;
    case wlan_interface_state_connected:
     wprintf(L"Connected\n");
     break;
    case wlan_interface_state_ad_hoc_network_formed:
     wprintf(L"First node in a ad hoc network\n");
     break;
    case wlan_interface_state_disconnecting:
     wprintf(L"Disconnecting\n");
     break;
    case wlan_interface_state_disconnected:
     wprintf(L"Not connected\n");
     break;
    case wlan_interface_state_associating:
     wprintf(L"Attempting to associate with a network\n");
     break;
    case wlan_interface_state_discovering:
     wprintf(L"Auto configuration is discovering settings for the network\n");
     break;
    case wlan_interface_state_authenticating:
     wprintf(L"In process of authenticating\n");
     break;
    default:
     wprintf(L"Unknown state %ld\n", pIfInfo->isState);
     break;
    }
   }
  }
 }
} 

int _tmain(int argc, _TCHAR* argv[])
{ 

 HANDLE hClient = NULL;
 DWORD dwMaxClient = 2;
 DWORD dwCurVersion = 0;
 DWORD dwResult = 0;
 DWORD dwRetVal = 0;
 int iRet = 0;  

 /* variables used for WlanEnumInterfaces */ 

 PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
 PWLAN_INTERFACE_INFO pIfInfo = NULL; 

 LPCWSTR pProfileName = NULL;
 LPWSTR pProfileXml = NULL;
 DWORD dwFlags = 0; 

 pProfileName = argv[1]; 

 wprintf(L"Information for profile: %ws\n\n", pProfileName); 

 dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);
 if (dwResult != ERROR_SUCCESS) {
  wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
  return 1;
 } 

 dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList);
 if (dwResult != ERROR_SUCCESS) {
  wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);
  return 1;
 } else {
  dwResult = WlanDisconnect(hClient, &pIfList->InterfaceInfo[0].InterfaceGuid,NULL);//DISCONNECT FIRST
  if(dwResult != ERROR_SUCCESS)
  {
   printf("WlanDisconnect failed with error: %u\n",dwResult);
   return -1;
  }
  PWLAN_AVAILABLE_NETWORK_LIST pWLAN_AVAILABLE_NETWORK_LIST = NULL;
  dwResult = WlanGetAvailableNetworkList(hClient, &pIfList->InterfaceInfo[0].InterfaceGuid,
    WLAN_AVAILABLE_NETWORK_INCLUDE_ALL_MANUAL_HIDDEN_PROFILES,
    NULL, &pWLAN_AVAILABLE_NETWORK_LIST);
  if (dwResult != ERROR_SUCCESS)
  {
   printf("WlanGetAvailableNetworkList failed with error: %u\n",dwResult);
   WlanFreeMemory(pWLAN_AVAILABLE_NETWORK_LIST);
   return -1;
  }
  WLAN_AVAILABLE_NETWORK wlanAN = pWLAN_AVAILABLE_NETWORK_LIST->Network[0];//PLEASE CHECK THIS YOURSELF
  if(pProfileName == NULL)
   pProfileName = wlanAN.strProfileName;
  WLAN_CONNECTION_PARAMETERS wlanConnPara;
  wlanConnPara.wlanConnectionMode =wlan_connection_mode_profile ; //YES,WE CONNECT AP VIA THE PROFILE
  wlanConnPara.strProfile =pProfileName;       // set the profile name
  wlanConnPara.pDot11Ssid = NULL;         // SET SSID NULL
  wlanConnPara.dot11BssType = dot11_BSS_type_infrastructure;  //dot11_BSS_type_any,I do not need it this time.
  wlanConnPara.pDesiredBssidList = NULL;       // the desired BSSID list is empty
  wlanConnPara.dwFlags = WLAN_CONNECTION_HIDDEN_NETWORK;   //it works on my WIN7\8 

  dwResult=WlanConnect(hClient,&pIfList->InterfaceInfo[0].InterfaceGuid,&wlanConnPara ,NULL);
  if (dwResult==ERROR_SUCCESS)
  {
   printf("WlanConnect success!\n");
  }
  else
  {
   printf("WlanConnect failed err is %d\n",dwResult);
  }
 } 

 listenStatus(); //LISTEN THE STATUS 

 if (pProfileXml != NULL) {
  WlanFreeMemory(pProfileXml);
  pProfileXml = NULL;
 } 

 if (pIfList != NULL) {
  WlanFreeMemory(pIfList);
  pIfList = NULL;
 }
 return dwRetVal;
}

5.打开网络设置界面
遇到以前没有连接过的AP,需要输入密码,那么,直接打开配置界面让用户自己来搞吧。

ShellExecute(
 NULL,
 L"open",
 L"shell:::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{38a98528-6cbf-4ca9-8dc0-b1e1d10f7b1b}",
 NULL,
 NULL,
 SW_SHOWNORMAL);

6.RSSI
当屏幕上打印出“WlanConnect success!”的时候,别提多高兴了。
就像爱迪生试验灯丝一下,在无数次失败后,终于找到了一种材料可以胜任灯丝的工作。这种喜悦真的令人振奋,往日的阴霾和不爽终于一扫而光。
其实我也尝试过WlanGetProfile和WlanSetProfile,虽然有时结果是能够连上指定AP,但是函数返回结果却总是ERROR_INVALID_PARAMETER。
网上的例子,很多都是抄来抄去的,写的不明不白,虽然有过帮助,但是也有些误导。
今天自己成功的连接到指定AP了(用命令行运行我的例子,输入参数profile name),我一定要把它发表出来,让其他人有个参考。
我认为这是一件诚意的作品,在此也谢谢给过我帮助的朋友。
最后说一下获得的信号。标准信号RSSI是负值,而这里获得的信号都是正值(0~100),在有些需要RSSI的地方,我们需要转换一下:

if (pBssEntry->wlanSignalQuality == 0)
  iRSSI = -100;
 else if (pBssEntry->wlanSignalQuality == 100)
  iRSSI = -50;
 else
  iRSSI = -100 + (pBssEntry->wlanSignalQuality/2);  

 wprintf(L" Signal Quality[%u]:\t %u (RSSI: %i dBm)\n", j,
  pBssEntry->wlanSignalQuality, iRSSI);

7.Wifi on与wifi off
下面要说的是在软件层面控制无线网卡的开和关。
问题听起来简单,调查起来复杂,但解决起来却也简单。关键函数便是Native wifi api中的WlanSetInterface。其实这个API功能也是非
常强大的,我只用到其中控制wifi radio state的功能。官网文档在此
函数原型:

DWORD WINAPI WlanSetInterface(
 _In_  HANDLE hClientHandle,
 _In_  const GUID *pInterfaceGuid,
 _In_  WLAN_INTF_OPCODE OpCode,
 _In_  DWORD dwDataSize,
 _In_  const PVOID pData,
 _Reserved_ PVOID pReserved
);

重点说一下三个参数:
(1) OpCode,指定要设置的参数。我们选择wlan_intf_opcode_radio_state
(2) DwDataSize,pData的size。传入时用sizeof得到。
(3) pData,radio state对应的data是WLAN_PHY_RADIO_STATE。
看看这个state结构体:

typedef struct _WLAN_PHY_RADIO_STATE {
 DWORD    dwPhyIndex;
 DOT11_RADIO_STATE dot11SoftwareRadioState;
 DOT11_RADIO_STATE dot11HardwareRadioState;
} WLAN_PHY_RADIO_STATE, *PWLAN_PHY_RADIO_STATE;

Index设为0.
State设置如下:

typedef enum _DOT11_RADIO_STATE {
 dot11_radio_state_unknown,
 dot11_radio_state_on,
 dot11_radio_state_off
} DOT11_RADIO_STATE, *PDOT11_RADIO_STATE;

与前几个API(比如wlanconnect)相比,这个函数的使用简单多了。全部源码如下:

// ManageWirelessNetwork.cpp : Defines the entry point for the console application.
// 

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <shellapi.h>
#include <wlanapi.h> 

// Need to link with shell32.lib
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "wlanapi.lib") 

int _tmain(int argc, _TCHAR* argv[])
{
 DWORD dwResult = 0;
 DWORD dwMaxClient = 2;
 DWORD dwCurVersion = 0;
 HANDLE hClient = NULL;
 PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
 PWLAN_INTERFACE_INFO pIfInfo = NULL; 

 dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);
 if (dwResult != ERROR_SUCCESS) {
  wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
  return false;
 } 

 dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList);
 if (dwResult != ERROR_SUCCESS) {
  wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);
  return false;
 } 

 WLAN_PHY_RADIO_STATE state;
 state.dwPhyIndex = 0;
 state.dot11SoftwareRadioState = dot11_radio_state_on;
 PVOID pData = &state; 

 dwResult = WlanSetInterface(hClient,&pIfList->InterfaceInfo[0].InterfaceGuid,
  wlan_intf_opcode_radio_state,sizeof(WLAN_PHY_RADIO_STATE),pData,NULL); 

 if(dwResult == ERROR_SUCCESS)
 {
  wprintf(L"set state success!\n");
 }
 else
 {
  wprintf(L"set state failed!err is %d\n",dwResult);
 } 

 return 0;
}

8.GOTO在释放资源时的作用
GOTO语句有着很臭的名声,我们的老师经常教导我们说,不要轻易使用它。
C++跳转语句有三个:goto、break和continue。它们只是工具,我觉得问题不能归咎于工具,问题在于人。
就像指针一样,goto这个无条件跳转语句力量还是很强大的,如果滥用,出现问题很难排查。
但有些时候goto确实是不二选择,例如我遇到的,在函数中有多个出口,而每个出口都遇到释放资源的时候,与其都把释放语句不厌其烦的写一遍,
不如一个goto语句来的干脆利落。
下面的例子取自上一篇Native Wifi API文章,由于我们的程序经常控制的wifi的on和off,必须注意释放资源。就拿WlanOpenHandle来说,
如果不注意对称WlanCloseHandler,程序几次运行后报错:ERROR_REMOTE_SESSION_LIMIT_EXCEEDED
官网解释为:Too many handles have been issued by the server.
所以我们会在每个API调用后,确认返回值,如果错误,程序将不再继续向下运行,return之前,我们必须释放资源。当出口很多时,我们要写很多同样的代码,
很烦躁,难读,代码急速膨胀。但使用goto后,问题便轻松了许多,请看简单例子:

// ManageWirelessNetwork.cpp : Defines the entry point for the console application.
// 

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <shellapi.h>
#include <wlanapi.h> 

// Need to link with shell32.lib
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "wlanapi.lib") 

int _tmain(int argc, _TCHAR* argv[])
{
  DWORD dwResult = 0;
  DWORD dwMaxClient = 2;
  DWORD dwCurVersion = 0;
  HANDLE hClient = NULL;
  PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
  PWLAN_INTERFACE_INFO pIfInfo = NULL; 

  dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &hClient);
  if (dwResult != ERROR_SUCCESS) {
    wprintf(L"WlanOpenHandle failed with error: %u\n", dwResult);
    return false;
  } 

  dwResult = WlanEnumInterfaces(hClient, NULL, &pIfList);
  if (dwResult != ERROR_SUCCESS) {
    wprintf(L"WlanEnumInterfaces failed with error: %u\n", dwResult);
    goto RELEASE_RESOURCE;
  } 

  WLAN_PHY_RADIO_STATE state;
  state.dwPhyIndex = 0;
  state.dot11SoftwareRadioState = dot11_radio_state_on;//off here too.
  PVOID pData = &state; 

  dwResult = WlanSetInterface(hClient,&pIfList->InterfaceInfo[0].InterfaceGuid,
    wlan_intf_opcode_radio_state,sizeof(WLAN_PHY_RADIO_STATE),pData,NULL); 

  if(dwResult == ERROR_SUCCESS)
  {
    wprintf(L"set state success!\n");
  }
  else
  {
    wprintf(L"set state failed!err is %d\n",dwResult);
  }
RELEASE_RESOURCE:
  if(hClient)
  {
    WlanCloseHandle(hClient,NULL);
    hClient = NULL;
  }
  if(pIfList)
  {
    WlanFreeMemory(pIfList);
    pIfList = NULL;
  }
  if(pIfInfo)
  {
    WlanFreeMemory(pIfInfo);
    pIfInfo = NULL;
  }
  return 0;
}

最后,goto还会用来跳出多重循环。但需要注意的是,只能从内层跳到外层,不可逆操作。

后记:
其实几个月前就要实现windows上的wifi on和off,问了许多人,发了许多帖子,最后都不了了之。之后的日子里也发生了许多事。国内的
搜索无果,加上google的无法使用,都对调查增加了些许难度。我们把重点先放到了native wifi api的几个方法,见上一篇玩转文章。但
那并不是我想要的。
原以为windows也会想android一样,普通应用没有权限来控制wifi的开关呢,结果并不是这样。这也宣告了之前我的判断失误。
直到今天,通过Bing发现了几条线索。那是通过C#调用native wifi api的问题,里面提及了之前并没有重视的wlansetinterface。
Interface,在这里我觉得可以理解成无线网卡。类似的WlanEnumInterfaces中实现的功能是罗列出当前无线网卡。
无线网卡的设置,其中有一项是radio的状态。
果然,这一切都有了了断。

(0)

相关推荐

  • 深入解析C++的WNDCLASS结构体及其在Windows中的应用

    WNDCLASS是一个由系统支持的结构,用来储存某一类窗口的信息,如ClassStyle,消息处理函数,Icon,Cursor,背景Brush等.也就是说,CreateWindow只是将某个WNDCLASS定义的窗体变成实例.要得到某一窗口的WNDCLASS数据,可以用GetClassLong(); RegisterClass()就是在系统注册某一类型的窗体.也就是将你提供的WNDCLASS数据注册为一个窗口类,在WNDCLASS.lpszClassName中定义该WNDCLASS的标识,无论C

  • Visual C++程序设计中Windows GDI贴图闪烁的解决方法

    本文实例讲述了Visual C++程序设计中Windows GDI贴图闪烁的解决方法.分享给大家供大家参考.具体如下: 一般的windows 复杂的界面需要使用多层窗口而且要用贴图来美化,所以不可避免在窗口移动或者改变大小的时候出现闪烁. 先来谈谈闪烁产生的原因 原因一: 如果熟悉显卡原理的话,调用GDI函数向屏幕输出的时候并不是立刻就显示在屏幕 上只是写到了显存里,而显卡每隔一段时间把显存的内容输出到屏幕上,这就是刷新周期. 一般显卡的刷新周期是 1/80秒左右,具体数字可以自己设置的. 这样

  • 基于Windows C++ 应用程序通用日志组件的使用详解

    引言 在如何记录程序日志方面,通常有三种选择: 1.采用Log4CXX等公共开源日志组件:这类日志组件的特点是跨平台且功能比较强大,例如可以把日志发往另一台服务器或记录到数据库中等:另外,可配置性较高,可以通过配置文件或程序代码对日志进行很多个性化设置.但从另外一个角度看,由于这些优点往往也导致了在使用方面的缺点.首先,对于一般应用程序来说,它们并不需要太多的功能,通常只需要把日志记录到文件或反馈到应用程序,功能太多反正让用户使用起来觉得繁琐还得背负很多从来都用不到的代码.其次,这类日志组件通常

  • 在C++程序中开启和禁用Windows设备的无线网卡的方法

    1.列出当前网卡:SetupDiEnumDeviceInfo 2.找出当前无线网卡的名字(用natvie wifi api) 3.卸载\安装此驱动 问题: log为:SetupDiSetClassInstallParams failed. -536870347   完整代码如下: // ControlWirelessCard.cpp : Defines the entry point for the console application. // #include "stdafx.h"

  • C++ 学习之旅 Windows程序内部运行原理

    学习C++与.net不同的是,一定要搞清楚Windows程序内部运行原理,因为他所涉及大多数是操作系统的调用,而.net毕竟是在.netFrameWork上唱戏. 那Windows应用程序,操作系统,计算机硬件之间的相互关系究竟什么了,下面的图就给予很好的解释. 向下箭头①是 应用程序运行判断处理的结果,输出到输出的设备. 向上箭头②是输入设备,输入到操作系统中. 向下箭头③代表API,我们要解释以下API是什么.API是应用程序接口, 表示应用程序可以通知操作系统执行某个具体的动作,如操作系统

  • c++利用windows函数实现计时示例

    复制代码 代码如下: //Windows系统下可以用 time(),clock(),timeGetTime(),GetTickCount(),QueryPerformanceCounter()来对一段程序代码进行计时 #include <stdio.h>#include <windows.h>#include <time.h>                   //time_t time()  clock_t clock()    #include <Mmsys

  • C++程序中使用Windows系统Native Wifi API的基本教程

    Windows应用想要实现连接wifi,监听wifi信号,断开连接等功能,用NativeWifi API是个不错的选择. 打开MSDN,搜索NativeWifi Api,找到Native Wifi页.在这里. 信息量很大,如果像我着急实现上述功能,看海量的文档有些来不及.如果直接给我例子,在运行中调试,阅读代码,效率会更高. 但是,我并没有成功.首先,Sample在SDK中,参见这里.我下载几次都失败了,最后放弃这条路.后来同事给了我一份Sample,我不敢确定是否就是这个,但是代码写的也是很晦

  • Windows系统下MySQL8.0.21安装教程(图文详解)

    安装建议:尽量不要用.exe进行安装,用压缩包安装,对日后的卸载/版本升级更为方便 下载地址:https://dev.mysql.com/downloads/mysql/ 1.点击上面的下载地址得到zip压缩包 2.解压到要安装的目录 我这里是E:\database\mysql8\mysql-8.0.21-winx64\bin data 文件夹与 my.ini文件需手动创建出来 3.添加环境变量 我的电脑–>属性–>高级系统设置–>环境变量 选择path添加:mysql安装目录下的bin

  • PHP中把错误日志保存在系统日志中(Windows系统)

    [将错误记录到系统日志中] 在 php.ini 中将 error_log 设置为: 复制代码 代码如下: error_log = syslog 或者在运行时使用 ini_set() 函数设置. [例1] <?php //关闭错误显示 ini_set('display_errors', 0); //开启错误日志功能 ini_set('log_errors', 'on'); //设置错误日志的路径 ini_set('error_log', 'syslog'); //显示所有错误 error_repo

  • 在Linux和Windows系统上安装Nginx服务器的教程

    1.在CentOS系统上安装Nginx 在 CentOS6 版本的 EPEL 源中,已经加入了 nginx 的 rpm 包,不过此 RPM 包版本较低.如果需要更新版本,可以使用官方制作的 rpm 包,或者使用源码包编译安装. 还可以使用一些二次开发功能增强的 nginx 版本,例如淘宝的 Tengine 和 OpenResty 都是不错的选择. 1.1 常用编译参数 --prefix=PATH:指定 nginx 的安装目录     --conf-path=PATH:指定 nginx.conf

  • windows系统mysql5.7.18安装图文教程

    windows系统MySQL安装教程 下载 1.登录https://dev.mysql.com/downloads/installer/ 选择Microsoft Windows 点击Download 2.点击页面下方No thanks, just start my download.开始下载 安装 1.双击刚下载完成的文件mysql-installer-community-5.7.18.1.msi开始安装 2.点击Add... 3.选择I accept the license terms 点击N

  • 程序中获取linux系统启动时间方法

    1.前言 时间对操作系统来说非常重要,从内核级到应用层,时间的表达方式及精度各部相同.linux内核里面用一个名为jiffes的常量来计算时间戳.应用层有time.getdaytime等函数.今天需要在应用程序获取系统的启动时间,通过sysinfo中的uptime可以计算出系统的启动时间. 2.sysinfo结构 sysinfo结构保持了系统启动后的信息,主要包括启动到现在的时间,可用内存空间.共享内存空间.进程的数目等.man sysinfo得到结果如下所示: 复制代码 代码如下: struc

  • PowerShell中获取Windows系统序列号的脚本分享

    windows序列号可以直接在注册表中读取,PowerShell要做的只是读出数据后稍作处理,让它更像一个序列号. 复制代码 代码如下: function Get-ProductKey {        $map="BCDFGHJKMPQRTVWXY2346789"     $value = (get-itemproperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").digitalproductid

  • nginx+tomcat实现Windows系统下的负载均衡搭建教程

    刚入行没多久就听过'负载均衡'的大名,到现在因为工作接触的少,所以没什么太多的认识.但自己又对其非常的好奇,所以前两天通过查资料,在自己的笔记本上就搭建了一个超简单的案例(工作中没有时间,晚上到家了条件又不够,只能用自己的笔记本将就一下了,重在理解思想..) 通俗点将,负载均衡就是因为访问流量太大,导致项目访问不流畅.甚至宕掉,所以通过一种分流的方式来缓解这种情况. 首先,安装两个tomcat,可以是同一个复制成两个,也可以下载两个不同版本的tomcat,我就是下载了两个不同版本的.下载地址:h

  • 部署ASP.NET Core程序到Windows系统

    目录 一.创建项目 二.发布项目 1.框架依赖 2.独立部署 三.部署 1.配置部署环境 2.控制台方式部署 3.部署到IIS 4.独立部署 一.创建项目 本篇文章介绍如何将一个ASP.NET Core Web程序部署到Windows系统上.这里以ASP.NET Core WebApi为例进行讲解.首先创建一个ASP.NET Core WebApi项目,使用默认的Values控制器,这里使用Visual Studio 2019创建一个ASP.NET Core 3.1d的WebApi项目. 创建新

  • 如何在linux系统的host上安装windows系统的guest

    本文将会介绍如何在Linux系统的host上安装windows系统的guest.这里以win7-32系统为例进行介绍. 1. 首先是正常运行linux的host系统,进入要放置相关安装文件的目录,这里假定把相关文件放置在/home目录下. 2. 获得windows系统镜像文件,也就是*.iso文件.相关命令为#wget  ip(ip指的是系统镜像文件所在的地址). 3. 创建硬盘文件,相关命令为:qemu-img create -f raw win7-32.raw 50G (注意这里的win7-

随机推荐