//---------------------------------------------------------------- // ■Win Chat Client(Chat ClientのWindows版) //---------------------------------------------------------------- // @ユーザ名、ホスト名(localhostまたはIPアドレス)を入力して // 「接続」ボタンをクリックすると、以下の一覧が表示されます。 // //   **Members:<ユーザ名一覧> // // Aユーザ名が登録されるているのを確認したら //  「メッセージ」欄にメッセージを入力して「送信」ボタンをクリックします。 // B「切断」ボタンをクリックすると終了します。 // C再度やりなおすときは@から開始します // #include "myWin.h" #include "process.h" #pragma comment(lib,"WS2_32.LIB") #define EDT1 1001 // ユーザ名 #define EDT2 1002 // ホスト名 #define EDT3 1003 // 送信メッセージ #define EDT4 1004 // 送受信結果 #define BTN1 2001 // 接続ボタン #define BTN2 2002 // 送信ボタン #define BTN3 2003 // 切断ボタン static HWND edit1, edit2, edit3, edit4;//エディットコントロールのハンドラ static HWND btn1, btn2, btn3; //ボタンコントロールのハンドラ static int notEnd=true; static TCHAR strFile[2048]=TEXT("winClient.dt"),dtBuff[2]; DWORD wReadSize,wWriteSize; TCHAR str[2][2048], log[20000]; SOCKADDR_IN addrServer; SOCKET soc;int icount; int wFlag=false; void procCreate(HWND hw, WPARAM wp, LPARAM lp){//■各コントロールの生成 CreateWindow(TEXT("STATIC"),TEXT("ユーザ名"),WS_CHILD|WS_VISIBLE|SS_CENTER, 0,0,100,20,hw,(HMENU)1, hInstance,NULL); CreateWindow(TEXT("STATIC"),TEXT("ホスト名"),WS_CHILD|WS_VISIBLE|SS_CENTER, 0,20,100,20,hw,(HMENU)1, hInstance,NULL); CreateWindow(TEXT("STATIC"),TEXT("メッセージ"),WS_CHILD|WS_VISIBLE|SS_CENTER, 0,40,100,20,hw,(HMENU)1, hInstance,NULL); edit1=CreateWindow(TEXT("EDIT"),TEXT("guest"), // ユーザ名エディットコントロール WS_CHILD | WS_VISIBLE |WS_BORDER |ES_LEFT,100,0,200,20,hw,(HMENU)EDT1,hInstance,NULL); edit2=CreateWindow(TEXT("EDIT"),TEXT("localhost"), // ホスト名エディットコントロール WS_CHILD | WS_VISIBLE |WS_BORDER |ES_LEFT,100,20,200,20,hw,(HMENU)EDT2,hInstance,NULL); edit3=CreateWindow(TEXT("EDIT"),TEXT(""), // メッセージ入力エディットコントロール WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_LEFT | ES_MULTILINE | ES_OEMCONVERT | ES_WANTRETURN,100,40,400,100,hw,(HMENU)EDT3,hInstance,NULL); edit4=CreateWindow(TEXT("EDIT"),TEXT(""), // 送受信結果エディットコントロール WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_LEFT | ES_MULTILINE | ES_OEMCONVERT | ES_WANTRETURN,100,150,400,300,hw,(HMENU)EDT4,hInstance,NULL); btn1=CreateWindow(TEXT("BUTTON"),TEXT("接続"), // 接続ボタン WS_CHILD | WS_VISIBLE |BS_PUSHBUTTON,10,80,50,20,hw,(HMENU)BTN1,hInstance,NULL); btn2=CreateWindow(TEXT("BUTTON"),TEXT("送信"), // 送信ボタン WS_CHILD | WS_VISIBLE |BS_PUSHBUTTON,10,120,50,20,hw,(HMENU)BTN2,hInstance,NULL); btn3=CreateWindow(TEXT("BUTTON"),TEXT("切断"), // 切断ボタン WS_CHILD | WS_VISIBLE |BS_PUSHBUTTON,10,160,50,20,hw,(HMENU)BTN3,hInstance,NULL); str[0][0]=str[1][0]=log[0]=0;//前回データの読込み(オープンできない/形式が異なるとき標準値) HANDLE hF=CreateFile(strFile,GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL); if(hF!=INVALID_HANDLE_VALUE){ ReadFile(hF,dtBuff,2,&wReadSize,NULL); if(wReadSize==2 && dtBuff[0]==0xFEFF){//UNICODEテキストファイルであることの確認 int i=0, j=0;// str[0][]:ユーザ名、str[1][]:ホスト名 while(ReadFile(hF,dtBuff,2,&wReadSize,NULL)){ if(wReadSize==0)break;//入力データなしのとき終わり if(dtBuff[0]==0x000D){//CRがあったら次のデータ ReadFile(hF,dtBuff,2,&wReadSize,NULL);//LFを無視 str[j][i++]=0; j++;i=0; if(j>=2)break;//ホスト名以降は送受信データ } else str[j][i++]=dtBuff[0]; } i=0; if(wReadSize!=0){//前回送受信データの読込み while(i<=10000 && ReadFile(hF,dtBuff,2,&wReadSize,NULL)){ if(wReadSize==0)break; log[i++]=dtBuff[0]; } } log[i]=0; } CloseHandle(hF);//前回データの終了 } if(str[0][0]==0)lstrcpy(str[0],TEXT("guest")); //ユーザ名の標準値 if(str[1][0]==0)lstrcpy(str[1],TEXT("localhost")); //ホスト名の標準値 SetWindowText(edit1,str[0]) ; SetWindowText(edit2,str[1]); SetWindowText(edit3,TEXT("")); SetWindowText(edit4,log); } int UNIToANSI(TCHAR UNI[], char ANSI[]){//■UNICODEからANSIコードに変換 int iLenANSI=WideCharToMultiByte(CP_ACP,0,UNI,-1,NULL ,0 ,NULL,NULL); WideCharToMultiByte(CP_ACP,0,UNI,-1,(LPSTR)ANSI,iLenANSI,NULL,NULL); return iLenANSI; } int ANSIToUNI(char ANSI[],TCHAR UNI[]){//■ANSIコードからUNICODEに変換 int iLenUNI=MultiByteToWideChar(CP_ACP,0,(LPSTR)ANSI,-1,NULL, 0); MultiByteToWideChar(CP_ACP,0,(LPSTR)ANSI,-1,UNI,iLenUNI); return iLenUNI; } void dspErr(HWND hw,TCHAR msg[]){//■エラー表示 TCHAR str[512]; wsprintf(str,TEXT(" %s Error No =%d"),msg,WSAGetLastError()); } void check2J(char INP[]){//■VT100用画面クリアメッセージを無視 if(strlen(INP)>=4) if(INP[0]==0x1B && INP[1]=='[' && INP[2]=='2' && INP[3]=='J'){ int i=0; for(int j=4; INP[j]!=0;i++,j++) INP[i]=INP[j]; INP[i]=0; } } int checkGoodBy(char INP[]){//■サーバからのGoodByメッセージの判定 char GoodBy[]="\r\nGreet : Good by!"; int num=strlen(GoodBy); for(int i=0;i15000){//文字数15000を制限とする。 int j=LL-15000;int i=0; while(log[j]!=0) log[i++]=log[j++]; log[i]=0; } SetWindowText(edit4,log); SendMessage(edit4,EM_LINESCROLL,0,15000); wFlag=false; } void dspRec(char ANSI[]){//■ANSIをUNICODEに変換してEditコントロールに設定 TCHAR tch[2048]; int L= ANSIToUNI(ANSI,tch); dspRec(tch); } void recDT(void *dt){//■サーバからの受信データを表示 char buff[1024]; int nRecv; while(1){ nRecv=recv(soc, buff, sizeof(buff),0); buff[nRecv]=0; if(nRecv==SOCKET_ERROR) {dspErr(NULL,TEXT("受信失敗")); break;} else if(checkGoodBy(buff)){ notEnd=false; dspRec(buff);break; }//サーバからのGood byで終わる else { check2J(buff); dspRec(buff);}// VT100エスケープシーケンスを無視して出力 Sleep(100); } } void procConnect(HWND hw){//■接続処理 char hName[2048]; GetWindowText(edit2,str[1],2048);UNIToANSI(str[1],hName); WSADATA DT; SOCKADDR_IN name={AF_INET}; int addrLen=sizeof(SOCKADDR); WSAStartup(2,&DT);// Windows Socket API開始 soc=socket(AF_INET,SOCK_STREAM,0); // ソケット作成 if(soc==INVALID_SOCKET)dspErr(hw, TEXT("ソケット作成エラー")); else{// IPアドレスを求める LPHOSTENT PH; unsigned long IPAddress; IPAddress=inet_addr(hName); if(IPAddress==-1){// IPアドレス形式でない場合、名前からIPアドレスを得る if((PH =(LPHOSTENT) gethostbyname(hName))!=NULL) IPAddress=*((unsigned long *)(PH->h_addr)); else{ dspErr(hw,TEXT("ホスト名取得エラー")); shutdown(soc,2);closesocket(soc);WSACleanup(); return; } } addrServer.sin_family=AF_INET; // サーバー接続 addrServer.sin_addr.S_un.S_addr=IPAddress; // IPアドレス addrServer.sin_port=htons((unsigned short)2048);// ポート番号 = 2048 if(connect(soc,(LPSOCKADDR)&addrServer,sizeof(addrServer))==SOCKET_ERROR) dspErr(hw,TEXT("サーバへの接続失敗")); else{ char uName[514]; _beginthread(recDT,0,NULL);// 受信スレッド開始 GetWindowText(edit1,str[0],2048);UNIToANSI(str[0],uName);//ユーザ名を送信(ANSIコードに変換) strcat(uName,"\r\n"); if(send(soc,uName,strlen(uName),0)==SOCKET_ERROR)dspErr(NULL, TEXT("送信エラー")); } } } void procSend(HWND hw){//■送信処理 TCHAR UNI[512];char ANSI[512];TCHAR CRLF[]=TEXT("\r\n"); char msg[512]; GetWindowText(edit3,UNI,512); UNIToANSI(UNI,ANSI); dspRec(UNI);dspRec(CRLF);//edit4表示のときは最後LFを出力 int j=0,i=0;//1行ずつ分けて送信する while(ANSI[i]!=0){ if(ANSI[i]=='\n') {// \nのとき\rを前に付加して送信 msg[j++]='\r';msg[j++]='\n';msg[j++]=0; if(send(soc,msg,strlen(msg),0)==SOCKET_ERROR)dspErr(NULL, TEXT("送信エラー")); j=0; i++; Sleep(100); } else msg[j++]=ANSI[i++]; } msg[j++]='\r';msg[j++]='\n';msg[j++]=0;// \r\nを付けて送信 if(send(soc,msg,strlen(msg),0)==SOCKET_ERROR)dspErr(NULL, TEXT("送信エラー")); Sleep(100); } void procDisconnect(HWND hw){ if(MessageBox(hw,TEXT("終わらせますか"),TEXT("切断"),MB_OKCANCEL)==IDOK){ char msg[]="$by\r\n"; // 通信を終わらせる if(send(soc,msg,strlen(msg),0)==SOCKET_ERROR)dspErr(NULL, TEXT("送信エラー")); while(notEnd)Sleep(100); notEnd=true; } } void procCommand(HWND hw, WPARAM wp, LPARAM lp){//■コマンド分岐 switch(LOWORD(wp)){ case BTN1:procConnect(hw);return; case BTN2:procSend(hw);return; case BTN3:procDisconnect(hw);return; } } void procEnd(HWND hw, WPARAM wp, LPARAM lp){//■終了処理 procDisconnect(hw); HANDLE hF=CreateFile(strFile,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if(hF!=INVALID_HANDLE_VALUE){ dtBuff[0]=0xFEFF; // UNICODEテキストファイル先頭 WriteFile(hF,dtBuff,2,&wWriteSize,NULL); dtBuff[0]=0x000D;dtBuff[1]=0x000A; GetWindowText(edit1,str[0],2048); GetWindowText(edit2,str[1],2048); WriteFile(hF,str[0],lstrlen(str[0])*2,&wWriteSize,NULL);//ユーザ名 WriteFile(hF,dtBuff,4,&wWriteSize,NULL); WriteFile(hF,str[1],lstrlen(str[1])*2,&wWriteSize,NULL);//ホスト名 WriteFile(hF,dtBuff,4,&wWriteSize,NULL); GetWindowText(edit4,log,15004); //送受信結果 WriteFile(hF,log,lstrlen(log)*2+1,&wWriteSize,NULL); FlushFileBuffers(hF); //Write Buffer Flush CloseHandle(hF); // ファイルクロース } shutdown(soc,2);closesocket(soc);WSACleanup(); PostQuitMessage(0) ; } LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp){//■メッセージ分岐 switch(msg){ case WM_DESTROY : procEnd(hw,wp,lp); ; return 0; case WM_CREATE: procCreate(hw,wp,lp);return 0; case WM_COMMAND: procCommand(hw,wp,lp);return 0; } return DefWindowProc(hw, msg, wp, lp); }