概要

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
}

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