ページ

2007-09-30

受信信号強度の取得

今回は PHSの受信信号強度の話。
 
私の生活圏はウィルコムのサービスエリアの端です。
今日も家族が連絡をしようとしたのになかなか繋がらなかったとの事。
 
アンテナはウィルコムさんに頑張って頂くとして、 圏外に移動したときに気付くような仕組みが欲しいと思いました。
 
PHSの受信信号強度の取得方法は 添付のコマンドリファレンスにも載っていませんが、 既に先人の方々によって調査されています。
 
「at@@lvl」というのが使えそうですね。
早速、試してみました。
 
 
1回目が自宅の窓際で 2回目が部屋の奥、3回目が別の部屋で圏外です。
 
自宅でこれだけのテストができるとはなんとありがたい環境でしょうか(違
 
ともかく、レスポンスが 00の場合は圏外という事でよさそうです。
後は開発環境を何とかしないと...。
 

2007-09-29

Bluetoothアダプタ購入

ウィルコムストアで注文していた Bluetoothアダプタが届きました。
 
今回購入したのはアダプタだけで、肝心のBluetoothデバイスがありません。
あまり意味はないのですが、手持ちのFOMA端末に繋いでみました。
 
 
設定中 パスフレーズが一致せずに先に進めなかったのですが、 単にアドエスの入力モードが英数モードになっていただけでした。
誰も引っかからないとは思いますが、一応お気をつけください。
 
ペアリング後は問題なくダイアルアップできました。
速度的には普段のデータ定額・高速化なしとの違いは体感できません。
PHS圏外での予備と考えるとなかなか便利かもしれませんね。
 

2007-09-28

デッドロック

WifiInfoは WM_TODAYCUSTOM_QUERYREFRESHCACHEメッセージが来る度に無線LANの状態を取得しています。
画面の再描画は無線LANの状態が変化したときだけなのですが rlTodayと併用したときの画面のチラつきが気になったので、 少しでも負荷を下げるために無線LANの監視をスレッド化してみようと思いました。
 
IOCTL_NDISUIO_REQUEST_NOTIFICATIONを使って 接続・切断を検出しようとしたのですが、 テスト版を職場の PCでビルドして動かしてみたところ見事にアドエスが動かなくなってしまいました。
たぶん WaitForMultipleObjectsあたりでで止まっているみたいです。
 
これが有名なデッドロックという奴でしょうか。
テストもせずに INFINITE指定は無謀でした。
 
問題はここから。
動かないアドエスはフルリセットするしかないのですが、フルリセットするためには ACアダプタが必要です。
 
ACアダプタは自宅なので帰宅すればフルリセットすることができます。
ところが自宅のPCは故障中、電話帳等を戻すには職場のPCを借りるしか手はありません。
 
おお、ここにもデッドロックが(笑
 
とりあえず週末はアドエス単体でできるところまで復旧作業でしょうか。
 

2007-09-27

今ごろになってカスタマイズ

未だに PCが壊れたままで何も出来ないので、 今ごろになって Today画面をカスタマイズしてみました。
 
まずは shino-blogさんからテーマを頂きました。 画面の縦横を切り替えると壁紙が正しく表示できてなかったのですが、 同じページの「Real WVGA & VGA壁紙」をインストールすることで正しく表示できるようになりました。
 
次に rlTodayを導入。
公式ページのフォーラムから rlPhoneといくつかのアイコンを頂きました。
 
アプリの登録画面が使いにくかったので rlToday.iniだけは PCを借りて編集しました。
頻繁に使用する Todayの設定を割り当てているのがポイントです。
[Files]
CommmandLine_0=
CommmandLine_1=
CommmandLine_2=
CommmandLine_3=
CommmandLine_4=
CommmandLine_5=
CommmandLine_6=
CommmandLine_7=-directory:\MicroSDカード\DCIM
CommmandLine_8=
CommmandLine_9=cplmain.cpl,13
FileName_0=\Program Files\OffisnailContact\OffisnailContact6_WZERO3.exe
FileName_1=\Program Files\OffisnailNote6\OffisnailNote6.exe
FileName_2=\Program Files\Opera\OperaLaunch.exe
FileName_3=\microSDカード\Program Files\2++\2.EXE
FileName_4=\microSDカード\Program Files\TwitterAway\TwitterAway.exe
FileName_5=\Windows\SkypeLauncher.exe
FileName_6=\Program Files\GSFinder+ for W-ZERO3\GSFinder-W03.exe
FileName_7=\Windows\pimg.exe
FileName_8=\microSDカード\Program Files\oneHandCalc\oneHandCalc.exe
FileName_9=\windows\ctlpnl.exe
IconPath_0=\Program Files\rlToday\rlPhone_bk\address.png
IconPath_1=\Program Files\rlToday\rlPhone_bk\edit.png
IconPath_2=\Program Files\rlToday\rlPhone_bk\web.png
IconPath_3=\Program Files\rlToday\rlPhone_bk\2.png
IconPath_4=\Program Files\rlToday\rlPhone_bk\tw_01.png
IconPath_5=\Program Files\rlToday\rlPhone_bk\skype.png
IconPath_6=\Program Files\rlToday\rlPhone_bk\idealib.png
IconPath_7=\Program Files\rlToday\rlPhone_bk\finder.png
IconPath_8=\Program Files\rlToday\rlPhone_bk\calc.png
IconPath_9=\Program Files\rlToday\rlPhone_bk\utlt.png
Name_0=Address
Name_1=Memo
Name_2=Opera
Name_3=2++
Name_4=Twitter
Name_5=Skype
Name_6=GSFinder
Name_7=Photos
Name_8=Calc
Name_9=Util
 
結果はこんな感じになりました。  
ただ、この状態で WifiInfoで無線をオンにすると rlTodayがはげしく点滅します。
こちらのページを参考に時計の秒針を消してみたりもしたのですが、変化はありませんでした。
 
他の Todayプラグインでは特に問題も無さそうでしたので、WifiInfoの表示まわりの問題でしょうか。
むしろ WifiInfoを独立したTodayプラグインとせずに、無線LANの情報をレジストリに吐き出すプログラムにしたほうがいいのかもしれませんね。
 

2007-09-26

.NETで Todayプラグイン

ちょっと調べ物をしていたときに MSDNで気になる記事を見つけました。
ちょっと古い記事ですが .NETで Todayプラグインを作ろうという内容でした。
Todayプラグインのお約束の制御は ".NETCF Today Screen Plug-in Host"というアンマネージコードで処理してくれるようです。
 
記事では Embedded Visual C++を想定しているようですが、Visual Studio 2005でも利用することができれば Todayプラグインを作るのが楽になるのではないでしょうか。
 
ただ、古い記事なのでいつぞやの問題のような 変更に追随できているのか気になります。
いろいろ試してみるためにも、早急にPCを復旧させたいですね。
 

2007-09-25

Todayプラグインのフォントサイズを変更する

先日気付いたWifiInfoのフォントサイズの問題を修正してみました。
 
 
 
フォントサイズは SHGetUIMetricsで取得できたので WM_PAINTの部分に追加します。
// フォントサイズを取得する。
if (S_OK == SHGetUIMetrics(SHUIM_FONTSIZE_POINT, &dwFontSize, sizeof(dwFontSize), NULL)) {
    dFontSize = dwFontSize / 100;
} else {
    // 取得できない場合は 9ポイントとしておく
    dFontSize = 9.0;
}
hSysFont = (HFONT) GetStockObject(SYSTEM_FONT);
GetObject(hSysFont, sizeof(LOGFONT), &lf);
lf.lfWeight = FW_NORMAL;
lf.lfHeight = (long) -((dFontSize * (double)GetDeviceCaps(hDC, LOGPIXELSY) / 72.0)+.5);
hFont = CreateFontIndirect(&lf);
hFontOld = (HFONT) SelectObject(hDC, hFont);
 
注意点としてフォントサイズをポイントで取得した場合は 100分の1にする必要があります。
最初、巨大な文字の端だけが表示されていて何が起こっているのかわかりませんでした(笑
 
また SHGetUIMetricsの結果を見る限り、標準のフォントサイズは 9ポイントで大丈夫でした。
もちろん環境によってどのようなフォントサイズになっているのかは分からないので取得しておく方が無難ですね。
 
他にも確認したい事はたくさんあるのですが、借り物の PCなので今日はこの辺で...。
とりあえずの修正版を W-ZERO3.org Uploaderにアップしておきます。  

2007-09-23

Todayプラグインの文字サイズは?

アドエスから簡単更新続行中(笑
 
今日になって気付いたのですが、 Fn+カーソル上下で Todayプラグインのフォントサイズを変更できるみたいです。
 
何かメッセージが飛んでくるのでしょうか...。
当然 WifiInfoは対応できていません(笑
 
ついでに、よく見ると WifiInfoのフォントサイズは標準状態でも他のTodayプラグインよりも大きい気がします。
どこかの資料で、Todayプラグインのフォントサイズは 9ポイントと読んだような気がするのですが間違えていたようですね。
 
あ~早く直してしまいたい。
 

2007-09-22

11bか 11gか

PCが壊れてしまったのでアドエスから更新。
 
WifiInfoでリンク速度を表示しようとすると、 11gのアクセスポイントに接続しているにもかかわらず リンク速度が 11Mbpsと表示されています。
 
もしかしたら、11gで接続できずに 11bで接続しているのかと思って、 無線APのログを見てみましたが、ちゃんと 11gで繋がっていました。
 
OID_802_11_NETWORK_TYPE_IN_USEを使うことで Ndis802_11FHや Ndis802_11OFDM24 といった結果を取得して 11bか 11gかを調べることができそうなのですが、 WM6のドキュメントでは Ndis802_11OFDM24の記述はありません。
 
もしかして WM6では機能してないのでしょうか。
ntddndis.hには Ndis802_11OFDM24も入っていたような気がするので、 単にアドエスの無線LANドライバがそこまで面倒見てくれてないだけなのかもしれません。
 
いずれにしてもリンク速度くらいはちゃんと教えて欲しいですよね。
 

2007-09-21

Vistaマシンから Sambaに接続する

職場でテスト用に Vistaマシンを用意したのですが、NASに接続できないトラブルが発生しました。 同じドメインの 2003 Serverには接続できるので、NAS(が利用している Samba)の問題のようです。
 
検索してみたところ すぐに原因が判明、FAQだったようです。 スタートメニューの「検索の開始」の部分に secpol.mscと入力して、ローカルセキュリティポリシーを起動します。
しばらく「ファイル名を指定して実行」はどこだ?と探していました...。
 
[ローカルポリシー]-[セキュリティ オプション]と辿って「ネットワークセキュリティ:LAN Manager 認証レベル」を「NTLM v2応答のみ送信する」から 「NTLM応答のみ送信する」に変更します。
 
 
 
これで無事 NASに繋がるようになったのですが、今度は別のメンバーが Vista Home Basicマシンで同じ問題に遭遇。
しかも Vista Home Basicには secpol.mscがありませんでした。
 
だから あれほど変なものは買うなと言ったのに...
 
仕方が無いので、最初のマシンで設定変更前後のレジストリの比較を取ろうとしたのですが、 ほとんど初期状態にもかかわらず 160MB超のファイルが吐き出されました。
さすがに比較する訳には行きません...Windows Mobileのようにはいかないのですね。
 
でも、これも検索してみるとすぐに解決。
レジストリの HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsaの値を 2に変更することで解決できました。
 
Vistaも少しずつ触っておかないと、この先思わぬトラブルで時間を取られそうですね。
ちょうどいいことに(?)、先日から自宅PCの電源が入らなくなってしまいました。 そろそろ新しい環境に移行しろという事なのでしょうか。
 

2007-09-18

機種依存せずに無線LANのデバイス名を取得する

WifiInfoでは無線LANの状態を取得するときにデバイスの名前を "GSPI86861"と直接指定しています。
ただ、機種依存のコードはあまりカッコよくないので修正する方法を考えてみました。
 
NSDNを眺めていると OID_GEN_PHYSICAL_MEDIUMを使うことで指定したデバイスの種類を取得できるようです。
 
IOCTL_NDISUIO_QUERY_BINDINGで デバイス名を列挙して、それぞれについて無線LANかどうかを調べるコードを書いてみます。
UCHAR                   cQueryBuffer1[1024],
                        cQueryBuffer2[1024];
PNDISUIO_QUERY_BINDING  pQueryBinding       = (PNDISUIO_QUERY_BINDING)&cQueryBuffer1[0];
PNDISUIO_QUERY_OID      pNdisQueryOid       = (PNDISUIO_QUERY_OID)&cQueryBuffer2[0];
NDIS_PHYSICAL_MEDIUM    ndisPhysicalMedium;
PTCHAR                  pcDeviceName;
DWORD                   dwBytesReturned     = 0;
BOOL                    bIsWlanFound        = FALSE;

// デバイス名列挙
pQueryBinding->BindingIndex = 0;
while (DeviceIoControl(
        g_hNdis                                 ,
        IOCTL_NDISUIO_QUERY_BINDING             ,
        (LPVOID)&cQueryBuffer1[0]               ,
        sizeof(cQueryBuffer1)                   ,
        (LPVOID)&cQueryBuffer1[0]               ,
        sizeof(cQueryBuffer1)                   ,
        &dwBytesReturned                        ,
        NULL
)) {
    // デバイスの種別を取得
    pcDeviceName = (PTCHAR)( cQueryBuffer1 + pQueryBinding->DeviceNameOffset );
    pNdisQueryOid->Oid                  = OID_GEN_PHYSICAL_MEDIUM;
    pNdisQueryOid->ptcDeviceName        = pcDeviceName;

    if (DeviceIoControl(
            g_hNdis                             ,
            IOCTL_NDISUIO_QUERY_OID_VALUE       ,
            (LPVOID)&cQueryBuffer2[0]           ,
            sizeof(cQueryBuffer2)               ,
            (LPVOID)&cQueryBuffer2[0]           ,
            sizeof(cQueryBuffer2)               ,
            &dwBytesReturned                    ,
            NULL
    )) {
        memcpy_s(&ndisPhysicalMedium, sizeof(NDIS_PHYSICAL_MEDIUM), &pNdisQueryOid->Data[0], sizeof(NDIS_PHYSICAL_MEDIUM));
        if (ndisPhysicalMedium == NdisPhysicalMediumWirelessLan ) {
            bIsWlanFound = TRUE;
            break;
        }
    }
    pQueryBinding->BindingIndex ++;
}

return bIsWlanFound;
 
このコードはうまく動くようですが、もうひとつ効率が良くないような気がしています。
できればアプリ起動時にデバイス名を取得してその後は取得したデバイス名を使いまわすようにしたいのですが、 無線LANがオフのときにはデバイス名を取得することができません。
 
まだまだ検討の余地がありますね。
 

2007-09-17

読書の秋

まだまだ暑い日が続きますが読書の秋ということで本を買い込んできました。
 
すぐには読めないので本棚にしまっておこうとしたところ、 ものすごく昔に買ったまま積読状態になっていた本を発見しました。
 
「WindowsNT マルチスレッドプログラミング入門」
 
1996年12月初版ですから今から10年以上前の本ですね...。
 
付録が CD-ROMではなくてフロッピーというところに時代を感じさせます。
 
それでも 2,3ページめくってみたところ、つい先日調べていた CreateEventや WaitoForSingleオブジェクト等の使い方が具体的な例で解説されていました。
これは是非とも読破せねば。
 
ちなみにこの本、アマゾンでは定価よりも高値で売りに出されているようです。
読めもしないくせに購入した当時の自分にグッジョブと言っておきます(笑
 

2007-09-16

LED制御 続き

先日の LED制御の件ですが、ちょっとだけ進展がありました。
 
最初に NLedSetDevice指定できる 2個目のLEDが何なのかわからなかった件ですが、2個目のLEDはどうやらバイブレータだったみたいです。
 
普段は [設定]-[電話]-[マナー]-[マナーモード]でバイブレータをオフにしていたので、気づきませんでした。
 
ともかくこれで充電ランプとバイブレータは制御できるようになりました。
NLED_SETTINGS_INFO ledSetting;
ledSetting.LedNum      = 1; // LED 1番 = バイブレータ
ledSetting.OffOnBlink  = 1; // 振動開始

NLedSetDevice(NLED_SETTINGS_INFO_ID, &ledSetting);
 
次に無線LANのランプに関して becknさんから情報を頂きました。
どうも無線LANのオン・オフと同様に名前付きのイベントを送ることで制御できるみたいです。
 
試してみると確かに無線LANのランプが点灯しました。
それにしても こんな情報を一体どうやって調べてくるのでしょうか。まだまだ奥が深いですね。
 
実は電波状態と無線LANのランプについては もしかしたら番号がとんでいるのかと思って 2番以降のLED番号を叩いてみていました。
もちろん何もありませんでしたが...
 
ただ、LED番号は UINTです。 UINT_MAXは 4,294,967,295と定義されていましたので、最後までは付き合いきれませんでした。
 
どうしても気になる方は 500万くらいまでは調査済みですので続きをお願いします(笑
 

2007-09-15

CAMモードの効果?

先日、WifiInfoで無線LANの省電力モードを省電力モード(Max PSP)から通常モード?(CAM)に切り替えられるように変更してみました。
 
ところが Webページを見ている限りでは あまり違いを感じられません。
 
YouTubeだと どちらの設定でもカクカクですしね...。
 
やはりプラシーボ効果だったのかと思っていましたが、 今日になって Skypeの音声通話をすると差が感じられるような気がすることに気が付きました。
これもプラシーボ効果かもしれませんが...
 
Webの閲覧では違いが分からなかった方も是非 Skype Test Callに発信してみてください。
尚、Skypeで音声通話をするときは ChgSndOut.exeをお忘れなく。
 
ちなみに MSDNによると CAMは "continuous access mode"の略ということですが、 Ciscoの資料を見ていると "constantly awake mode"と書かれていました。 どちらにしてもあまり聞きなれない言葉ですね。
 

2007-09-14

LED制御

MSDNを読んでいたら適当にクリックしていたら、 NLedSetDeviceなるものを発見しました。
 
どうやら、指定したLEDを点灯・消灯・点滅させることができる APIみたいです。 早速、適当に動かしてみることにします。
NLED_SETTINGS_INFO ledSetting;
ledSetting.LedNum      = 0; // LED 0番
ledSetting.OffOnBlink  = 1; // 点灯

if (!NLedSetDevice(NLED_SETTINGS_INFO_ID, &ledSetting)) {
    CString strErrorMessage;

    strErrorMessage.Format(_T("Error : %d"), GetLastError());
    MessageBox(NULL, strErrorMessage, _T("NLedSetDevice"), MB_OK);
}
 
このコードで充電ランプが黄緑色に点灯しました。
 
ところが同じように LedNumに 1を指定すれば 電波状態ランプが点灯すると思ったのですが、 実行しても何も光りませんでした。
 
念のため LedNumに 2を指定してみましたが、 今度は ERROR_INVALID_PARAMETER(87)のエラーが発生しました。
 
確認のために NLedGetDeviceInfoで LEDの数を取得してみたところ、2個あることになっているみたいです。
NLED_COUNT_INFO ledCount;
INT iCount = 0;

if(NLedGetDeviceInfo(NLED_COUNT_INFO_ID, (PVOID) &ledCount)) {
    iCount = ledCount.cLeds;
}
 
てっきり 0, 1, 2で充電、電波状態、無線LANのランプが制御できると思っていたのですが、 電波状態と無線LANのランプはどこで制御するのでしょうか?
 
また、システムに登録されている 2番目のLEDはどこに行ってしまったのでしょうか?
 

2007-09-13

WifiInfo更新

WifiInfoのテストをしているときに ふと無線LANの省電力の状態を確認したくなったので、 パワーモードの表示を追加してみました。
 
あれ?省電力モードで動いているんですね。
 
せっかくなので通常のモードに切り替えることができるようにしてみました。
 
パワーモードの表示中にアクションボタンを押すことで省電力の設定を切り替えることができます。
 
 
CAMとうのは "continuous access mode"の略で、要は常に電源がオンの状態らしいです。
Max PSPは "maximum power saving"で省電力モードということです。
最後のPは何でしょうね...
 
この中間に "fast power-saving mode"なるものもあるようなのですが、アドエスでは切り替えることができませんでした。
 
 
そしてパワーモードCAMで速度測定した結果がこれです。
 
 
ちなみにパワーモードMax PSPだとこんな感じです。
 
 
測定は 11bのアクセスポイントに接続して こちらのページで測定させていただきました。
一応、測定の度に Operaのキャッシュはクリアしています。
 
う~ん、プラシーボ効果...でしょうか?
 
とりあえず W-ZERO3.org Uploaderにアップしておきますので、お試しください。  
効果がありそうなら wifictrlみたいに呼び出すだけのプログラムを作ると便利かもしれませんね。
 

2007-09-12

WifiInfo更新

まだまだ修正できてない部分も残っていますが、 WifiInfoの更新版を W-ZERO3.org Uploaderにアップしました。
 
新たに無線LAN接続中にカーソルキーの左右を押すことで画面に表示する情報が切り替わるようになりました。
※Today画面でカーソルの左右キーを使用するには、[設定]-[Today]-[カーソルキー]で「カーソル移動」を選択する必要があります。
 
最初はこれまでと同じIPアドレスを表示します。
 
 
表示内容は変わっていませんが、これまでのレジストリ経由から NDISと WinSock経由で情報を取得するようになりました。
ただ、ときどきループバックアドレスを表示しているような気がします...。
 
 
次にリンク速度と暗号化方式が表示します。
 
 
暗号化方式については AESやTKIPが使えるような高級な機械を持ってないので動作は未確認です(笑
 
更にうちの 11gのアクセスポイントでは常にリンク速度が 11Mbpsになってしまいます。
 
 
最後に受信信号強度を表示します。
 
 
値が 0に近づくほど感度がよいことになります。
スクリーンショットの -49dBはアクセスポイントから 3mほど離れた場所での値です。
 
どの程度が良好な感度と言えるのかはよくわかりません(笑
 
 
内部を大幅に作り変えたことで突っ込みどころ満載な動作をするようになってしまいましたが、 少しずつ直していきますので気長にお付き合いください。
 

2007-09-11

WifiInfo更新中

昨日までのコードをもとに WifiInfoを更新しています。
 
無線LANの状態取得をレジストリの監視からNDIS経由での取得に改めたため、受信信号強度等も取得できるようになっています。
 
 
ただし -48dBがどの程度のものなのかは分かりません(笑
 
修正版をアップローダに...といきたい所ですが、まだ一部のコードが修正できてないのでもうしばらくお待ちください。
 

2007-09-10

無線LANの受信信号強度を取得する

先日から悩んでいた 無線LANの受信信号強度が取得できない問題ですが、つい先ほどあっさりと解決しました。
 
 
と言っても、先日のコードからの変更はありません。
 
単にデバッガを使わずに実行したら動きました。
なんじゃそりゃー
 
 
デバッガで実行していたときのエラー「ERROR_GEN_FAILURE」の日本語訳は 「システムに装着されたデバイスは動作していません。」との事ですが、 ちょっと想像つかないですよね。
 

2007-09-08

無線LANの受信信号強度が取得できない

先日 SSIDを取得したのと同様の方法で無線LANの受信信号強度を取得しようとしています。
 
受信信号強度(RSSI)の取得には OID_802_11_RSSIを 使うようですが、実際に呼び出してみると ERROR_GEN_FAILURE(31)で失敗してしまいます。
 
// RSSI取得
pNdisQueryOid->Oid = OID_802_11_RSSI;
pNdisQueryOid->ptcDeviceName = _T("GSPI86861");

if (DeviceIoControl(
        hNdis                           ,
        IOCTL_NDISUIO_QUERY_OID_VALUE   ,
        (LPVOID)&cBuffer[0]             ,
        sizeof(cBuffer)                 ,
        (LPVOID)&cBuffer[0]             ,
        sizeof(cBuffer)                 ,
        &dwBytesReturned                ,
        NULL)) {

        memcpy_s(&lRssi, sizeof(NDIS_802_11_RSSI), &pNdisQueryOid->Data[0], sizeof(NDIS_802_11_RSSI));
        
        strMessage.Format(_T("RSSI: %ddB"), lRssi);
        MessageBox(NULL, strMessage, _T("受信信号強度を取得してみるテスト"), MB_OK);

} else {
    dwError = GetLastError();
    bRet  = FALSE;
}
 
いろいろ試行錯誤した結果、事前に OID_802_11_RSSI_TRIGGERで トリガ値をセットしておくと何度か成功したのですが、どのような値をセットすればいいのか、成功するときと失敗するときの違いは何なのかがよくわかっていません。
 
もう少し実験と整理が必要ですね。
素直にドキュメント読破した方がいいのかもしれませんが...
 

2007-09-07

Outlook Expressの怪

Postfixでメールの制限をかけるために簡単なポリシーサーバを作成して main.cfの中で smtpd_client_restrictionsに仕掛けました。
 
ポリシーサーバのテストをするために Outlook Expressでメールを送っていたのですが、 何故かメール 1通につきログが 2件記録されています。
 
Outlook Expressのログを見る限り、おかしい動作はしていません。
SMTP: 14:00:29 [rx] 220 xxx.localdomain ESMTP Postfix
SMTP: 14:00:29 [tx] HELO xxxx
SMTP: 14:00:29 [rx] 250 xx.localdomain
SMTP: 14:00:29 [tx] MAIL FROM: xxxxx@xxxxx.jp>
SMTP: 14:00:29 [rx] 250 2.1.0 Ok
SMTP: 14:00:29 [tx] RCPT TO: 
SMTP: 14:00:29 [rx] 250 2.1.5 Ok
SMTP: 14:00:29 [tx] DATA
SMTP: 14:00:29 [rx] 354 Please start mail input.
SMTP: 14:00:29 [tx] 
.
SMTP: 14:00:29 [rx] 250 Mail queued for delivery.
SMTP: 14:00:29 [tx] QUIT
SMTP: 14:00:29 [rx] 221 Closing connection. Good bye.
 
ところが、パケットを監視してみると...。
SMTP: Rsp 220  xxx.localdomain ESMTP Postfix, 34 bytes
SMTP: Cmd HELO xxxxx, 13 bytes
SMTP: Rsp 250  xxx.localdomain, 20 bytes
SMTP: Cmd MAIL FROM: , 44 bytes
SMTP: Rsp 250  2.1.0 Ok, 14 bytes
SMTP: Cmd RCPT TO: , 42 bytes
SMTP: Rsp 250  2.1.5 Ok, 14 bytes
SMTP: Cmd RSET, Resets mail connection
SMTP: Rsp 250  2.0.0 Ok, 14 bytes
SMTP: Cmd RSET, Resets mail connection
SMTP: Rsp 250  2.0.0 Ok, 14 bytes
SMTP: Cmd MAIL FROM: , 44 bytes
SMTP: Rsp 250  2.1.0 Ok, 14 bytes
SMTP: Cmd RCPT TO: , 42 bytes
SMTP: Rsp 250  2.1.5 Ok, 14 bytes
SMTP: Cmd DATA, Begins message composition
SMTP: Rsp 354  End data with ., 37 bytes
MIME: Version =  1.0, multipart/alternative
SMTP: Data Payload, 5 bytes
SMTP: Rsp 250  2.0.0 Ok: queued as AF1E2544412, 37 bytes
SMTP: Cmd QUIT, Terminates the mail session
SMTP: Rsp 221  2.0.0 Bye, 15 bytes
 
MAIL FROM ~ RCPT TOやり直してるじゃないか(笑
 
最終的にポリシーサーバを仕掛ける位置を smtpd_data_restrictionsに変更することで回避できましたが、 自分自身のログにも正直に記録して欲しいですね。
 

2007-09-06

NDIS経由で無線LANの状態を取得してみる

無線LANの状態をまじめに取得してみようと格闘中です。
 
とりあえず NDIS経由で 情報取得できるんだろうなぁということは想像できるのですが、 意味がわからない上にドキュメントの分量も多いので ちょっと挫折気味です。
 
とりあえず斜め読みして理解できた範囲の事を書いておきます。
  1. NDISのハンドルは CreateFileに NDISUIO_DEVICE_NAMEを指定して開く。
    NDISUIO_DEVICE_NAMEは uuiouser.hで "UIO1:"として定義されています。
  2.  
  3. NDISに対する操作は DeviceIoControlに いろいろな制御コードを指定して行う。
 
試しに接続中のSSIDを取得するサンプルを作ってみました。
 
DeviceIoContorolに IOCTL_NDISUIO_QUERY_OID_VALUEを指定することで、 いろいろな情報を取得できるみたいです。 問い合わせたい内容は対象とするデバイス名と一緒に NDISUIO_QUERY_OIDに指定します。
 
サンプルはデバイス名に "GSPI86861"をハードコーディングしている時点でアドエス専用確定ですが...。
 
尚、取得した SSIDはそのままでは表示できないので、UNICODEに変換してやる必要があります。  
static BOOL GetSsid_Test()
{
    HANDLE              hNdis;
    UCHAR               cBuffer[1024];
    PNDISUIO_QUERY_OID  pNdisQueryOid   = (PNDISUIO_QUERY_OID)&cBuffer[0];
    NDIS_802_11_SSID    ndisSsid        = { 0 };
    BOOL                bRet            = TRUE;
    DWORD               dwBytesReturned = 0,
                        dwError;
    CString             strSsid;
    INT                 iLen;

    // NDISのハンドル取得
    hNdis = CreateFile(
        NDISUIO_DEVICE_NAME                         ,
        GENERIC_ALL                                 ,
        0                                           ,
        NULL                                        ,
        OPEN_EXISTING                               ,
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
        (HANDLE)INVALID_HANDLE_VALUE);
    if (hNdis == INVALID_HANDLE_VALUE) {
        return FALSE;
    }

    // SSID取得
    pNdisQueryOid->Oid = OID_802_11_SSID;
    pNdisQueryOid->ptcDeviceName = _T("GSPI86861");

    if (DeviceIoControl(
            hNdis                                   ,
            IOCTL_NDISUIO_QUERY_OID_VALUE           ,
            (LPVOID)&cBuffer[0]                     ,
            sizeof(cBuffer)                         ,
            (LPVOID)&cBuffer[0]                     ,
            sizeof(cBuffer)                         ,
            &dwBytesReturned                        ,
            NULL)) {

        memcpy_s(&ndisSsid, sizeof(NDIS_802_11_SSID), &pNdisQueryOid->Data[0], sizeof(NDIS_802_11_SSID));
        
        // UNICODEに変換してから表示
        iLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)ndisSsid.Ssid, -1, NULL, 0);
        if (iLen > 0) {
            MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)ndisSsid.Ssid, -1, strSsid.GetBuffer(iLen), iLen);
            strSsid.ReleaseBuffer();
            MessageBox(NULL, strSsid, _T("SSIDを取得してみるテスト"), MB_OK);
        }

    } else {
        dwError = GetLastError();
        bRet  = FALSE;
    }

    //
    CloseHandle(hNdis);
    hNdis = INVALID_HANDLE_VALUE;
    return bRet;
}
 
この方法でSSID以外にもいろいろな情報を取得できそうです。
もう少し整理して WifiInfoに反映したいですね。
 

2007-09-05

Microsoft Network Monitor

今日は tcpdumpを使ってちょっとしたネットワークの調査をしていました。
 
「もう少しわかりやすく整形できんかな」と文句を言っていると、会社の同僚が Microsoft Netwoek Monitorというものを教えてくれました。
マイクロソフトが無償で公開しているパケットキャプチャツールで WireSharkと違って WinPcapをインストールする必要がないそうです。  
早速インストールして試してみました。
 
起動後、使用するインタフェースを選択して[Create a new capture tab...]ボタンをクリックします。
 
ツールボックスの[Start Capture]ボタンをクリックしてキャプチャ開始。  
[Stop Capture]でキャプチャ終了。  
表示内容を絞り込むために Display Filterに条件を入力します。
条件は「protocol.」まで入力すると候補が表示されます。
 
条件入力後、[Apply Filter]ボタンをクリックすると結果が絞り込まれます。
 
細かい使い勝手は WireSharkの方が上のような気もしますが、抽出条件の入力補完はなかなか便利です。
少なくともコンソールで tcpdumpしてるよりはよほど効率がいいですよね。
 

2007-09-04

更新の更新プログラム

アドエスの本体アプリケーションの更新版が公開されていました。
1.01aを使っている 4日間、1回もリセットすることなく普通に使えていました。一体何が悪かったのでしょうね。
 
早速アップデートしてみましたが、1.01aから更新しているにもかかわらず「1.00からアップデート」と表示されています。
 
 
ひょっとして 1.01aは無かったことにされてませんか?
 
さて 1.01aで変更された HKLM\System\State\Hardware\Wifiの値ですが、1.02aになってもやはり1のままでした。
 
 
という訳で WifiInfoは 1.18以降でないと動作しません。  
実はこのレジストリの値の意味もよくわかってないので、この値で無線LANのオン・オフを判断するのは手抜きすぎるのかもしれませんね。
まじめに NDIS経由で取得する方法を調べてみようと思います。
 

2007-09-03

ダイアログベースのアプリケーションを作る

Visual Studioが自動生成したソースを元にダイアログベースのアプリケーションの作り方を調べてみました。
Todayプラグインで日本語入力させるのは諦めました...。
 
ポイントは 4つ、
  1. CreateWindowの代わりに CreateDialogを使う
  2. WNDCLASSの cbWndExtraに DLGWINDOWEXTRAを指定する
  3. メッセージループで IsDialogMessageを呼ぶ
  4. WM_INITDIALOGメッセージでダイアログを初期化する
 
1. CreateWindowの代わりに CreateDialogを使う
 
表示したいダイアログをリソースエディタで作成しておき、 CreateDialogで登録します。 このとき、ウィンドウプロシージャが DLGPROC型でないというエラーが出たのでキャストしてみました。
//hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
//    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
g_hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, (DLGPROC)WndProc);
 
 
2. WNDCLASSの cbWndExtraに DLGWINDOWEXTRAを指定する
 
この辺を読む限り、cbWndExtraに DLGWINDOWEXTRAを指定する必要があるみたいです。
WNDCLASS wc;

wc.style         = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc   = WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = DLGWINDOWEXTRA;
wc.hInstance     = hInstance;
wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DIALOGAPP));
wc.hCursor       = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName  = 0;
wc.lpszClassName = szWindowClass;

return RegisterClass(&wc);
 
 
3. メッセージループで IsDialogMessageを呼ぶ
 
CreateDialogのドキュメントによると、ダイアログボックスの動作をサポートするために IsDialogMessageを呼ぶ必要があるそうです。
ただ、プラットホームSDKのドキュメントにはそのような記述がありましたが WM6 SDKのドキュメントには記述がありませんでした。 本当に必要なのでしょうか?
if (!g_hWnd || !IsDialogMessage(g_hWnd, &msg))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}
 
 
4. WM_INITDIALOGメッセージでダイアログを初期化する
 
初期化は WM_CREATEではなく、WM_INITDIALOGで行います。
また、ダイアログの設定にはSHInitDialogを使用します。
 
自動生成されたソースの WM_CREATEで行っていた SHACTIVATEINFOの初期化もここにもって来ました。
case WM_INITDIALOG:
    {
        SHINITDLGINFO   shidi;

        shidi.dwMask = SHIDIM_FLAGS;
        shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_WANTSCROLLBAR;
        shidi.hDlg = hWnd;
        SHInitDialog(&shidi);

        // shell アクティベート情報のストラクチャを初期化します。
        memset(&s_sai, 0, sizeof (s_sai));
        s_sai.cbSize = sizeof (s_sai);

        break;
    }
 
 
後は不要な部分を削除する程度でダイアログを表示できるようになりました。
// DialogApp.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "DialogApp.h"
#include <windows.h>
#include <commctrl.h>

#define MAX_LOADSTRING 100

// グローバル変数:
HINSTANCE           g_hInst;    // 現在のインターフェイス
HWND                g_hWnd;     // ウィンドウハンドル(追加)

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM                MyRegisterClass(HINSTANCE, LPTSTR);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
    MSG msg;

    // アプリケーションの初期化を実行します:
    if (!InitInstance(hInstance, nCmdShow)) {
        return FALSE;
    }

    HACCEL hAccelTable;
    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DIALOGAPP));

    // メイン メッセージ ループ:
    while (GetMessage(&msg, NULL, 0, 0)) {
        if (!g_hWnd || !IsDialogMessage(g_hWnd, &msg)) {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }

    return (int) msg.wParam;
}

//
//  関数 : MyRegisterClass()
//
//  目的 : ウィンドウ クラスを登録します。
//
//  コメント:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
    WNDCLASS wc;

    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = DLGWINDOWEXTRA;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DIALOGAPP));
    wc.hCursor       = 0;
    wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  = 0;
    wc.lpszClassName = szWindowClass;

 return RegisterClass(&wc);
}

//
//   関数: InitInstance(HINSTANCE, int)
//
//   目的 : インスタンス ハンドルを保存して、メイン ウィンドウを作成します。
//
//   コメント:
//
//        この関数で、グローバル変数でインスタンス ハンドルを保存し、
//        メイン プログラム ウィンドウを作成および表示します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    TCHAR szTitle[MAX_LOADSTRING];          // タイトル バー テキスト
    TCHAR szWindowClass[MAX_LOADSTRING];    // メイン ウィンドウ クラス名

    g_hInst = hInstance;                    // グローバル変数にインスタンス処理を格納します。

    // CAPEDIT および SIPPREF のようなデバイス固有のコントロールを初期化するには、アプリケーションの
    // 初期化中に SHInitExtraControls を一度呼び出す必要があります。
    SHInitExtraControls();

    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 
    LoadString(hInstance, IDC_DIALOGAPP, szWindowClass, MAX_LOADSTRING);

    //既に実行している場合は、ウィンドウにフォーカスを与え、終了します。
    g_hWnd = FindWindow(szWindowClass, szTitle); 
    if (g_hWnd) {
        // 最下位の子ウィンドウにフォーカスを設定します。
        // 所有するすべてのウィンドウを前に配置して、アクティブにするために "| 0x00000001"
        // が使用されました。
        SetForegroundWindow((HWND)((ULONG) g_hWnd | 0x00000001));
        return 0;
    } 

    if (!MyRegisterClass(hInstance, szWindowClass)) {
     return FALSE;
    }

    // CreateWindowの代わりに CreateDialogを使う
    g_hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, (DLGPROC)WndProc);

    if (!g_hWnd) {
        return FALSE;
    }

    ShowWindow(g_hWnd, nCmdShow);
    UpdateWindow(g_hWnd);


    return TRUE;
}

//
//  関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的 :  メイン ウィンドウのメッセージを処理します。
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;

    static SHACTIVATEINFO s_sai;
 
    switch (message) {
        // ダイアログ初期化
        case WM_INITDIALOG:
            {
                SHINITDLGINFO   shidi;

                shidi.dwMask = SHIDIM_FLAGS;
                shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_WANTSCROLLBAR;
                shidi.hDlg = hWnd;
                SHInitDialog(&shidi);

                // shell アクティベート情報のストラクチャを初期化します。
                memset(&s_sai, 0, sizeof (s_sai));
                s_sai.cbSize = sizeof (s_sai);

                break;
            }

        case WM_COMMAND:
            wmId    = LOWORD(wParam); 
            wmEvent = HIWORD(wParam); 
            // 選択されたメニューの解析:
            switch (wmId) {
                case IDOK:
                    SendMessage (hWnd, WM_CLOSE, 0, 0);
                    break;
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
            }
            break;
        
        case WM_CLOSE:
            DestroyWindow(hWnd);
            break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        case WM_ACTIVATE:
            // メッセージのアクティベートを shell に通知します。
            SHHandleWMActivate(hWnd, wParam, lParam, &s_sai, FALSE);
            break;

        case WM_SETTINGCHANGE:
            SHHandleWMSettingChange(hWnd, wParam, lParam, &s_sai);
            break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
 

2007-09-02

待ち受け1000時間?

今日、部屋で本を読んでいると Zero3の電池切れの警告音が聞こえました。
 
ところが充電しようとアドエスを手に取ってみると、バッテリはまだまだ残っています。 その他の警告が表示されている様子もありません。
 
おかしいなと思いながら しばらくアドエスを触っていて はっと気づきました。
 
警告音を出したのは机の端に置きっぱなしの esでした。
 
アドエスに変更したときにフル充電して電源を切っていたので約45日間、 esのカタログスペック上の 連続待受時間は500時間ということですから、その倍くらいバッテリが持ったことになります。 W-SIMを抜いているからでしょうか?
 
思えばこの esは ほとんど何のカスタマイズもせずに (カスタマイズしてないのは今も同じですが) メール受信端末としてしか利用していませんでした。
今のようにプログラムを作ろうとしていればもっと楽しめたと思います。
 
久しぶりに触った esはソフトの起動こそ遅いですがキーが大きくて操作しやすいと感じました。 無線LANカードがはみ出さなければ まだまだ遊べる端末なのではないでしょうか。
 
これといった活用法は思い浮かびませんでしたが、 また充電しておきました。
 

2007-09-01

1.01a快調です

「1日1回リセットして下さい」と言われている 1.01aですが、今のところ何の問題もなく動いています。
 
 
どうせなら分かりやすい不具合が発生してくれたほうが状況を楽しめるのですが...。
 
このまま何も無かったらかえって寂しいですよね。