開発環境はVS2008std、C言語とWINAPIとwinsockを用いてダイアログベースの通信プログラムを書いています。
TCP接続を用いて、1サーバ対1クライアントでチャットを行うソフトです。
ランタイムが入っていないパソコンでも使用できるようにしたいので、マルチスレッド (/MT)でリリースビルドしました。
デバックモードのEXEはサーバとクライアントの通信が問題なく行えているのですが
リリースモードでビルドしたEXEはサーバ、クライアントの通信が行えなくて困っています。
(ソフトウェアの起動はします、ランタイムが入ってないパソコンでも起動だけはしました、通信はNG)
サーバーをリリースモードのEXE、クライアントをデバックモードのEXEで通信を行ってみたところ
問題なく通信することが出来たので、クライアントがオカシイのかなと踏んでいるのですが
なにぶんデバックモードでは問題なく通信できているのでエラー箇所がわからずに居ます。
プログラムを書いたのに環境依存の事項で頓挫しております、何方かご指導お願いします。
リリースビルドするとプログラムがきちんと動作しなくて困っています。
Re: リリースビルドするとプログラムがきちんと動作しなくて困っています。
クライアントのコードです。
#define WIN32_LEAN_AND_MEAN
#define MY_MSG (WM_USER +1)
#include<windows.h>
#include"resource.h"
#include<winsock2.h>
#include<stdlib.h>
//IDC_SEND 送信エディットボックス
//IDC_PREV クライアントからのメッセージエディットボックス
//IDC_SARVER サーバー名入力ダイアログボックス
//IDC_PORT ポート番号入力ダイアログボックス
//IDC_START 接続ボタン
//IDC_CUT 切断ボタン
//IDC_SENDBUTTON 送信ボタン
//クラスネーム
char *ClassName="GUI Client";
//グローバル変数
HINSTANCE hInstance;
HWND hWnd;
HICON hIcon;
SOCKET InitSocket(u_short,HWND,HWND);
SOCKET InitSocket(u_short uport,HWND hPrev,HWND hDlg)
{
SOCKET s;
char szInfo[64];
s = socket(AF_INET,SOCK_STREAM,0);
if(s < 0){
strcpy(szInfo,"info:ソケット生成エラー\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
return NULL;
}
else{
strcpy(szInfo,"info:ソケットを生成しました\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
strcpy(szInfo,"info:サーバへ接続待機します\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
}
return s;
}
BOOL CALLBACK DlgProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
{
static HWND hSend; //送信エディットボックス
static HWND hPrev; //受信メッセージエディット
static HWND hSarver; //サーバー名入力ダイアログボックス
static HWND hPort; //ポート番号入力エディット
static HWND hStart; //接続ボタン
static HWND hCut; //切断ボタン
static HWND hSendButton;//送信ボタン
char szPort[128],szAddres[128];
char szInfo[128],szSendBuff[384],szEditBuff[512*2],rcvBuff[512];
int nPort;
static u_short uPort;
unsigned int addr;
static SOCKET s;
static HOSTENT *lpHost;
static SOCKADDR_IN saddr;
int nError,nEvent;
unsigned int nRet;
switch(msg)
{
case WM_INITDIALOG:
hSend = GetDlgItem(hDlg,IDC_SEND);
hPrev = GetDlgItem(hDlg,IDC_PREV);
hSarver = GetDlgItem(hDlg,IDC_SARVER);
hPort = GetDlgItem(hDlg,IDC_PORT);
hStart = GetDlgItem(hDlg,IDC_START);
hCut = GetDlgItem(hDlg,IDC_CUT);
hSendButton = GetDlgItem(hDlg,IDC_SENDBUTTON);
SetWindowText(hPort,"49152");
SetWindowText(hDlg,"GUI Client");
EnableWindow(hCut,FALSE);
EnableWindow(hSendButton,FALSE);
hIcon = (HICON)LoadImage(hInstance,"IDI_ICON",IMAGE_ICON,0,0,
LR_SHARED|LR_DEFAULTCOLOR);
if(hIcon == NULL)
MessageBox(hDlg,"","",MB_OK);
SendMessage(hDlg,WM_SETICON,(WPARAM)ICON_BIG,(LPARAM)hIcon);
break;
case WM_CLOSE:
EndDialog(hDlg,0);
break;
case WM_COMMAND:
switch(LOWORD(wParam)){
case IDC_START:
GetWindowText(hPort,szPort,(int)strlen(szPort));
nPort = atoi(szPort);
if(nPort < 0||nPort > 65535){
strcpy(szInfo,"info:ポート番号が不正です\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
return TRUE;
}
else{
strcpy(szInfo,"info:ポート番号を取得しました\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
uPort = atoi(szPort);
}
GetWindowText(hSarver,szAddres,sizeof(szAddres));
if(strcmp(szAddres,"") == 0){
strcpy(szInfo,"info:サーバー名を入力してください\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
return TRUE;
}
lpHost = gethostbyname(szAddres);
if(lpHost == NULL){
addr = inet_addr(szAddres);
lpHost = gethostbyaddr((char *)&addr,4,AF_INET);
strcpy(szInfo,"info:ホスト名を取得しました\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
}
if(lpHost == NULL){
strcpy(szInfo,"info:ホスト名を取得できません\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
return TRUE;
}
s = InitSocket(uPort,hPrev,hDlg);
if(s == NULL){
return TRUE;
}
WSAAsyncSelect(s,hDlg,MY_MSG,FD_CONNECT|FD_READ|FD_CLOSE);
memset(&saddr,0,sizeof(SOCKADDR_IN));
saddr.sin_family = lpHost->h_addrtype;
saddr.sin_port = htons(uPort);
saddr.sin_addr.s_addr = *((u_long *)lpHost->h_addr);
if(connect(s,(SOCKADDR *)&saddr,sizeof(saddr)) == SOCKET_ERROR){
nError = WSAGetLastError();
if(nError != WSAEWOULDBLOCK){
strcpy(szInfo,"info:接続エラーです\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
closesocket(s);
return TRUE;
}
else{
EnableWindow(hStart,FALSE);
EnableWindow(hCut,TRUE);
}
}
return TRUE;
case IDC_SENDBUTTON:
GetWindowText(hSend,szSendBuff,sizeof(szSendBuff) -2);
if(strcmp(szSendBuff,"") == 0)
return 0;
nRet = send(s,szSendBuff,(int)strlen(szSendBuff),0);
strcpy(szEditBuff,"Client:");
strcat(szEditBuff,szSendBuff);
strcat(szEditBuff,"\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szEditBuff);
SetWindowText(hSend,"");
return TRUE;
case IDC_CUT:
shutdown(s,SD_BOTH);
closesocket(s);
strcpy(szInfo,"info:切断しました\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
EnableWindow(hStart,TRUE);
EnableWindow(hCut,FALSE);
EnableWindow(hSendButton,FALSE);
return TRUE;
}
case MY_MSG:
nEvent = WSAGETSELECTEVENT(lParam);
switch(nEvent){
case FD_CONNECT:
strcpy(szInfo,"info:接続しました\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
EnableWindow(hSendButton,TRUE);
return TRUE;
case FD_CLOSE:
strcpy(szInfo,"info:切断されました\r\n");
EnableWindow(hStart,TRUE);
EnableWindow(hCut,FALSE);
EnableWindow(hSendButton,FALSE);
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szInfo);
shutdown(s,SD_BOTH);
closesocket(s);
return TRUE;
case FD_READ:
nRet = recv(s,rcvBuff,sizeof(rcvBuff) - 1,0);
rcvBuff[nRet] = '\0';
strcpy(szEditBuff,"Server:");
strcat(szEditBuff,rcvBuff);
strcat(szEditBuff,"\r\n");
SendMessage(hPrev,EM_REPLACESEL,1,(LPARAM)szEditBuff);
return TRUE;
}
}
return FALSE;
}
int WINAPI WinMain(HINSTANCE hCurInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
WSADATA wsaData;
hInstance = hCurInst; //グローバル変数にコピー
if(WSAStartup(MAKEWORD(1,1),&wsaData)){
MessageBox(NULL,"WSAStartUp Error","Error",MB_OK|MB_ICONEXCLAMATION);
return -1;
}
DialogBox(hInstance,MAKEINTRESOURCE(IDD_CLIENT),NULL,(DLGPROC)DlgProc);
if(WSACleanup() == SOCKET_ERROR){
MessageBox(NULL,"WSACleanup Error","Error",MB_OK|MB_ICONEXCLAMATION);
return -1;
}
return 0;
}
Re: リリースビルドするとプログラムがきちんと動作しなくて困っています。
サーバー側のコードです。
識者の方、よろしくお願いいたします。ご不明点ありましたらご指摘ください。
識者の方、よろしくお願いいたします。ご不明点ありましたらご指摘ください。
#define WIN32_LEAN_AND_MEAN
#define MY_MSG (WM_USER +1)
#include<windows.h>
#include"resource.h"
#include<winsock2.h>
#include<stdlib.h>
//クラスネーム
char *ClassName="テンプレート";
//グローバル変数
HINSTANCE hInstance;
BOOL socket_flag = FALSE,socket_flag2 = FALSE;
HICON hIcon;
SOCKET InitSocket(HWND,HWND,u_short,HWND,HWND);
HWND hWnd;
SOCKET InitSocket(HWND hDlg,HWND hEdit1,u_short uport,HWND hStart,HWND hEnd)
{
SOCKADDR_IN sockaddr_in;
SOCKET s_listen;
char szInfo[128] = "";
int nAsync;
s_listen = socket(AF_INET,SOCK_STREAM,0);
if(s_listen < 0)
{
MessageBox(hDlg,"listenソケット作成エラー","error",MB_OK);
return -1;
}
else
{
strcpy(szInfo,"info:ソケットを生成しました\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
wsprintf(szInfo,"info:Port番号%d\r\n",uport);
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
SetCaretPos(100,50);
}
nAsync = WSAAsyncSelect(s_listen,hDlg,MY_MSG,FD_ACCEPT);
if(nAsync != 0){
MessageBox(hDlg,"非同期化error","error",MB_OK|MB_ICONEXCLAMATION);
closesocket(s_listen);
return -2;
}
memset(&sockaddr_in,0,sizeof(SOCKADDR_IN));
sockaddr_in.sin_family = AF_INET;
sockaddr_in.sin_port = htons(uport);
sockaddr_in.sin_addr.s_addr = INADDR_ANY;
if(bind(s_listen,(SOCKADDR *)&sockaddr_in,sizeof(sockaddr_in)) == SOCKET_ERROR)
{
MessageBox(hDlg,"bind error 別のポートで接続してください","error",MB_OK);
closesocket(s_listen);
return -3;
}
if(listen(s_listen,0) == SOCKET_ERROR)
{
MessageBox(hDlg,"listen error","error",MB_OK);
closesocket(s_listen);
EnableWindow(hStart,TRUE);
EnableWindow(hEnd,FALSE);
return -4;
}
else
{
strcpy(szInfo,"info:クライアント待機状態です\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
EnableWindow(hEnd,TRUE);
EnableWindow(hStart,FALSE);
}
socket_flag = TRUE;
return s_listen;
}
BOOL CALLBACK DlgProc(HWND hDlg,UINT msg,WPARAM wParam,LPARAM lParam)
{
static HWND hEdit1,hEdit2,hSend,hPort,hStart,hEnd;
u_short ushort;
char szBuff[128];
int nEvent,nfromlen,nAsync,nRcv,nSend,nPortBuff;
static SOCKET s_listen,s;
char szInfo[128] = "";
SOCKADDR_IN from;
char rcvBuff[512],EditData[512*2] ="Client:";
char sendBuff[384],sendBuff1[512] = "Server:";
unsigned long dwRcv = 0;
switch(msg)
{
case WM_INITDIALOG:
hEdit1 = GetDlgItem(hDlg,IDC_EDIT2);
hEdit2 = GetDlgItem(hDlg,IDC_EDIT3);
hSend = GetDlgItem(hDlg,IDC_BUTTON1);
hPort = GetDlgItem(hDlg,IDC_EDIT1);
hStart = GetDlgItem(hDlg,IDC_BUTTON2);
hEnd = GetDlgItem(hDlg,IDC_BUTTON3);
EnableWindow(hSend,FALSE);
EnableWindow(hEnd,FALSE);
SetWindowText(hDlg,"GUI SERVER");
SetWindowText(hPort,"49152");
hIcon = (HICON)LoadImage(hInstance,"IDI_ICON",IMAGE_ICON,0,0,
LR_SHARED|LR_DEFAULTCOLOR);
if(hIcon == NULL)
MessageBox(hDlg,"","",MB_OK);
SendMessage(hDlg,WM_SETICON,(WPARAM)ICON_BIG,(LPARAM)hIcon);
break;
case WM_CLOSE:
if(socket_flag){
shutdown(s_listen,SD_BOTH);
}
if(socket_flag2){
shutdown(s,SD_BOTH);
}
DestroyWindow(hDlg);
break;
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDC_BUTTON2://winsock start
GetDlgItemText(hDlg,IDC_EDIT1,szBuff,sizeof(szBuff));
nPortBuff = atoi(szBuff);
if(nPortBuff < 0 || 65535 < nPortBuff){
MessageBox(hDlg,"Port error","error",
MB_OK|MB_ICONEXCLAMATION);
return 0;
}
ushort = atoi(szBuff);
s_listen = InitSocket(hDlg,hEdit1,ushort,hStart,hEnd);
break;
case IDC_BUTTON3:
if(socket_flag){
closesocket(s_listen);
shutdown(s_listen,SD_BOTH);
strcpy(szInfo,"info:listenソケットを閉じました\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
socket_flag = FALSE;
}
if(socket_flag2){
closesocket(s);
shutdown(s,SD_BOTH);
strcpy(szInfo,"info:通信ソケットを閉じました\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
socket_flag2 = FALSE;
}
EnableWindow(hEnd,FALSE);
EnableWindow(hSend,FALSE);
EnableWindow(hStart,TRUE);
break;
case IDC_BUTTON1:
GetWindowText(hEdit2,sendBuff,(int)sizeof(sendBuff)-2);
if(!strlen(sendBuff)){
return 0;
}
nSend = send(s,sendBuff,strlen(sendBuff),0);
strcat(sendBuff,"\r\n");
strcat(sendBuff1,sendBuff);
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)sendBuff1);
SetWindowText(hEdit2,"");
break;
return TRUE;
}
}
case MY_MSG:
nEvent = WSAGETSELECTEVENT(lParam);
switch(nEvent)
{
case FD_ACCEPT:
nfromlen = sizeof(from);
memset(&from,0,sizeof(SOCKADDR));
s = accept(s_listen,(SOCKADDR *)&from,&nfromlen);
if(s == INVALID_SOCKET){
strcpy(szInfo,"info:接続ソケット生成エラー\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
}
else{
strcpy(szInfo,"info:接続ソケットを生成しました\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
closesocket(s_listen);
socket_flag = FALSE;
socket_flag2 = TRUE;
}
nAsync = WSAAsyncSelect(s,hDlg,MY_MSG,FD_CLOSE | FD_READ);
if(nAsync != 0){
strcpy(szInfo,"info:非同期化エラー\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
}
else{
strcpy(szInfo,"info:非同期化成功\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
EnableWindow(hSend,TRUE);
wsprintf(szInfo,"info:%sが接続してきました\r\n",inet_ntoa(from.sin_addr));
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
}
break;
case FD_CLOSE:
strcpy(szInfo,"info:クライアントが切断しました\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
strcpy(szInfo,"info:サーバを立ち上げてください\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)szInfo);
shutdown(s,SD_BOTH);
EnableWindow(hStart,TRUE);
EnableWindow(hEnd,FALSE);
EnableWindow(hSend,FALSE);
break;
case FD_READ:
nRcv = recv(s,rcvBuff,sizeof(rcvBuff)-1,0);
rcvBuff[nRcv] = '\0';
strncat(EditData,rcvBuff,sizeof(EditData));
strcat(EditData,"\r\n");
SendMessage(hEdit1,EM_REPLACESEL,1,(LPARAM)EditData);
break;
return TRUE;
}
default:
return FALSE;
}
return FALSE;
}
int WINAPI WinMain(HINSTANCE hCurInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
WSADATA wsaData;
hInstance = hCurInst;
if(WSAStartup(MAKEWORD(1,1),&wsaData))
{
MessageBox(NULL,"WSAStartUp Error","error",MB_OK);
WSACleanup();
return -1;
}
DialogBox(hInstance,"MYSERVER",NULL,(DLGPROC)DlgProc);
if(WSACleanup() != 0){
MessageBox(NULL,"WSACleanup Error","error",MB_OK|MB_ICONEXCLAMATION);
return -1;
}
return 0;
}
Re: リリースビルドするとプログラムがきちんと動作しなくて困っています。
クライアントの99行目は文字列長ではなくてバッファの大きさを渡すのではないですか?
デバッグモードは未初期化のローカル変数でも特定の値で埋められるので、コピーする文字列長に十分なバッファ『より大きい』値になってたまたま期待通りに動いたのだと思います。
デバッグモードは未初期化のローカル変数でも特定の値で埋められるので、コピーする文字列長に十分なバッファ『より大きい』値になってたまたま期待通りに動いたのだと思います。
Re: リリースビルドするとプログラムがきちんと動作しなくて困っています。
ISLeさん素早いお返事ありがとうございます。strlenをsizeofにしたら・・・・動きました。
こんなミスだったとは、自分では一週間経っても気がつかなかったと思います、ご指摘ありがとうございます。
>デバッグモードは未初期化のローカル変数でも特定の値で埋められるので、コピーする文字列長に十分なバッファ『より大きい』値になってたまたま期待通りに動いたのだと思います。
デバックとリリースではこのような違いがあるのですね、とても勉強になりました。
こんなミスだったとは、自分では一週間経っても気がつかなかったと思います、ご指摘ありがとうございます。
>デバッグモードは未初期化のローカル変数でも特定の値で埋められるので、コピーする文字列長に十分なバッファ『より大きい』値になってたまたま期待通りに動いたのだと思います。
デバックとリリースではこのような違いがあるのですね、とても勉強になりました。