2009-10-15

Native WiFi API (Wlanapi)

Windows のプログラミングのネタです。
最近、お仕事で必要になり、今更ながら Study したのですが、これ関連のキーワードを検索しても日本語の情報が少なかったので、この機会に書き留めておきます。

開発環境: Visual Studio 2005 (Visual Studio 8)
開発言語: C
対象OS: Windows XP SP3
Embedded な仕事が多いので、C++ ではなく、C がメインです。

◆ Native WiFi API 概要 (Wireless LAN API)
PC にワイヤレスのネットワークアダプタをつけていると、ワイヤレスネットワーク接続 というメニューが使えて、SSID のリストを更新したり、接続/切断 といった操作が可能になりますが、それらをネイティブなプログラム言語から簡単に操作できるようにしたもの。
※ UWSC 使ってラクしてたんだけど、XPスタイルだったり、クラシックだったり、[スタート]メニューのオプション差異だったりで、対応が大変なことになったので、Native WiFi を使うことにしました。

Native Wifi (Windows) -- MSDN
http://msdn.microsoft.com/en-us/library/ms706556%28VS.85%29.aspx
Native WiFi API は、Windows XP SP3 以降から対応 との事なんですが、それは Wlanapi.dll が(System32 の中に)入ってます...という事らしいです。
開発するには、Wlanapi.lib, Wlanapi.h が必要です。

◆Windows SDK 6.0 のインストール
ワシの環境 (VS8) には、Wlanapi 関連のファイル(.lib/.h) はありませんでした。最新の Windows SDK (旧:Platform SDK) に含まれているらしいです。
早速ダウンロード。
Windows SDK 6.0 (EN)
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=4377f86d-c913-4b5c-b87e-ef72e5b4e065

Windows Vista および .NET Framework 3.0 ランタイム コンポーネント用 Microsoft Windows Software Development Kit
http://www.microsoft.com/downloads/details.aspx?FamilyID=7614fe22-8a64-4dfb-aa0c-db53035f40a0&DisplayLang=ja
MS の英語サイトからでも、日本語サイトからでもダウンロード可能。日本語サイトだとバージョン表示が 1.0 とかになってるけど、ファイル名をみると 6.2.600... とかなので OK のようです。ワシは、日本語サイトからダウンロードしました。Vista とか言ってるけど、XP に入れて良いものです。
※ MS のサイトはすぐにデッドリンクになるので、困ったら [Windows SDK] で検索してみてください。

ダウンロードしたファイルは、CD/DVD のイメージファイル(*.img) なので、仮想CD/DVDドライブソフト(DAEMON Tools Lite など)でイメージをマウント。インストールウィザードに従いインストールを完了させます。

インストールの途中、HDD のアクセスランプが点きっぱなしになり、プログレスバーが固まった...ように見える時がありますが、そこは耐えて待ってください。CPU: Core2 Duo 2.4GHz/HDD: SATA2 (会社PC)なんですが、インストールの終わる気配が無いので、何度キャンセルボタンを押しそうになったか...。しかし、寝て待ってたら、無事に完了しました。

◆環境設定
Windows SDK は、下記のフォルダにインストールされたハズ。
  • C:\Program Files\Microsoft SDKs\Windows\v6.0\
で、この後はどうするのか?→Visual Studio が上記フォルダパスを認識するよう、プロジェクトのプロファイルをセットアップする必要があります。
また、Native WiFi のプログラムを書く場合は、上記フォルダ配下から、Wlanapi.lib, Wlanapi.h を(Native WiFi API を利用したい)自分のプロジェクトのフォルダへコピーして来ます。

プロジェクトを立ち上げ(Visual Studio 2005 起動)、プロジェクトのプロファイルを修正します。
「C/C++/全般/追加のインクルードディレクトリ」に Windows SDK の Include フォルダを指定し、パスを通します。
C:\Program Files\Microsoft SDKs\Windows\v6.0\Include

「リンカ/入力/追加の依存ファイル」 に wlanapi.lib を追加します。
自分のプロジェクトの Native WiFi API を利用するモジュールで、以下の宣言を追加
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <windows.h>
#include <winnt.h>
#include "wlanapi.h"
...と、これでコンパイルが通るハズ。
プロジェクト全体に WIN32_LEAN_AND_MEAN を適用すると問題がでる場合もあるかも。Wlanapi を使うモジュール内でのみの宣言が吉。

◆使用する
API 利用のサンプルコードは、Windows SDK のインストールフォルダ階層に含まれてます。
Native Wifi API Sample
C:\Program Files\Microsoft SDKs\Windows\v6.0\Samples\NetDs\Wlan

追記:適当なネットワークに接続するコードを書いてみました。

blogger にソースコードを貼り付けるテストも兼ねて。
//-------------------------------------------------------------------------
//
//  Native WiFi API 関連
//
//-------------------------------------------------------------------------

#define  WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <windows.h>
#include <winnt.h>
#include "wlanapi.h"


//-------------------------------------------------------------------------
//  ワイヤレスネットワークに接続する
//
BOOL ConnetWirelessLAN(void)
{
 HANDLE      hWLAN = NULL;
 PWLAN_INTERFACE_INFO_LIST pInterfaceList = NULL;

 DWORD dwNicCount;
 DWORD dwVersion;
 BOOL retCode = FALSE;

 // WLAN ハンドル取得
 if(WlanOpenHandle(WLAN_API_MAKE_VERSION(1, 0), NULL, &dwVersion, &hWLAN) != ERROR_SUCCESS){
  return FALSE;
 }

 // NIC リスト取得
 if(WlanEnumInterfaces(hWLAN, NULL, &pInterfaceList) != ERROR_SUCCESS){
  WlanCloseHandle(hWLAN, NULL);
  return FALSE;
 }

 // NIC 列挙
 for(dwNicCount=0; dwNicCount < pInterfaceList->dwNumberOfItems; dwNicCount++){
  PWLAN_AVAILABLE_NETWORK_LIST pAvailableNetworkList;
  GUID*       pGuid;

  pGuid = &pInterfaceList->InterfaceInfo[dwNicCount].InterfaceGuid;

  //使用可能なネットワークリストの取得
  if(WlanGetAvailableNetworkList(hWLAN, pGuid, 0, NULL, &pAvailableNetworkList) == ERROR_SUCCESS){
   DWORD dwAvailableCount;

   //見つけたネットワークに対して順に接続を試みる
   for(dwAvailableCount=0; dwAvailableCount < pAvailableNetworkList->dwNumberOfItems; dwAvailableCount++){
    PWLAN_AVAILABLE_NETWORK  pAvailableNetwork = &pAvailableNetworkList->Network[dwAvailableCount];
    WLAN_CONNECTION_PARAMETERS wlanConnectionParams;

    //接続パラメータ
    ZeroMemory(&wlanConnectionParams, sizeof(WLAN_CONNECTION_PARAMETERS));
    wlanConnectionParams.wlanConnectionMode = wlan_connection_mode_profile;
    wlanConnectionParams.strProfile         = pAvailableNetwork->strProfileName;
    wlanConnectionParams.pDot11Ssid         = &pAvailableNetwork->dot11Ssid;
    wlanConnectionParams.pDesiredBssidList  = NULL;
    wlanConnectionParams.dot11BssType       = pAvailableNetwork->dot11BssType;
    wlanConnectionParams.dwFlags            = 0;

    //接続
    if(WlanConnect(hWLAN, pGuid, &wlanConnectionParams, NULL) == ERROR_SUCCESS){
     retCode = TRUE;
     break;
    }
   }

   WlanFreeMemory(pAvailableNetworkList);
  }
 }

 WlanFreeMemory(pInterfaceList);
 WlanCloseHandle(hWLAN, NULL);

 return retCode;
}

ソースコードをBloggerに貼り付けるための変換("<, >"記号をタグとして認識させないようにするとか)には、クリボウさんのコンバータを利用させて頂きました。
有用なToolの提供、有難うございます。
クリボウの Blogger Tips: コードをハイライトする「Code Prettify」ウィジェット