概要

指定されたIPアドレス範囲に対してpingを実行し、応答があればホスト名及びmacアドレス等をリストビューに表示します。(IPv4専用)
表示内容は、応答があったIPアドレスとtimeはパケット送信から受信までの時間(ミリ秒)、TTLはIPパケットの生存時間、macアドレス、ホスト名、ベンダー名である。
ベンダー名の一覧は、IEEE-SAのホームページのhttp://standards-oui.ieee.org/oui.txtより本プログラムが自動的に取得し、macアドレスと一致するベンダーを表示します。
1回取得できればファイルoui.txtに保存されます。次回は、インターネットから取得せずにファイルの一覧表を基にベンダー名を表示します。
IPアドレスは自身のPCのIPアドレスとサブネットマスクによって範囲の初期値が設定されます。
pingは16スレッドを同時に処理しますので高速に動作します。

IPアドレスの指定

IPアドレスの検索方法には次の2種類の方法があります。

IPアドレス範囲で指定


ラジオボタンで範囲で検索が選択されている場合、この方法が選択されます。
このPCのIPアドレスを選択するとこのPCのIPアドレスとサブネットマスクによってIPアドレス範囲が自動的にIPアドレス範囲に反映されます。IPアドレスの検索範囲は第4オクテットのみです。ユーザー自身が範囲を変更することができます。
上図の場合、IPアドレス192.168.0.0~192.168.0.10が検索対象となります。

サブネットマスクで検索


ラジオボタンでサブネットマスクで検索が選択されている場合、この方法が選択されます。
このPCのIPアドレスを選択するとこのPCのIPアドレスとサブネットマスクによってIPアドレス範囲が自動的に変更されます。IPアドレスの検索範囲は、このIPアドレスとサブネットマスクにより自動的に算出されます。IPアドレスは第1~第4オクテットにわたって有効です。ダイアログボックスのIPアドレスの範囲とサブネットマスクに指定された値は無視されます。
上図の場合、ブロードキャストアドレス192.168.0.255を除いた、IPアドレス192.168.0.0~192.168.0.254が検索対象となります。

上図の場合、ブロードキャストアドレス192.168.255.255を除いた、IPアドレス192.168.0.0~192.168.255.255が検索対象となります。

バッファサイズ

ディフォルトではWindowsのpingコマンドと同じ32byteに設定しています。

タイムアウト

ディフォルト値は2000msとしています。255個のアドレス範囲で自分自身以外に機器がない場合、254個が応答なしとなります。16スレッドなので、 最低、254個/16スレッド*2000ms=32秒実行時間がかかることとなります。LAN内で2000msの応答時間がかかることはないので、総当たりで検索する場合は、タイムアウト値は小さな値を指定すべきです。

ping実行ボタン

設定されたIPアドレスの範囲にたいして16スレッドでpingを実行します。キャンセルボタンによりpingを中止することができます。

キャンセル

実行中のpingを中止します。

保存

リストビューに表示されている内容をテキストファイル(TAB区切り形式)で保存します。

終了

本プログラムを終了します。

テスト環境

コンパイラ

Visual C++ 2008/2013 Express 32/64bit マルチバイト/UNICODE

実行環境

Windows XP Professional Service Pack 3 32bit(Virtual Box上の仮想マシーン)
Windows 7 Enterprise Service Pack 1 64bit

プログラムソースの概要

ping2.cpp

WinMain

WINSOCKの初期化が必要であるため、WSAStartup APIを呼び出します。
ダイアログボックスを開きます。
WSACleanup APIによりWINSOCKの開放を行います。

DlgProc

WM_INITDIALOG
ダイアログボックスの初期化時に呼び出されます。
get_my_ip関数により自身のPCのIPアドレスとサブネットマスクを取得します。複数のLANカードにも対応しています。
リストビューのヘッダ及びIPアドレスコントロール等の初期値を設定します。
WM_NOTIFY
メッセージの中からIPアドレスコントロールで値が変化した場合を抽出し、グローバル変数にその値を保存します。
WM_COMMAND
各ボタンがクリックされた場合およびコンボボックスやエディットボックスの内容が変更された場合に呼び出されます。
wParamの下位ワード(16bit)にコントロールのID、wParamの上位ワードにメッセージが格納されています。
コントロールのID別に処理をswitchステートメントで記述しています。
IDC_END_ADR_EDIT
IPアドレス範囲のうち終わりを設定するエディットボックスからのメッセージがある場合に呼び出されます。
エディットボックスの内容に変化があった場合EN_UPDATEメッセージが送られるので、エディットボックスの値を取得し、検索するIPアドレスの個数を変更します。
IDC_COMBOBOX
このPCのIPアドレスコンボボックスのメッセージがある場合に呼び出されます。
コンボボックスの選択されているアイテムに変化があった場合CBN_SELCHANGEメッセージが送られるので、選択されているIPアドレスとサブネットマスク値を取得し、検索するIPアドレスの個数を変更します。
また、選択されているIPアドレスとサブネットマスクを基にIPアドレス範囲とサブネットマスクの表示する値を変更します。
IDOK
ping実行ボタンがクリックされた場合に呼び出されます。
直接関数を呼び出すとメッセージが回らなくなりキャンセルボタンが有効にならずしかも応答なし状態となるのでスレッドとしてping_thread関数を呼び出します。
IDC_SAVE
保存ボタンが押された時呼び出されます。
GetFileName関数を呼び出し保存するファイル名を取得します。
ListViewPut関数を呼び出しリストビューの内容を呼び出しテキスト形式(TAB区切り)で保存します。
IDC_ERASE
クリアボタンが押された時呼び出されます。
リストビューにLVM_DELETEALLITEMSメッセージを送信しリストビューのアイテムを全部クリアします。
IDCANCEL
キャンセルボタンがクリックされた場合に呼び出されます。
クリティカルセッションを使い、ping_run_fをfalseにセットします。
ping関数がこの値をたまにチェックしており、falseの場合、関数を終了します。
IDC_QUIT
終了ボタンをクリックすると呼び出され、EndDialog APIにより本プログラムを終了させます。

mask_max

指定されたIPアドレスとサブネットマスク値よりとりうるIPアドレスの最大個数(ブロードキャストアドレスを除く)を計算し返します。

ip_range_set

IPアドレスの開始値と終了値よりとりうるIPアドレスの最大個数を計算し返します。

ip_mask_set

指定されたIPアドレスとサブネットマスク値を基にアドレス範囲の初期値を設定します。

ListViewHeader

リストビューのヘッダーを初期化します。

get_mac_url

カレントフォルダーにmacアドレスとベンダー名の一覧を示すファイルoui.txtがあれば、ファイルを読み込みmacアドレスとベンダー名の一覧を作成します。
ファイルがない場合、メッセージボックスを表示、インターネットからの読み込みが選択された場合、インターネットからの読み取りを実行しファイルに保存します。
インターネットからの読み取り
ファイルからの読み取り
get_mac_vendor関数を呼び出しファイルを読み取り、macアドレスとベンダー名の一覧(vendor_vec)を作成します。

ping_thread

スレッド作成APIであるCreateThreadより呼び出され、ping関数を呼び出します。

ping

指定された範囲のIPについてpingを実行し、結果をリストビューに表示します。
スレッドを管理するTHREAD_MANクラスを16スレッド、スレッド関数ping_rootを指定して初期化します。
macアドレスとベンダー名の一覧(vendor_vec)が作成されていない場合は、get_mac_url関数を呼び出して作成します。
スレッド分のpingで使用するバッファをnew演算子で作成します。
IcmpCreateFile APIによりスレッド数分のハンドルを作成します。
スレッド分の送信するデータを初期化します。
IP範囲の指定方法をラジオボタンのチェック状態から取得します。
範囲の検索が指定されている場合は、第4オクテットをfor分で変化させます。
サブネットマスクで検索が指定されている場合は、各オクテットのipの組み合わせが保存されている配列ip1,ip2,ip3,ip4を検索してIPアドレスを変化させます。
各IPアドレスに対して以下の処理を行います。
SetWindowText APIにより現在のIPアドレスを表示します。
スレッドを管理するTHREAD_MANクラスのdispatchメソッドにより待機中のスレッドを検索し、スレッドにIPアドレスを指定して、pingを実行します。
ping_run_fをチェックしflaseがセットされていれば、検索を終了します。
検索が終了したら、スレッドを管理するTHREAD_MANクラスのall_killメソッドにより全スレッド関数ping_rootを終了させます。
IcmpCloseHandle APIによりスレッド数分のハンドルを解放します。
new演算子で作成したpingで使用したバッファをdelete []演算子で解放します。

mac2vendor_name

指定されたmacアドレスをvendor_vec配列から検索し一致したものがあればベンダー名を返します。

vendor_fput

macアドレスとベンダー名の対応の配列をファイルに保存します。

get_mac_vendor

ファイルを読み取りmacアドレスとベンダー名の対応を一覧を作成する

ListViewPut

リストビューをTAB形式でファイルへ保存する

GetFileName

ファイル名を指定するコモンダイアログを表示

error_msg

エラーコードに対応するメッセージを出力する

set_ip

マスク値から取りうるIPアドレスの一覧を作成する(1byte)

get_my_ip

自身のIPアドレスを取得

run_thread

THREAD_MANから起動されるスレッドです。
ping_run_fがflaseの場合は、スレッドの終了させます。
スレッドに割り付けられているイベントrun_evenメンバーをチェックしシグナル状態になるまで待機しシグナルになった時、IPアドレスがセットされているので、ユーザー定義関数(ping_root)を実行します。
イベントのチェックがタイムアウトした場合は、50ms待機し再度イベントのチェックを行います。
ユーザー定義関数(ping_root)が終了した場合は、非シグナル状態に設定します。

THREAD_MANクラス

init

スレッドごとに割り付けるイベント(run_eventメンバー)を非シグナル状態で作成します。このイベントは各スレッドがping実行中の場合シグナル、待機中の場合は非シグナルとなります。
指定されたスレッド数のrun_threadスレッドを作成します。

clear

スレッド用の変数を解放します。

all_kill

スレッドの終了を待ちます。

dispatch

イベントをチェックし待機スレッドを検索しそのスレッドにIPアドレスを設定しイベントをシグナルに設定し、スレッドを待機状態から実行状態に移行させます。

ソースコード

guiping2.cpp

//	指定した範囲のIPアドレスに同時に最大16個同時にPINGを実行し、レスポンスがあればマックアドレスとベンダー名およびホスト名を表示
//	2015/08/25

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <icmpapi.h>
#include <wininet.h>
#include <tchar.h>
#include <vector>
#include <commctrl.h>
#include "resource.h"

#pragma comment(lib,"iphlpapi.lib")
#pragma comment(lib,"Ws2_32.lib")
#pragma comment(lib,"wininet.lib")
#pragma comment(lib,"comctl32.lib")

#define OUT_TXT_URL _TEXT("http://standards-oui.ieee.org/oui.txt")

int BUF_SIZE = 32;	//	pingのバッファサイズ
int TIMEOUT = 2000;	//	タイムアウト値(ms)

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;
	}
};

//	IPアドレスとサブネットマスク値

struct IP_ADS_MASK{
	DWORD32 ip;
	DWORD32 mask;
};

using namespace std;

vector<VENDOR_ID> vendor_vec;	//	macアドレスとベンダー名の一覧
vector<IP_ADS_MASK> my_ip_ads_mask;	//	このPCのアドレスとサブネットマスク
int my_ip_sel = 0;	//	コンボボックスで選択されている my_ip_ads_maskの要素
HWND hDlg = 0;
HWND hList = 0;
HWND hLabel1 = 0;
unsigned char ip[4];
unsigned char ends;
CRITICAL_SECTION cs;	//	ping_run_fの読書用のクリティカルセッション
CRITICAL_SECTION listview_cs;	//	リストビューの行数の操作用のクリティカルセッション

bool ping_run_f = false;	//	ping実行中にfalseをセットするとpingを終了する

int listview_max = 0;	//	リストビューの行数

//	マスク値でpingを実行する場合の各バイトの組み合わせ表
BYTE ip1[256];
BYTE ip2[256];
BYTE ip3[256];
BYTE ip4[256];
int	ip1_max;
int ip2_max;
int ip3_max;
int ip4_max;


//	自身のIPアドレスを取得
BOOL get_my_ip(void);

//	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);

//	リストビューをTAB形式でファイルへ保存する
void ListViewPut(HWND hList, FILE* fp);

// ファイル名を指定するコモンダイアログを表示
BOOL GetFileName(HWND hWnd, TCHAR* fname, int sz);

//	マスク値から取りうるIPアドレスの一覧を作成する(1byte)
int set_ip(DWORD x, BYTE* ip);

//	マスク値から取りうるIPアドレス(IPv4)の個数を返す

DWORD mask_max(DWORD32 ipads, DWORD32 maskv);

//	IPアドレスのマスク値より必要な情報をセット

void ip_mask_set(void);

//	IPアドレスと終了アドレスより必要な情報をセット

void ip_range_set(void);

//	エラーコードに対応するメッセージを出力する
void error_msg(HWND hWnd);

//	スレッドの管理

//	ユーザー定義関数
typedef DWORD (* THREAD_MAN_FUNC)(LPVOID lParam,int num);

struct THREAD_MAN_CREATE{
	LPVOID thread_man;
	int num;
};

//	登録した関数をマルチスレッドで実行するクラス

struct THREAD_MAN{
	HANDLE* run_event;	//	イベントオブジェクト シグナル時はスレッドが実行中
	HANDLE* thread;		//	スレッドハンドル
	LPVOID* data;	//	ユーザースレッドに渡すデータ
	THREAD_MAN_FUNC func;	//	ユーザー定義関数
	int thread_max;	//	スレッド数
	THREAD_MAN_CREATE* tmcp;	//	各スレッドの初期値
	friend DWORD WINAPI run_thread(LPVOID lParam);	//	起動されるスレッド

	THREAD_MAN(){
		thread_max = 0;
	}
		
	void init(int max, THREAD_MAN_FUNC def_func){	//	スレッドの起動
		func = def_func;
		thread_max = max;
		run_event = new HANDLE[thread_max];
		thread = new HANDLE[thread_max];
		data = new LPVOID[thread_max];
		tmcp = new THREAD_MAN_CREATE[thread_max];

		for (int n = 0; n < thread_max; n++){
			run_event[n] = CreateEvent(NULL, TRUE, FALSE, NULL);//	非シグナル状態で初期化
			tmcp[n].thread_man = (LPVOID)this;
			tmcp[n].num = n;
			thread[n] = CreateThread(NULL, 0, run_thread, &tmcp[n], 0, NULL);	//	run_threadをスレッドとして起動
		}
	}
	void clear(void){	//	スレッド用の変数の解放
		delete[] tmcp;
		delete[] data;
		delete[] thread;
		delete[] run_event;
	}
	void all_kill(void){	//	スレッドの終了を待つ
		WaitForMultipleObjects(thread_max, thread, TRUE, INFINITE); //全スレッドの終了を待つ
		for (int n = 0; n < thread_max; n++){
			thread[n] = NULL;
		}
	}
	void dispatch(LPVOID lParam){	//	待機スレッドに処理を発行
		DWORD ret;
		int n;
		do{
			Sleep(100);
			ret = WaitForMultipleObjects(thread_max, run_event, TRUE, 0);	// 全イベントがシグナル状態であるか取得
		} while (WAIT_OBJECT_0 <= ret && ret < WAIT_OBJECT_0 + thread_max);	//	全イベントがシグナル状態なので待機
		for (n = 0; n < thread_max; n++){
			ret = WaitForSingleObject(run_event[n], 0);	// 全イベントがシグナル状態であるか取得
			if (ret != WAIT_OBJECT_0)	//	非シグナル
				break;
		}
		data[n] = lParam;
		SetEvent(run_event[n]);	//	シグナル状態に設定
	}
};

THREAD_MAN thread_man;

int WINAPI _tWinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,TCHAR* lpsCmdLine, int nCmdShow){
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);	//	WINSOCKを初期化

	DialogBox(hCurInst, TEXT("DLG1"), 0, (DLGPROC)DlgProc);

	WSACleanup();
	return (int)0;
}


//	ダイアログボックスプロシージャー

LRESULT CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
	static HWND hIPA;
	static HWND hEdit;
	static DWORD tid;
	TCHAR buf[64];

	switch (msg) {
		case WM_INITDIALOG:{
			::hDlg=hDlg;
			hList=GetDlgItem(hDlg,IDC_LISTVIEW1);
			hIPA=GetDlgItem(hDlg,IDC_IPADDRE);
			hEdit=GetDlgItem(hDlg,IDC_END_ADR_EDIT);
			hLabel1=GetDlgItem(hDlg,IDC_LABEL1);

			ip4_max = 0;
			ListViewHeader(hList);
			SetWindowText(hEdit,_TEXT("254"));
			if(get_my_ip()==TRUE){	//	このPCのIPアドレスおよびサブネットマスク値を得る
				for (DWORD n = 0; n < my_ip_ads_mask.size(); n++){
					char ansi[16];
					inet_ntop(AF_INET, (void*)&::my_ip_ads_mask[n].ip, ansi, sizeof(ansi));
					SendMessageA(GetDlgItem(hDlg, IDC_COMBOBOX), CB_INSERTSTRING, n,(LPARAM) ansi);	//コンボボックスにアイテムの設定
				}
				SendMessage(GetDlgItem(hDlg, IDC_COMBOBOX), CB_SETCURSEL, ::my_ip_sel, (LPARAM)0);	//	初期時に選択されるアイテムを選択
				*(DWORD*)ip = ::my_ip_ads_mask[::my_ip_sel].ip & ::my_ip_ads_mask[::my_ip_sel].mask;
				ip_mask_set();
				ip_range_set();
			}else{
				MessageBox(hDlg, _TEXT("このPCのIPアドレスが検出できませんでした"), _TEXT("エラー"), MB_OK);
				EndDialog(hDlg, TRUE);
				return TRUE;
			}
			LPARAM ipadd = MAKEIPADDRESS(ip[0], ip[1], ip[2], ip[3]);
			SendMessage(hIPA, IPM_SETADDRESS, 0, ipadd);
			EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
			SendMessage(GetDlgItem(hDlg, IDC_RADIOBOX101), BM_SETCHECK, BST_CHECKED, 0);
			_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%d"), BUF_SIZE);
			SetWindowText(GetDlgItem(hDlg,IDC_BUFSIZE), buf);
			_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%d"),TIMEOUT);
			SetWindowText(GetDlgItem(hDlg, IDC_TIMEOUT), buf);

			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;
					ip_range_set();
					return TRUE;
				}
				default:
					return FALSE;
				}
			}
			break;
        case WM_COMMAND:
            switch (LOWORD(wParam)) {
				case IDC_END_ADR_EDIT:{
					if (HIWORD(wParam) == EN_UPDATE){
						GetWindowText(hEdit, buf, sizeof(buf) / sizeof(TCHAR));
						::ends = _ttoi(buf);
						ip_range_set();
					}
					break;
				}
				case IDC_COMBOBOX:{
					if (HIWORD(wParam) == CBN_SELCHANGE){	//	コンボボックスのアイテムが選択されたときに呼び出される
						::my_ip_sel = (int)SendMessage(GetDlgItem(hDlg, IDC_COMBOBOX), CB_GETCURSEL, 0, 0);	//	カーソル位置のアイテムを取得
						ip_mask_set();
						*(DWORD*)ip = ::my_ip_ads_mask[::my_ip_sel].ip & ::my_ip_ads_mask[::my_ip_sel].mask;
						LPARAM ipadd = MAKEIPADDRESS(ip[0], ip[1], ip[2], ip[3]);
						SendMessage(hIPA, IPM_SETADDRESS, 0, ipadd);
						ip_range_set();
					}
					break;
				} 
				case IDOK:{	//	ping実行
					EnableWindow(GetDlgItem(hDlg,IDOK),FALSE);
					EnableWindow(GetDlgItem(hDlg, IDC_SAVE), FALSE);
					EnableWindow(GetDlgItem(hDlg, IDC_ERASE), FALSE);
					EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE);
					TCHAR buf[8];
					GetWindowText(hEdit,buf,sizeof(buf)/sizeof(TCHAR));
					ends=_ttoi(buf);
					int minv=min(ip[3],ends);
					int maxv=max(ip[3],ends);
					ip[3]=minv;
					ends=maxv;

					GetWindowText(GetDlgItem(hDlg,IDC_BUFSIZE), buf, sizeof(buf) / sizeof(TCHAR));
					BUF_SIZE = _ttoi(buf);
					if (BUF_SIZE < 32 || 65536 < BUF_SIZE){
						MessageBox(hDlg, _TEXT("バッファイサイズは32~65536の間でなければなりません。"), _TEXT("エラー"), MB_OK);
						EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
						EnableWindow(GetDlgItem(hDlg, IDC_SAVE), TRUE);
						EnableWindow(GetDlgItem(hDlg, IDC_ERASE), TRUE);
						EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
						return FALSE;
					}

					GetWindowText(GetDlgItem(hDlg, IDC_TIMEOUT), buf, sizeof(buf) / sizeof(TCHAR));
					TIMEOUT = _ttoi(buf);

					ping_run_f = true;
					CreateThread(NULL,0,ping_thread,0,0,&tid);	//	pingをスレッドとして実行
					return FALSE;
				}
				case IDC_SAVE:{	//	リストビューの内容をテキストファイルに保存
					FILE* fp;
					TCHAR buf[MAX_PATH];
					if (GetFileName(hDlg, buf, sizeof(buf) / sizeof(TCHAR)) == TRUE){
						if (_tfopen_s(&fp, buf, _TEXT("w")) == 0){
							ListViewPut(hList, fp);
							fclose(fp);
						}
					}
					return TRUE;
				}
				case IDC_ERASE:{	//	リストビュー全消去
					SendMessage(hList,LVM_DELETEALLITEMS,0,0);
					return TRUE;
				}
				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;
}

//	マスク値から取りうるIPアドレス(IPv4)の個数を返す

DWORD mask_max(DWORD32 ipads, DWORD32 maskv){
	BYTE* my_ip = (BYTE*)&ipads;
	BYTE* mask = (BYTE*)&maskv;

	ip1_max = set_ip(mask[0], ip1);
	ip2_max = set_ip(mask[1], ip2);
	ip3_max = set_ip(mask[2], ip3);
	ip4_max = set_ip(mask[3], ip4); 
	if (ip1_max == 0){
		ip1[0] = my_ip[0];
		ip1_max = 1;
	}
	if (ip2_max == 0){
		ip2[0] = my_ip[1];
		ip2_max = 1;
	}
	if (ip3_max == 0){
		ip3[0] = my_ip[2];
		ip3_max = 1;
	}
	if (ip4_max == 0){
		ip4[0] = 0;
		ip4_max = 1;
	}
	return ip1_max*ip2_max*ip3_max*ip4_max - 1;
}

//	IPアドレスと終了アドレスより必要な情報をセット

void ip_range_set(void){
	TCHAR buf[16];
	GetWindowText(GetDlgItem(::hDlg, IDC_END_ADR_EDIT), buf, sizeof(buf) / sizeof(TCHAR));
	::ends = _ttoi(buf);
	int minv = min(::ip[3], ::ends);
	int maxv = max(::ip[3], ::ends);

	_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%d個"), maxv - minv + 1);
	SetWindowText(GetDlgItem(::hDlg, IDC_RENGE_LABEL), buf);
}

//	IPアドレスのマスク値より必要な情報をセット

void ip_mask_set(void){
	TCHAR buf[16];
	char ansi[16];
	DWORD ipmax = mask_max(::my_ip_ads_mask[::my_ip_sel].ip, ::my_ip_ads_mask[::my_ip_sel].mask);
	inet_ntop(AF_INET, (void*)&::my_ip_ads_mask[::my_ip_sel].mask, ansi, sizeof(ansi));
	SetWindowTextA(GetDlgItem(::hDlg, IDC_MY_MASK_EDIT), ansi);
	_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%d個"), ipmax);
	SetWindowText(GetDlgItem(::hDlg, IDC_MY_MASK_LABEL), buf);

	if (0 < ip4_max){
		_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%d"), ip4[ip4_max - 1] - 1);
		SetWindowText(GetDlgItem(::hDlg, IDC_END_ADR_EDIT), buf);
	}
}

//	リストビューのヘッダーを表示

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);
}

//	ベンダーの一覧をファイル又はwebから取得しファイルに保存する

bool get_mac_url(void){
	TCHAR buf[128];
	int num = 0;
	bool f = true;
	FILE* fp;
	if (_tfopen_s(&fp, _TEXT("oui.txt"), _TEXT("r"))){
		if (MessageBox(hDlg, _TEXT("ベンダー一覧をインターネットから取得しますか"), _TEXT("選択"), MB_YESNO) == IDNO){
			return false;
		}else{
			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, OUT_TXT_URL, 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);
				fclose(fp);
				return false;
			}
			LeaveCriticalSection(&cs);
		}
	}
	get_mac_vendor(fp);
	fclose(fp);
	return true;
}

//	指定アドレスにpingを実行し応答があればリストビューに表示

BOOL ping_sub(HANDLE hIcmp, IPAddr ipaddr, char* cbRequest,  char*  pReply,DWORD cbReply,DWORD timeout){
	TCHAR buf[128];
	LV_ITEM item;
	int num;
	unsigned char* ip = (unsigned char*)&ipaddr;

	PICMP_ECHO_REPLY p = (PICMP_ECHO_REPLY)pReply;

	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アドレスを取得

#pragma warning(push)

	/* Visual C++ 2013 コンパイル時のエラー抑制
	  error C4996 : 'gethostbyaddr' : Use getnameinfo() or GetNameInfoW() instead or define _WINSOCK_DEPRECATED_NO_WARNINGS to disable deprecated API warnings
	*/
	#pragma warning(disable:4996)
			hostp = gethostbyaddr((const char*)ip, 4, AF_INET);	//	IPアドレスからホスト名を取得

#pragma warning(pop)

			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]);

			EnterCriticalSection(&listview_cs);

			num = listview_max++;

			LeaveCriticalSection(&listview_cs);

			item.mask = LVIF_TEXT | LVIF_PARAM;
			item.pszText = buf;
			item.iItem = num;
			item.iSubItem = 0;
			item.lParam = ipaddr;
			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);

			return TRUE;
		}else
			return FALSE;
	}else{	//	pingに失敗した場合
		return FALSE;
	}
}


HANDLE* hIcmp;
char** cbRequest;
char** pReply;
DWORD cbReply;

//	THREAD_MANに登録する関数  IPアドレスを受け取り、ping_subを呼び出す

DWORD ping_root(LPVOID lParam, int num){
	IPAddr ipaddr=(IPAddr)lParam;
	char* ip = (char*)&lParam;
	ping_sub(hIcmp[num], ipaddr, cbRequest[num], pReply[num], cbReply, TIMEOUT);
	return 0;
}


//	指定した範囲ぶpingを実行後、macアドレス・ホスト名を取得しリストビューに表示

bool ping(HWND hList,unsigned char* ipa,unsigned char end){
	int thread_max = 16;
	thread_man.init( thread_max , ping_root);
	TCHAR buf[128];
	int n;
	bool f=true;

	if(vendor_vec.size()==0){	//	ベンダー情報が読み込まれていないのでファイルまたはインターネットから取得
		//	ファイルが開けない場合、インターネットから取得しファイルに保存後、再度ファイルを開く
		get_mac_url();	//	MACアドレスの一覧をwebから取得しファイルに保存する
	}
	cbReply = sizeof(ICMP_ECHO_REPLY) + BUF_SIZE;
	IPAddr ipaddr;

	listview_max = (int)SendMessage(hList, LVM_GETITEMCOUNT, 0, 0);

	hIcmp = new HANDLE[thread_max];
	cbRequest=new LPSTR[thread_max];
	pReply = new LPSTR[thread_max];

	for (n = 0; n < thread_man.thread_max; n++){
		hIcmp[n] = IcmpCreateFile();
		cbRequest[n]=new char[BUF_SIZE];	//	送信するデータ
		memset(cbRequest[n], 'a', BUF_SIZE);	//	送信するデータを設定
		pReply[n] = new char[cbReply];	//	受信するヘッダー + 受信するデータ
	}
	unsigned char* ip=(unsigned char*)&ipaddr;
	ip[0]=ipa[0];
	ip[1]=ipa[1];
	ip[2]=ipa[2];

	InitializeCriticalSection(&listview_cs);

	if (SendMessage(GetDlgItem(hDlg, IDC_RADIOBOX101), BM_GETCHECK, 0, 0) == BST_CHECKED){
		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);
			thread_man.dispatch((LPVOID)ipaddr);
			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);
		}
	}else{
		::my_ip_ads_mask[::my_ip_sel].ip;
		BYTE* mask = (BYTE*)&::my_ip_ads_mask[::my_ip_sel].mask;
		BYTE* my_ip = (BYTE*)&::my_ip_ads_mask[::my_ip_sel].ip;

		int ip1_v = 0;
		int ip2_v;
		int ip3_v;
		int ip4_v;
		while (ip1_v < ip1_max){
			ip2_v = 0;
			while (ip2_v < ip2_max){
				ip3_v = 0;
				while (ip3_v < ip3_max){
					ip4_v = 0;
					while (ip4_v < ip4_max){
						if (ip1_v == ip1_max - 1 && ip2_v == ip2_max - 1 && ip3_v == ip3_max - 1 && ip4_v == ip4_max - 1){
							//	ブロードキャストアドレスなので終了させる
							break;
						}
						else{
							ip[0] = ip1[ip1_v];
							ip[1] = ip2[ip2_v];
							ip[2] = ip3[ip3_v];
							ip[3] = ip4[ip4_v];

							_stprintf_s(buf, sizeof(buf) / sizeof(TCHAR), _TEXT("%3i.%3i.%3i.%3i PINGを実行しています。"), ip[0], ip[1], ip[2], ip[3]);
							SetWindowText(hLabel1, buf);
							thread_man.dispatch((LPVOID)ipaddr);
							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);
							ip4_v++;

						}

					}
					ip3_v++;
				}
				ip2_v++;
			}
			ip1_v++;
		}

	}
	if(f==true)
		SetWindowText(hLabel1,_TEXT(""));

	ping_run_f = false;	//	スレッドの終了を要求
	thread_man.all_kill();
	thread_man.clear();
	DeleteCriticalSection(&listview_cs);

	for (n = 0; n < thread_man.thread_max; n++){
		IcmpCloseHandle(hIcmp[n]);
		delete[] cbRequest[n];	//	送信するデータ
		delete[] pReply[n];	//	受信するヘッダー + 受信するデータ
	}
	delete[] cbRequest;
	delete[] pReply;
	delete[] hIcmp;

	cbRequest=0;
	pReply=0;
	hIcmp=0;
	ping_run_f = true;
	return f;
}

//	pingをスレッドで実行

DWORD WINAPI  ping_thread(LPVOID lParam){
	ping(hList, ip, ends);
	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);
	EnableWindow(GetDlgItem(hDlg, IDC_SAVE), TRUE);
	EnableWindow(GetDlgItem(hDlg, IDC_ERASE), TRUE);
	return 0;
}


//	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;
	}
	if (vendor_vec.size())
		return _TEXT("error");
	else
		return _TEXT("");
}

//	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;
			}
		}
	}
}

//	リストビューをTAB形式でファイルへ保存する

void ListViewPut(HWND hList, FILE* fp){
	HWND hHeader;
	TCHAR buf[256];
	int rmax = (int)SendMessage(hList, LVM_GETITEMCOUNT, 0, 0);
	hHeader = ListView_GetHeader(hList);
	int cmax = (int)SendMessage(hHeader, HDM_GETITEMCOUNT, 0, 0);
	HDITEM hdi;
	ZeroMemory(&hdi, sizeof(hdi));
	hdi.mask = HDI_TEXT;
	hdi.pszText = buf;
	hdi.cchTextMax = sizeof(buf) / sizeof(TCHAR);
	int c, r;
	for (c = 0; c < cmax; c++){
		SendMessage(hHeader, HDM_GETITEM, c, (LPARAM)&hdi);
		_ftprintf(fp, _TEXT("%s"), buf);
		if (c != cmax - 1)
			_fputtc(_T('\t'), fp);
	}
	_fputtc(_T('\n'), fp);
	for (r = 0; r < rmax; r++){
		for (c = 0; c < cmax; c++){
			ListView_GetItemText(hList, r, c, buf, sizeof(buf) / sizeof(TCHAR));
			_ftprintf(fp, _TEXT("%s"), buf);
			if (c != cmax - 1)
				_fputtc(_T('\t'), fp);
		}
		_fputtc(_T('\n'), fp);
	}
}

// ファイル名を指定するコモンダイアログを表示

BOOL GetFileName(HWND hWnd, TCHAR* fname, int sz){
	OPENFILENAME o;
	fname[0] = _T('\0');
	ZeroMemory(&o, sizeof(o));
	o.lStructSize = sizeof(o);
	o.hwndOwner = hWnd;
	o.Flags = 0;
	o.lpstrFile = fname;
	o.nMaxFile = sz;
	o.lpstrFilter = _TEXT("TXT files(*.TXT)\0\0");
	o.lpstrDefExt = _TEXT("TXT");
	o.lpstrTitle = _TEXT("テキストファイルを指定");
	o.nFilterIndex = 1;
	return GetSaveFileName(&o);
}

//	エラーコードに対応するメッセージを出力する

void error_msg(HWND hWnd){
	LPVOID lpMsgBuf;

	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // 既定の言語
		(TCHAR*)&lpMsgBuf,
		0,
		NULL
		);

	MessageBox(hWnd, (TCHAR*)lpMsgBuf, _TEXT("エラー"), MB_OK);

	// バッファを解放する。
	LocalFree(lpMsgBuf);
}

//	マスク値から取りうるIPアドレスの一覧を作成する(1byte)

int set_ip(DWORD x, BYTE* ip){
	DWORD base = 1;
	DWORD bit[8];
	DWORD i = 0, u, n;
	for (n = 0; n<8; n++){
		if ((x & base) == 0){	//	マスクされていないビット
			bit[i++] = base;
		}
		base = base * 2;
	}	//	iに有効なビット数が取得される
	if (i == 0)
		return 0;
	base = 1;
	for (u = 0; u<i; u++)
		base = base * 2;
	int y;
	for (u = 0; u<base; u++){
		y = 0;
		for (n = 0; n<i; n++){
			y += (u & (1 << n)) ? bit[n] : 0;
		}
		ip[u] = y;
	}
	return base;
}

//	自身のIPアドレスを取得

BOOL get_my_ip(void){
	PMIB_IPADDRTABLE pTable = 0;
	DWORD dwSize = 0;
	// GetIpAddrTable()で使用するバッファサイズを取得 
	if (GetIpAddrTable(NULL, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
		pTable = (MIB_IPADDRTABLE *) new BYTE[dwSize];
	}
	else{
		error_msg(hDlg);
		return FALSE;
	}
	if (GetIpAddrTable(pTable, &dwSize, 0) == NO_ERROR) {
		if (0 < pTable->dwNumEntries) {
			for (DWORD i = 0; i < pTable->dwNumEntries; i++) {
				IP_ADS_MASK t;
				if (pTable->table[i].dwAddr != 0x0100007f){	//	127.0.0.1
					t.ip = pTable->table[i].dwAddr;
					t.mask = pTable->table[i].dwMask;
					my_ip_ads_mask.push_back(t);
				}
			}
		}
	}
	else{
		error_msg(hDlg);
		delete[](MIB_IPADDRTABLE *)pTable;
		return FALSE;
	}
	delete[](MIB_IPADDRTABLE *)pTable;
	return TRUE;
}

//	THREAD_MANから指定個数起動されるスレッド
//	IPアドレスが発行されシグナル状態となるとユーザー定義関数を呼び出し終了を待ちイベントを非シグナルにする。

DWORD WINAPI run_thread(LPVOID lParam){	//	起動されるスレッド
	THREAD_MAN_CREATE* cp = (THREAD_MAN_CREATE*)lParam;
	THREAD_MAN* tmp = (THREAD_MAN*)cp->thread_man;
	int num = cp->num;

	DWORD ret;
	//	データーが投入されるまで待機
	for (;;){
		if (ping_run_f == false)
			return 0;
		ret = WaitForSingleObject(tmp->run_event[num], 200);//	0.2秒待機
		if (ret == WAIT_OBJECT_0){
			(*tmp->func)(tmp->data[num], num);	//	ユーザー定義関数
		}
		else{
			Sleep(50);
			continue;
		}
		ResetEvent(tmp->run_event[num]);	//	非シグナル状態に設定
	}
	return 0;
}

resource.h

#define APL_NAME "GUIPING"
#define APL_NAME0 "GUIPING"
#define FILE_VERSION 1,1,0,0
#define VERSION_NUMBER 	"1, 1, 0,0"
#define VERSION_NUMBER0 "1, 1, 0,0\0"
#define COPYRIGHT "Copyright (C) 2015/08/25"
#define COPYRIGHT0 "Copyright (C) 2015/08/25"
#define DESCRIPTION  "キラー"
#define DESCRIPTION0  "キラー\0"
#define APL_VER	"GUIPing Version  1, 1, 0,0"


#define IDC_IPADDRE	100	//	IPアドレス
#define IDC_END_ADR_EDIT 110	//
#define IDC_MY_IP_EDIT	120	//	終了IPアドレス
#define IDC_MY_MASK_EDIT	130	//	終了IPアドレス
#define IDC_LISTVIEW1	140	//	リストビュー
#define IDC_LABEL1	150	//	ラベル
#define IDC_COMBOBOX 160

#define IDC_BUFSIZE 165
#define IDC_TIMEOUT 167

#define	IDC_SAVE	170	//	保存
#define	IDC_ERASE	180	//	リストビュー消去
#define	IDC_QUIT	190	//	終了

#define IDC_RADIOBOX101 200
#define IDC_RADIOBOX102 210

#define IDC_RENGE_LABEL 220
#define IDC_MY_MASK_LABEL 230

resource.rc

#define APL_NAME "GUIPING"
#define APL_NAME0 "GUIPING"
#define FILE_VERSION 1,1,0,0
#define VERSION_NUMBER 	"1, 1, 0,0"
#define VERSION_NUMBER0 "1, 1, 0,0\0"
#define COPYRIGHT "Copyright (C) 2015/08/25"
#define COPYRIGHT0 "Copyright (C) 2015/08/25"
#define DESCRIPTION  "キラー"
#define DESCRIPTION0  "キラー\0"
#define APL_VER	"GUIPing Version  1, 1, 0,0"


#define IDC_IPADDRE	100	//	IPアドレス
#define IDC_END_ADR_EDIT 110	//
#define IDC_MY_IP_EDIT	120	//	終了IPアドレス
#define IDC_MY_MASK_EDIT	130	//	終了IPアドレス
#define IDC_LISTVIEW1	140	//	リストビュー
#define IDC_LABEL1	150	//	ラベル
#define IDC_COMBOBOX 160

#define IDC_BUFSIZE 165
#define IDC_TIMEOUT 167

#define	IDC_SAVE	170	//	保存
#define	IDC_ERASE	180	//	リストビュー消去
#define	IDC_QUIT	190	//	終了

#define IDC_RADIOBOX101 200
#define IDC_RADIOBOX102 210

#define IDC_RENGE_LABEL 220
#define IDC_MY_MASK_LABEL 230

ソースファイルと実行ファイルのダウンロード

ダウンロード guiping2.zip(75.0kByte)

ZIPファイルに含まれるファイル
guiping2.cpp
resource.h
resource.rc
guiping2.exe