Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他
概要
ingテスト及びmacアドレス・ホスト名・ベンダー名の取得(32/64bit)のGUI版です。
IIPアドレス範囲はダイアログボックスで指定できます。(ディフォルトは192.168.0.0~192.168.0.254)ping実行ボタンをクリックするとpingを実行し、応答があればホスト名及びmacアドレス等をリストビューに表示します。(IPv4専用)
表示内容は、応答があったIPアドレスとtimeはパケット送信から受信までの時間(ミリ秒)、TTLはIPパケットの生存時間、macアドレス、ホスト名、ベンダー名である。
ベンダー名の一覧は、IEEE-SAのホームページの下のほうのDownload a copyより本プログラムが自動的に取得し、macアドレスと一致するベンダーを表示します。
テスト環境
コンパイラ
Visual C++ 2008/2013 Express 32/64bit マルチバイト/UNICODE実行環境
Windows XP Professional Service Pack 3 32bit(Virtual Box上の仮想マシーン)Windows 7 Enterprise Service Pack 1 64bit
プログラムソースの概要
ping1.cpp
WinMain
ダイアログボックスを開きます。DlgProc
WM_INITDIALOG
ダイアログボックスの初期化時に呼び出されます。リストビューのヘッダ及びIPアドレスコントロール等の初期値を設定します。
WM_NOTIFY
メッセージの中からIPアドレスコントロールで値が変化した場合を抽出し、グローバル変数にその値を保存します。WM_COMMAND
各ボタンがクリックされた場合に呼び出されます。IDOK
ping実行ボタンがクリックされた場合に呼び出されます。コントロールからIPアドレスを取得し、スレッドとしてping_thread関数を呼び出します。直接関数を呼び出すとメッセージが回らなくなりキャンセルボタンが有効になりません。
IDCANCEL
キャンセルボタンがクリックされた場合に呼び出されます。クリティカルセッションを使い、ping_run_fをfalseにセットします。
ping関数がこの値をたまにチェックしており、falseの場合、関数を終了します。
IDC_QUIT
終了ボタンをクリックすると呼び出され、EndDialog APIにより本プログラムを終了させます。ListViewHeader
リストビューのヘッダーを初期化します。ping_thread
スレッド作成APIであるCreateThreadより呼び出され、ping関数を呼び出します。ping
指定された範囲のIPについてpingを実行し、結果をリストビューに表示します。ひとつのIPごとにクリティカルセッションを使い、ping_run_fをチェックしflaseがセットされていれば、関数を終了します。
カレントフォルダーにIEEE-SAサイトからダウンロードしたoui.txtファイルがあればこれを開きます。
ファイルがなければインターネットからダウンロードします。
get_mac_vendor関数によりファイルを読み取り、macアドレスとベンダー名の一覧(vendor_vec)を作成します。
IcmpCreateFile APIによりハンドルを作成します。
IPアドレスは、for文の中の配列ipで定義しています。(ビックエンディアンで設定)
IcmpSendEcho APIでpingを実行します。引数で送信するデータサイズやタイムアウトなどを指定できます。ここではマクロBUF_SIZEで32byteのデータサイズ及び2000ミリ秒をタイムアウト値としています。
APIが正常値を返した場合、SendARP APIによりIPアドレスからmacアドレスを取得します。
macアドレスよりmac2vendor_name関数によりベンダー名を取得します。
gethostbyaddr APIによりIPアドレスからホスト名を取得します。このAPI実行にはWINSOCKの初期化が必要であるため、WSAStartup APIをあらかじめ実行しておきます。
なぜかこのAPIはUNICODE版がないので、MultiByteToWideChar APIによりUNICODEに変換します。
for文のループから抜けたら、IcmpCloseHandle APIによりハンドルの開放、WSACleanup APIによりWINSOCKの開放を行います。
get_mac_vendor
ファイルよりmacアドレスとベンダー名の対応を一覧を作成します。一覧はvendor_vecに保存されます。
mac2vendor_name
macアドレスよりベンダー名を取得します。該当するmacアドレスがない場合は文字列errorを返します。ソースコード
guiping.cpp
// 指定した範囲のIPアドレスにPINGを実行し、レスポンスがあればマックアドレスとベンダー名およびホスト名を表示 // 2014/07/21 #include <stdio.h> #include <winsock2.h> #include <ws2tcpip.h> #include <iphlpapi.h> #include <icmpapi.h> #include <wininet.h> #include <locale.h> #include <tchar.h> #include <vector> #include <commctrl.h> #include "resource.h" #pragma comment(lib,"iphlpapi.lib") #pragma comment(lib,"Ws2_32.lib") // gethostbyaddr関数に必要 #pragma comment(lib,"wininet.lib") #pragma comment(lib,"comctl32.lib") #define BUF_SIZE 32 HWND hLabel1=0; struct VENDOR_ID{ unsigned char mac[3]; // macアドレス 上位3byte TCHAR* name; // ベンダー名 void put(FILE* fp){ _ftprintf(fp,_TEXT("%02x:%02x:%02x\t%s\n"),mac[0],mac[1],mac[2],name); } bool cmp(unsigned char* src_mac){ if(mac[0]==src_mac[0] && mac[1]==src_mac[1] && mac[2]==src_mac[2]) return true; else return false; } }; using namespace std; vector<VENDOR_ID> vendor_vec; // macアドレスとベンダー名の一覧 // pingをスレッドで実行 DWORD WINAPI ping_thread(LPVOID lParam); // pingを実行後、macアドレス・ホスト名を取得しリストビューに表示 bool ping(HWND hList,unsigned char* ipa,unsigned char end); // macアドレスよりベンダー名を取得する TCHAR* mac2vendor_name(unsigned char* src_mac); // macアドレスとベンダー名の対応を一覧する void vendor_fput(FILE* fp); // macアドレスとベンダー名の対応を一覧する void vendor_fput(FILE* fp); // ファイルよりmacアドレスとベンダー名の対応を一覧を作成する void get_mac_vendor(FILE* fp); // リストビューのヘッダーを表示 void ListViewHeader(HWND hList); // ダイアログボックスプロシージャー LRESULT CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,LPSTR lpsCmdLine, int nCmdShow){ InitCommonControls(); DialogBox(hCurInst, TEXT("DLG1"), 0, (DLGPROC)DlgProc); return (int)0; } HWND hDlg=0; HWND hList=0; unsigned char ip[4]; unsigned char end; CRITICAL_SECTION cs; bool ping_run_f=false; // ping実行中にfalseをセットするとpingを終了する // pingをスレッドで実行 DWORD WINAPI ping_thread(LPVOID lParam){ ping(hList,ip,end); if(0<ListView_GetItemCount(hList)){ for(int n=0;n<=5;n++){ // リストビューの列幅を自動設定する SendMessage(hList,LVM_SETCOLUMNWIDTH,n,LVSCW_AUTOSIZE_USEHEADER); } } EnableWindow(GetDlgItem(::hDlg,IDOK),TRUE); EnableWindow(GetDlgItem(::hDlg,IDCANCEL),FALSE); return 0; } // ダイアログボックスプロシージャー LRESULT CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){ static HWND hIPA; static HWND hEdit; static DWORD tid; switch (msg) { case WM_INITDIALOG:{ ::hDlg=hDlg; hList=GetDlgItem(hDlg,IDC_LISTVIEW1); hIPA=GetDlgItem(hDlg,IDC_IPADDRE); hEdit=GetDlgItem(hDlg,IDC_EDIT1); hLabel1=GetDlgItem(hDlg,IDC_LABEL1); ListViewHeader(hList); ip[0]=192; ip[1]=168; ip[2]=0; ip[3]=0; LPARAM ipadd=MAKEIPADDRESS(ip[0],ip[1],ip[2],ip[3]); SendMessage(hIPA, IPM_SETADDRESS, 0, ipadd); SetWindowText(hEdit,_TEXT("254")); EnableWindow(GetDlgItem(hDlg,IDCANCEL),FALSE); InitializeCriticalSection(&cs); return TRUE; } case WM_NOTIFY: if( ((LPNMHDR)lParam)->hwndFrom == hIPA){ // IPコントロールの変更を検出する LPNMIPADDRESS lpnmipa=(LPNMIPADDRESS)lParam; switch(lpnmipa->hdr.code){ case IPN_FIELDCHANGED: ip[lpnmipa->iField]=lpnmipa->iValue; return TRUE; default: return FALSE; } } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK:{ // ping実行 EnableWindow(GetDlgItem(hDlg,IDOK),FALSE); EnableWindow(GetDlgItem(hDlg,IDCANCEL),TRUE); TCHAR buf[8]; GetWindowText(hEdit,buf,sizeof(buf)/sizeof(TCHAR)); end=_ttoi(buf); int minv=min(ip[3],end); int maxv=max(ip[3],end); ip[3]=minv; end=maxv; ping_run_f=true; CreateThread(NULL,0,ping_thread,0,0,&tid); // pingをスレッドとして実行 return FALSE; } case IDCANCEL: // pingキャンセル EnterCriticalSection(&cs); ping_run_f=false; LeaveCriticalSection(&cs); return FALSE; case IDC_QUIT: // ダイアログボックス終了 EndDialog(hDlg,TRUE); return TRUE; default: return FALSE; } default: return FALSE; } return TRUE; } // リストビューのヘッダーを表示 void ListViewHeader(HWND hList){ LV_COLUMN lvcol; lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvcol.fmt = LVCFMT_LEFT; lvcol.cx = 100; lvcol.pszText = _TEXT("IP"); lvcol.iSubItem = 0; ListView_InsertColumn(hList, 0, &lvcol); lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM ; lvcol.fmt = LVCFMT_RIGHT; lvcol.cx = 48; lvcol.pszText = _TEXT("Time"); lvcol.iSubItem = 1; ListView_InsertColumn(hList, 1, &lvcol); lvcol.cx = 48; lvcol.fmt = LVCFMT_RIGHT; lvcol.pszText = _TEXT("TTL"); lvcol.iSubItem = 2; ListView_InsertColumn(hList, 2, &lvcol); lvcol.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM ; lvcol.cx = 100; lvcol.pszText = _TEXT("MAC"); lvcol.iSubItem = 3; ListView_InsertColumn(hList, 3, &lvcol); lvcol.cx = 150; lvcol.pszText = _TEXT("Vendor"); lvcol.iSubItem = 4; ListView_InsertColumn(hList, 4, &lvcol); lvcol.cx = 150; lvcol.pszText = _TEXT("Name"); lvcol.iSubItem = 5; ListView_InsertColumn(hList, 5, &lvcol); } // pingを実行後、macアドレス・ホスト名を取得しリストビューに表示 bool ping(HWND hList,unsigned char* ipa,unsigned char end){ TCHAR buf[128]; LV_ITEM item; int num=0; bool f=true; FILE* fp; if(vendor_vec.size()==0){ // ベンダー情報が読み込まれていないのでファイルまたはインターネットから取得 // ファイルが開けない場合、インターネットから取得しファイルに保存後、再度ファイルを開く if(_tfopen_s(&fp,_TEXT("oui.txt"),_TEXT("r"))){ SetWindowText(hLabel1,_TEXT("インターネットからベンダー一覧表を取得します")); if(_tfopen_s(&fp,_TEXT("oui.txt"),_TEXT("wb"))){ return false; } HINTERNET hInet, hUrl; //インターネット(WinInet)開始 hInet = InternetOpen(_TEXT("xyz-123"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if (hInet == NULL) { return false; } //HTTPセッションの開始, 指定のURLオープン hUrl = InternetOpenUrl(hInet, _TEXT("http://standards.ieee.org/develop/regauth/oui/oui.txt"), NULL, 0, 0, 0); if (hUrl == NULL) { InternetCloseHandle(hInet); return false; } char szBuf[1024]; DWORD dwRead = 0; unsigned read_sz=0; //読み出す物がなくなるまで読み出す while (1) { InternetReadFile(hUrl, szBuf, (DWORD)sizeof(szBuf), &dwRead); //読み出す物がなくなったのでループ脱出 if (dwRead == 0) break; EnterCriticalSection(&cs); if(ping_run_f==false){ LeaveCriticalSection(&cs); SetWindowText(hLabel1,_TEXT("インターネットから読み込みがキャンセルされました。")); break; } LeaveCriticalSection(&cs); read_sz+=dwRead; _stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%dbyte読み込みました"),read_sz); SetWindowText(hLabel1,buf); fwrite(szBuf,1,dwRead,fp); } fclose(fp); if(ping_run_f==true){ if(_tfopen_s(&fp,_TEXT("oui.txt"),_TEXT("r"))){ return false; } } //インターネットハンドルの解放 InternetCloseHandle(hUrl); InternetCloseHandle(hInet); EnterCriticalSection(&cs); if(ping_run_f==false){ LeaveCriticalSection(&cs); _stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("pingがキャンセルされました")); SetWindowText(hLabel1,buf); return false; } LeaveCriticalSection(&cs); } get_mac_vendor(fp); fclose(fp); #ifdef _DEBUG if(_tfopen_s(&fp,_TEXT("vendor.txt"),_TEXT("w"))){ return false; } vendor_fput(fp); fclose(fp); #endif } HANDLE hIcmp; IPAddr ipaddr; hIcmp=IcmpCreateFile(); char cbRequest[BUF_SIZE]; // 送信するデータ memset(cbRequest,'a',BUF_SIZE); // 送信するデータを設定 DWORD cbReply=sizeof(ICMP_ECHO_REPLY)+BUF_SIZE; char* pReply=new char[cbReply]; // 受信するヘッダー + 受信するデータ PICMP_ECHO_REPLY p=(PICMP_ECHO_REPLY)pReply; WSADATA wsaData; int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); // WINSOCKを初期化 unsigned char* ip=(unsigned char*)&ipaddr; ip[0]=ipa[0]; ip[1]=ipa[1]; ip[2]=ipa[2]; _tprintf(_TEXT("IPアドレス time TTL マックアドレス ベンダー名\tホスト名\n")); for(unsigned n=ipa[3];n<=end;n++){ // IPアドレスの検索範囲を設定している ip[3]=n; _stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%3i.%3i.%3i.%3i PINGを実行しています。"),ip[0],ip[1],ip[2],ip[3]); SetWindowText(hLabel1,buf); // pingを実行 // IPアドレス 送信データ データーサイズ タイムアウトms DWORD ret=IcmpSendEcho( hIcmp ,ipaddr , cbRequest ,BUF_SIZE , NULL , pReply , cbReply , 2000); if(ret){ // pingが成功した unsigned char mac[6]; struct hostent* hostp; ULONG len=sizeof(mac)/sizeof(unsigned char); if(SendARP(ipaddr,NULL,mac,&len)==NO_ERROR){ // IPアドレスからmacアドレスを取得 hostp=gethostbyaddr((const char*)ip,4,AF_INET); // IPアドレスからホスト名を取得 TCHAR t[64]; if(hostp) #ifdef UNICODE // UNICODEに変換 MultiByteToWideChar(932,0,hostp->h_name,-1,t,sizeof(t)/sizeof(TCHAR)); #else _tcscpy_s(t,sizeof(t)/sizeof(TCHAR),hostp->h_name); #endif else t[0]=_T('\0'); _stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%3i.%3i.%3i.%3i"),ip[0],ip[1],ip[2],ip[3]); item.mask = LVIF_TEXT | LVIF_PARAM; item.pszText =buf; item.iItem = num; item.iSubItem = 0; item.lParam = num; ListView_InsertItem(hList, &item); _stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%i"),p->RoundTripTime); item.mask = LVIF_TEXT; item.pszText =buf; item.iItem = num; item.iSubItem = 1; ListView_SetItem(hList, &item); _stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%i"),p->Options.Ttl); item.mask = LVIF_TEXT; item.pszText =buf; item.iItem = num; item.iSubItem = 2; ListView_SetItem(hList, &item); _stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%02x:%02x:%02x:%02x:%02x:%02x"),mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); item.mask = LVIF_TEXT; item.pszText =buf; item.iItem = num; item.iSubItem = 3; ListView_SetItem(hList, &item); item.mask = LVIF_TEXT; item.pszText =mac2vendor_name(mac); item.iItem = num; item.iSubItem = 4; ListView_SetItem(hList, &item); item.mask = LVIF_TEXT; item.pszText =t; item.iItem = num; item.iSubItem = 5; ListView_SetItem(hList, &item); ++num; } }else{ // pingに失敗した場合 } EnterCriticalSection(&cs); if(ping_run_f==false){ LeaveCriticalSection(&cs); _stprintf_s(buf,sizeof(buf)/sizeof(TCHAR),_TEXT("%3i.%3i.%3i.%3iまでpingを実行しました"),ip[0],ip[1],ip[2],ip[3]); SetWindowText(hLabel1,buf); f=false; break; } LeaveCriticalSection(&cs); } if(f==true) SetWindowText(hLabel1,_TEXT("")); delete [] pReply; IcmpCloseHandle(hIcmp); WSACleanup(); return f; } // macアドレスよりベンダー名を取得する TCHAR* mac2vendor_name(unsigned char* src_mac){ for(unsigned n=0;n<vendor_vec.size();n++){ if(vendor_vec[n].cmp(src_mac)==true) return vendor_vec[n].name; } return _TEXT("error"); } // macアドレスとベンダー名の対応を一覧する void vendor_fput(FILE* fp){ for(unsigned n=0;n<vendor_vec.size();n++){ vendor_vec[n].put(fp); } } // ファイルよりmacアドレスとベンダー名の対応を一覧を作成する void get_mac_vendor(FILE* fp){ TCHAR buf[256]; int f=1; int len; TCHAR* top; TCHAR* p; VENDOR_ID id; while(_fgetts(buf,sizeof(buf)/sizeof(TCHAR),fp)){ top=buf; while(*top){ if(*top!=_T(' ')) break; ++top; } if(f==1){ len=(int)_tcslen(top); if(10<=len){ if(_istxdigit(top[0]) && top[2]==_T('-')){ f=2; } } } switch(f){ case 2:{ TCHAR* name=top; id.mac[0]=(unsigned char)_tcstol(top,NULL,16); id.mac[1]=(unsigned char)_tcstol(top+3,NULL,16); id.mac[2]=(unsigned char)_tcstol(top+6,NULL,16); while(*name){ if(*name==_T(' ')) break; ++name; } while(*name){ if(*name!=_T(' ')) break; ++name; } while(*name){ if(*name==_T(')')) break; ++name; } while(*name){ if(*name!=_T('\t')) break; ++name; } name+=3; p=name; while(*p){ if(*p==_T('\n') || *p==_T('\r') || *p==_T('\t')) *p=_T('\0'); ++p; } id.name=_tcsdup(name); vendor_vec.push_back(id); f=1; break; } } } }
resource.h
#define IDC_IPADDRE 100 // IPアドレス #define IDC_EDIT1 110 // 終了IPアドレス #define IDC_LISTVIEW1 120 // リストビュー #define IDC_LABEL1 130 // ラベル #define IDC_QUIT 140 // 終了
resource.rc
#include <windows.h> #include "resource.h" DLG1 DIALOG DISCARDABLE 0, 0, 494, 230 EXSTYLE WS_EX_DLGMODALFRAME STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_SETFONT CAPTION "guiping" FONT 9, "MS 明朝" { CONTROL "IPアドレス範囲", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 7, 14 , 80 , 14 CONTROL "IPAddress1", IDC_IPADDRE, "SysIPAddress32", WS_CHILD | WS_VISIBLE | SS_SUNKEN | SS_NOTIFY, 7, 28, 96, 14 CONTROL "~", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 110, 32 , 8 , 14 CONTROL "", IDC_EDIT1, "EDIT", WS_CHILD | WS_DLGFRAME | WS_VISIBLE | ES_AUTOHSCROLL, 130, 28, 32, 14 CONTROL "応答のあったIPアドレス", -1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 7, 49 , 160 , 14 CONTROL "ListView100", IDC_LISTVIEW1, "SYSLISTVIEW32", WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT, 7, 63, 480, 100 CONTROL "", IDC_LABEL1, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 7, 170 , 450 , 14 CONTROL "ping実行", IDOK, "BUTTON", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 143, 198, 60, 18 CONTROL "キャンセル", IDCANCEL, "BUTTON", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 217, 198, 60, 18 CONTROL "終了", IDC_QUIT, "BUTTON", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 291, 198, 60, 18 }
Copyright (C) 2012 山本ワールド All Rights Reserved.