非同期名前解決ダイアログ
ここで作るプログラムは次のようなダイアログプログラムです。
今回作るプログラム - 非同期名前解決プログラムのダウンロード
これはどのようなものかと言うと、使い方は次の通りです。
- Host name に名前解決したいホスト名を入力する。(例えば www.microsoft.com)
- Resolve ボタンをクリックする
- その結果が表示される
というものです。
名前解決というと、ホスト名から IP アドレスを引いてくるだけのものかと思ってしまいますが、 (もちろん、ポイントはそこですが) API を呼び出した結果ではエイリアスなども引いてきていることが、上の結果からわかると思います。
ここで使っているのは、WSAAsyncGetHostByName 関数です。
HANDLE WSAAsyncGetHostByName( __in HWND hWnd, __in unsigned int wMsg, __in const char *name, __out char *buf, __in int buflen );
この第4引数の buf に結果が返りますが、この時のデータが次のような HOSTENT 型として返ります。
typedef struct hostent { char FAR * h_name; char FAR FAR **h_aliases; short h_addrtype; short h_length; char FAR FAR **h_addr_list; } HOSTENT, *PHOSTENT, FAR *LPHOSTENT;
パッと見、ちょっとわかりにくいように感じると思いますので、実際にどんなデータが入っているか見てみよう、というのがこのプログラムの狙いです。
尚、お気づきと思いますが名前解決をするのに使用している WSAAsyncGetHostByName 関数は、 Async と付いているように非同期 (Asynchronous) 関数です。
そのため、Resolve ボタンを押した後に待たされることなく、なんとなく軽快に動くような感じがすると思います。
非同期名前解決のサンプルコード
それでは実際に上記のコードを示します。
いきなり、最初にイイワケさせていただくと(苦笑)、かなり昔に書いたコードで、 今見ると直したいと思う箇所がちょこちょこ見受けられます。(ちなみに 2001年11月14日 に書いてます)
ご丁寧に TCHAR 使ってますが、でも Unicode ビルドできなかったりします (笑) WSAAsyncGetHostByName 関数が char* を受け取ったりするんですが、その辺の変換までは入れ込んでないってことです。 直したい方は自分で直してください。
と、言い訳もしたところでコードはこちらです。
まずは以下のコードを HostentTest.h として保存してください。
#pragma once #include <windows.h> #include <windowsx.h> /////////////////////////////////////////////////////////////////////////////// #define HANDLE_DLG_MSG(hwnd, msg, fn) \ case (msg): \ return SetDlgMsgResult(hwnd, msg, HANDLE_##msg(hwnd, wParam, lParam, fn)) #define HANDLE_SM_GETHOSTBYNAME(hwnd, wParam, lParam, fn) \ (LRESULT)(DWORD)(UINT)(BOOL)(fn)((hwnd), (HANDLE)(wParam), lParam) #define GET_ERROR_RESOURCEID(msg, x) \ case (msg): (x) = IDS_##msg; break /////////////////////////////////////////////////////////////////////////////// #define SM_GETHOSTBYNAME (WM_USER+5001) /////////////////////////////////////////////////////////////////////////////// BOOL InitializeGlobalVariables(HWND hWnd); void ClearControls(HWND hWnd);
次に次のコードを HostentTest.cpp として保存します。
#include <winsock2.h> #include "HostentTest.h" #include <tchar.h> #include <stdio.h> #include "resource.h" /////////////////////////////////////////////////////////////////////////////// // // global variables. // WSADATA g_wsaData; HANDLE g_hTask = NULL; TCHAR g_HostEntry[MAXGETHOSTSTRUCT]; /////////////////////////////////////////////////////////////////////////////// BOOL CallGetHostByName(HWND hWnd) { TCHAR szName[50]; Edit_GetText(GetDlgItem(hWnd, IDC_HOSTNAME), szName, 50); ::ZeroMemory(&g_HostEntry, MAXGETHOSTSTRUCT); g_hTask = WSAAsyncGetHostByName( hWnd, SM_GETHOSTBYNAME, szName, g_HostEntry, MAXGETHOSTSTRUCT ); if(!g_hTask) { return FALSE; } return TRUE; } /////////////////////////////////////////////////////////////////////////////// BOOL OnGetHostEntry(HWND hWnd, HANDLE hTaskHandle, LPARAM lParam) { INT nError = WSAGETASYNCERROR(lParam); // Get an error code from lParam. if(nError == 0) { //success Static_SetText(GetDlgItem(hWnd, IDC_STATUS), TEXT("Found!")); INT i; TCHAR szBuff[100]; HOSTENT* pHostEntry = (HOSTENT*) g_HostEntry; Static_SetText(GetDlgItem(hWnd, IDC_HNAME), pHostEntry->h_name); for(i=0; pHostEntry->h_aliases[i] != NULL; i++) { ListBox_AddString(GetDlgItem(hWnd, IDC_HALIASES), pHostEntry->h_aliases[i]); } _stprintf(szBuff, "%d", pHostEntry->h_addrtype); Static_SetText(GetDlgItem(hWnd, IDC_HADDRTYPE), szBuff); _stprintf(szBuff, "%d", pHostEntry->h_length); Static_SetText(GetDlgItem(hWnd, IDC_HLENGTH), szBuff); for(i=0; pHostEntry->h_addr_list[i] != NULL; i++) { IN_ADDR* pInAddr = NULL; pInAddr = (IN_ADDR*) pHostEntry->h_addr_list[i]; //network byte order LPCTSTR lpszDotAddr = inet_ntoa(*pInAddr); ListBox_AddString( GetDlgItem( hWnd, IDC_HADDRLIST), lpszDotAddr ? lpszDotAddr : TEXT("")); } } else { TCHAR szBuff[255]; INT nStringID = 0; switch(nError) { GET_ERROR_RESOURCEID(WSAENETDOWN, nStringID); GET_ERROR_RESOURCEID(WSAENOBUFS, nStringID); GET_ERROR_RESOURCEID(WSAEFAULT, nStringID); GET_ERROR_RESOURCEID(WSAHOST_NOT_FOUND, nStringID); GET_ERROR_RESOURCEID(WSATRY_AGAIN, nStringID); GET_ERROR_RESOURCEID(WSANO_RECOVERY, nStringID); GET_ERROR_RESOURCEID(WSANO_DATA, nStringID); } if(nStringID) { LoadString((HINSTANCE) GetWindowLongPtr(hWnd, GWL_HINSTANCE), nStringID, szBuff, 255); } else { _stprintf(szBuff, TEXT("Unexpected error has occured.")); } Static_SetText(GetDlgItem(hWnd, IDC_STATUS), szBuff); } InitializeGlobalVariables(hWnd); return TRUE; } /////////////////////////////////////////////////////////////////////////////// inline void SetButtonTextInSearch(HWND hWnd, BOOL bInSearch) { HWND hButton = GetDlgItem(hWnd, IDC_RESOLVE); if(bInSearch) { Button_SetText(hButton, TEXT("C&ancel")); } else { Button_SetText(hButton, TEXT("&Resolve")); } } /////////////////////////////////////////////////////////////////////////////// // // Initialize global variables except g_wsaData; // BOOL InitializeGlobalVariables(HWND hWnd) { ::ZeroMemory(g_HostEntry, MAXGETHOSTSTRUCT); g_hTask = NULL; SetButtonTextInSearch(hWnd, FALSE); return TRUE; } /////////////////////////////////////////////////////////////////////////////// // // Initialize a main dialog box // BOOL OnInitDialog(HWND hWnd, HWND hWndFocus, LPARAM lParam) { //Set text Edit_SetText(GetDlgItem(hWnd, IDC_HOSTNAME), TEXT("www.microsoft.com")); //Set icon SendMessage(hWnd, WM_SETICON, TRUE, (LPARAM) LoadIcon((HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE), MAKEINTRESOURCE(IDI_HOSTENTTEST))); return TRUE; } /////////////////////////////////////////////////////////////////////////////// void CancelSearching(HWND hWnd) { WSACancelAsyncRequest(g_hTask); } /////////////////////////////////////////////////////////////////////////////// // // Handling WM_COMMAND Message // void OnCommand(HWND hWnd, int nID, HWND hWndCtl, UINT codeNotify) { switch(nID) { case IDC_RESOLVE: if(g_hTask) { CancelSearching(hWnd); InitializeGlobalVariables(hWnd); SetButtonTextInSearch(hWnd, FALSE); Static_SetText(GetDlgItem(hWnd, IDC_STATUS), TEXT("The request has been successfully canceled.")); } else { ClearControls(hWnd); CallGetHostByName(hWnd); SetButtonTextInSearch(hWnd, TRUE); Static_SetText(GetDlgItem(hWnd, IDC_STATUS), TEXT("Searching...")); } break; case IDCANCEL: EndDialog(hWnd, 0); break; } } /////////////////////////////////////////////////////////////////////////////// // // Main Window Procedure // BOOL CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { HANDLE_DLG_MSG(hWnd, WM_INITDIALOG, OnInitDialog); HANDLE_DLG_MSG(hWnd, WM_COMMAND, OnCommand); HANDLE_DLG_MSG(hWnd, SM_GETHOSTBYNAME, OnGetHostEntry); } return FALSE; } /////////////////////////////////////////////////////////////////////////////// // // WinSock �������� // BOOL InitializeWinSock() { ::ZeroMemory(&g_wsaData, sizeof(WSADATA)); WORD wVersionRequested = WINSOCK_VERSION; WORD nRet = WSAStartup( wVersionRequested, &g_wsaData); return nRet == 0 ? TRUE: FALSE; } /////////////////////////////////////////////////////////////////////////////// // // Clear all controls // void ClearControls(HWND hWnd) { Static_SetText(GetDlgItem(hWnd, IDC_HNAME), TEXT("")); ListBox_ResetContent(GetDlgItem(hWnd, IDC_HALIASES)); Static_SetText(GetDlgItem(hWnd, IDC_HADDRTYPE), TEXT("")); Static_SetText(GetDlgItem(hWnd, IDC_HLENGTH), TEXT("")); ListBox_ResetContent(GetDlgItem(hWnd, IDC_HADDRLIST)); } /////////////////////////////////////////////////////////////////////////////// // // WinMain // int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { if(!InitializeWinSock()) { ::MessageBox(NULL, TEXT("WinSock is not available."), TEXT("Error"), MB_OK|MB_ICONERROR); return 0; } ::DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAINWND), NULL, MainWndProc); WSACleanup(); return 0; }
リソーススクリプト HostentTest.rc はこちら。ダイアログのサイズ・配置など好きに書き換えてください。 (リソースファイルの書き換えには ResEdit などが良いです。 http://www.resedit.net/ 私は Visual Studio は余計なコードを書き込むので好きじゃありません... 全く... 何でコードにデザイナーの情報を書き入れるんだ...ブツブツ)
#include "resource.h" #include <windows.h> // // Dialog resources // LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_MAINWND DIALOGEX 0, 0, 226, 203 STYLE DS_CENTER | DS_MODALFRAME | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU CAPTION "Hostent Test" FONT 10, "MS Sans Serif", 400, 0, 0 BEGIN PUSHBUTTON "&Close", IDCANCEL, 169, 182, 50, 14 EDITTEXT IDC_HOSTNAME, 47, 7, 118, 14, ES_AUTOHSCROLL LTEXT "Host name:", IDC_STATIC, 7, 10, 36, 10 DEFPUSHBUTTON "&Resolve", IDC_RESOLVE, 171, 7, 48, 14 GROUPBOX "Result (The content of Hostent structure)", IDC_STATIC, 7, 39, 212, 135 LTEXT "Host name (h_name) :", IDC_STATIC, 13, 53, 64, 10 LTEXT "", IDC_HNAME, 78, 51, 133, 12, SS_SUNKEN LTEXT "Alias (h_aliases) :", IDC_STATIC, 13, 66, 55, 10 LISTBOX IDC_HALIASES, 78, 65, 134, 23, WS_TABSTOP | WS_VSCROLL | LBS_NOINTEGRALHEIGHT | LBS_SORT LTEXT "Address Type (h_addrtype) : ", IDC_STATIC, 14, 95, 83, 9 LTEXT "", IDC_HADDRTYPE, 98, 93, 114, 13, SS_SUNKEN LTEXT "Length (h_length) : ", IDC_STATIC, 14, 109, 70, 10 LTEXT "", IDC_HLENGTH, 98, 107, 114, 13, SS_SUNKEN LTEXT "Address List (h_addr_list) :", IDC_STATIC, 14, 123, 83, 10 LISTBOX IDC_HADDRLIST, 80, 135, 132, 34, WS_TABSTOP | WS_VSCROLL | LBS_NOINTEGRALHEIGHT | LBS_SORT LTEXT "", IDC_STATUS, 47, 24, 172, 12, SS_SUNKEN LTEXT "Status:", IDC_STATIC, 7, 25, 35, 10 END // // Icon resources // LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDI_HOSTENTTEST ICON "icon1.ico" // // String Table resources // LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL STRINGTABLE BEGIN IDS_WSAENETDOWN "The network subsystem has failed." IDS_WSAENOBUFS "Insufficient buffer space is available." IDS_WSAEFAULT "The name or buf parameter is not in a valid part of the process address space." IDS_WSAHOST_NOT_FOUND "Authoritative answer host not found." IDS_WSATRY_AGAIN "A nonauthoritative host not found, or SERVERFAIL." IDS_WSANO_RECOVERY "Nonrecoverable errors, FORMERR, REFUSED, NOTIMP." IDS_WSANO_DATA "Valid name, no data record of requested type." END
resource.h はこちら
# i f n d e f I D C _ S T A T I C
# d e f i n e I D C _ S T A T I C (