diff --git a/WinChat/WinChat.rc b/WinChat/WinChat.rc index e402b59..b3debba 100644 Binary files a/WinChat/WinChat.rc and b/WinChat/WinChat.rc differ diff --git a/WinChat/WinChat.vcxproj.filters b/WinChat/WinChat.vcxproj.filters index fc05d7b..07bc997 100644 --- a/WinChat/WinChat.vcxproj.filters +++ b/WinChat/WinChat.vcxproj.filters @@ -24,6 +24,12 @@ Source Files + + Source Files + + + Source Files + @@ -35,6 +41,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/WinChat/resource.h b/WinChat/resource.h index 7e418c0..347b243 100644 --- a/WinChat/resource.h +++ b/WinChat/resource.h @@ -5,6 +5,7 @@ #define IDD_DIALOGMAIN 101 #define IDR_MENUMAIN 104 #define IDI_ICONMAIN 106 +#define IDD_DIALOGCONNECTING 107 #define IDC_STATICTITLE 1001 #define IDC_BUTTONEXIT 1003 #define IDC_BUTTONCONNECT 1005 @@ -12,6 +13,8 @@ #define IDC_ICONMAIN 1007 #define IDC_EDITSCREENNAME 1008 #define IDC_STATICDESC 1009 +#define IDC_STATICADDRESS 1010 +#define IDC_PROGRESS 1011 #define ID_FILE_EXIT 40001 #define ID_HELP_ABOUT 40002 @@ -19,9 +22,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_RESOURCE_VALUE 109 #define _APS_NEXT_COMMAND_VALUE 40003 -#define _APS_NEXT_CONTROL_VALUE 1010 +#define _APS_NEXT_CONTROL_VALUE 1012 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/WinChat/src/Application.cpp b/WinChat/src/Application.cpp index cc4233b..8d7fe87 100644 --- a/WinChat/src/Application.cpp +++ b/WinChat/src/Application.cpp @@ -42,24 +42,24 @@ namespace wc { } void Application::run() { - //First, start a thread to listen for incoming connections... + //First, start a thread to listen for incoming connections std::thread listenThread(&Application::startListen, this); - //Then, run the main dialog to get needed input... + //Then, run the main dialog to get needed input INT_PTR result = NULL; MainDlgInput* input = new MainDlgInput{ this, -1, -1 }; - while (result = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOGMAIN), nullptr, (DLGPROC)mainDlgProc, reinterpret_cast(input))) { - //Then create a Chat with the collected input... + while (result = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOGMAIN), nullptr, reinterpret_cast(mainDlgProc), reinterpret_cast(input))) { + //Then create a Chat with the collected input MainDlgOutput* output = reinterpret_cast(result); const auto [address, screenname, x, y] = *output; delete output; { Chat chat(address, screenname); - chat.run(); + chat.run(x, y); } - //And repeat until the user exits from the main dialog. + //And repeat until the user exits from the main dialog input = new MainDlgInput{ this, x, y }; } @@ -134,13 +134,13 @@ namespace wc { case WM_INITDIALOG: { MainDlgInput* in = reinterpret_cast(lParam); auto [appTemp, xPos, yPos] = *in; - app = appTemp; delete in; + app = appTemp; SetWindowText(dlg, app->m_appName.c_str()); SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN)))); - if (xPos < 0) { + if (xPos == -1 && yPos == -1) { POINT pt = { }; GetCursorPos(&pt); MONITORINFO mi = { }; @@ -171,7 +171,7 @@ namespace wc { int addressSize = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITADDRESS)); int screennameSize = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITSCREENNAME)); if (!addressSize || !screennameSize) { - EDITBALLOONTIP balloon = { .cbStruct = sizeof(balloon), .pszTitle = L"Alert", .pszText = L"You must enter an address and screenname." }; + EDITBALLOONTIP balloon = { .cbStruct = sizeof(balloon), .pszTitle = L"Alert", .pszText = L"You must enter an address and screen name." }; SendDlgItemMessage(dlg, addressSize ? IDC_EDITSCREENNAME : IDC_EDITADDRESS, EM_SHOWBALLOONTIP, NULL, reinterpret_cast(&balloon)); return TRUE; } @@ -204,7 +204,7 @@ namespace wc { return FALSE; case WM_HOTKEY: - if (wParam != 1) + if (wParam != 1 || GetForegroundWindow() != dlg) return FALSE; [[fallthrough]]; case WM_CLOSE: diff --git a/WinChat/src/Chat.cpp b/WinChat/src/Chat.cpp index 679c211..45bc9a8 100644 --- a/WinChat/src/Chat.cpp +++ b/WinChat/src/Chat.cpp @@ -2,19 +2,43 @@ #include "Chat.h" #include "StrConv.h" +#include "../resource.h" + +#define IDT_CHECKCONN 1 namespace wc { + struct ConnDlgInput { + Chat* chat; + int xPos, yPos; + }; + Chat::Chat(std::wstring address, std::wstring screenname) : m_address(address) , m_screenname(screenname) + , m_connected(false) + , m_connectionError(false) { } - void Chat::run() { + void Chat::run(int xPos, int yPos) { + //Run net thread to connect and communicate + std::thread netThread(&Chat::runNetThread, this); + + //Show connection dialog until net thread connects + ConnDlgInput* input = new ConnDlgInput{ this, xPos, yPos }; + DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOGCONNECTING), nullptr, reinterpret_cast(connDlgProc), reinterpret_cast(input)); + + netThread.join(); + } + + void Chat::runNetThread() { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + addrinfo* destInfo = nullptr; if (getaddrinfo(toStr(m_address).c_str(), "9430", nullptr, &destInfo) != 0) { MessageBox(nullptr, L"Error: Could not resolve host or invalid address!", L"Error", MB_ICONERROR); + m_connectionError = true; return; } @@ -22,42 +46,21 @@ namespace wc { if (sock == INVALID_SOCKET) { MessageBox(nullptr, L"Error: could not create network socket!", L"Error", MB_ICONERROR); freeaddrinfo(destInfo); + m_connectionError = true; return; } if (connect(sock, destInfo->ai_addr, static_cast(destInfo->ai_addrlen)) != 0) { - int errorCode = WSAGetLastError(); - std::wstring errorStr; - switch (errorCode) { - case WSAETIMEDOUT: - errorStr = L"Timed out"; - break; - - case WSAECONNREFUSED: - errorStr = L"Connection refused (WinChat may not be running on remote host)"; - break; - - case WSAENETUNREACH: - case WSAEHOSTUNREACH: - errorStr = L"Remote host unreachable (You may not be connected to the internet)"; - break; - - case WSAEADDRNOTAVAIL: - errorStr = L"Not a valid address to connect to"; - break; - - default: - errorStr = std::format(L"Error Code {}", errorCode); - break; - } - + std::wstring errorStr = getErrorString(); MessageBox(nullptr, std::format(L"Error: Could not connect - {}", errorStr).c_str(), L"Error", MB_ICONERROR); freeaddrinfo(destInfo); closesocket(sock); + m_connectionError = true; return; } freeaddrinfo(destInfo); + m_connected = true; std::string data; while (data != "end") { @@ -68,6 +71,63 @@ namespace wc { closesocket(sock); } + std::wstring Chat::getErrorString() { + int errorCode = WSAGetLastError(); + std::wstring out; + switch (errorCode) { + case WSAETIMEDOUT: + out = L"Timed out"; + break; + + case WSAECONNREFUSED: + out = L"Connection refused (WinChat may not be running on remote host)"; + break; + + case WSAENETUNREACH: + case WSAEHOSTUNREACH: + out = L"Remote host unreachable (You may not be connected to the internet)"; + break; + + case WSAEADDRNOTAVAIL: + out = L"Not a valid address to connect to"; + break; + + default: + out = std::format(L"Error Code {}", errorCode); + break; + } + + return out; + } + + BOOL CALLBACK Chat::connDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) { + static Chat* chat = nullptr; + + switch (msg) { + case WM_INITDIALOG: { + ConnDlgInput* in = reinterpret_cast(lParam); + auto [chatTemp, x, y] = *in; + delete in; + chat = chatTemp; + SetWindowPos(dlg, nullptr, x + 100, y + 100, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + SetDlgItemText(dlg, IDC_STATICADDRESS, chat->m_address.c_str()); + SendDlgItemMessage(dlg, IDC_PROGRESS, PBM_SETMARQUEE, TRUE, NULL); + SetTimer(dlg, IDT_CHECKCONN, 100, nullptr); + + return TRUE; + } + + case WM_TIMER: + if (wParam == IDT_CHECKCONN && (chat->m_connected || chat->m_connectionError)) { + EndDialog(dlg, 0); + return TRUE; + } + } + + return FALSE; + } + + Chat::~Chat() { } diff --git a/WinChat/src/Chat.h b/WinChat/src/Chat.h index 00cbec4..9d084eb 100644 --- a/WinChat/src/Chat.h +++ b/WinChat/src/Chat.h @@ -8,11 +8,17 @@ namespace wc { public: Chat(std::wstring address, std::wstring screenname); - void run(); + void run(int xPos, int yPos); ~Chat(); private: + void runNetThread(); + std::wstring getErrorString(); + static BOOL CALLBACK connDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam); + const std::wstring m_address; const std::wstring m_screenname; + bool m_connected; + bool m_connectionError; }; } \ No newline at end of file