Add connection dialog

This commit is contained in:
Grayson Riffe 2023-09-25 18:36:00 -05:00
parent 3053a0b8f8
commit 15655a6aec
6 changed files with 120 additions and 39 deletions

Binary file not shown.

View File

@ -24,6 +24,12 @@
<ClCompile Include="src\Chat.cpp"> <ClCompile Include="src\Chat.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\StrConv.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\Application.h"> <ClInclude Include="src\Application.h">
@ -35,6 +41,12 @@
<ClInclude Include="src\Chat.h"> <ClInclude Include="src\Chat.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\StrConv.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="WinChat.rc"> <ResourceCompile Include="WinChat.rc">

View File

@ -5,6 +5,7 @@
#define IDD_DIALOGMAIN 101 #define IDD_DIALOGMAIN 101
#define IDR_MENUMAIN 104 #define IDR_MENUMAIN 104
#define IDI_ICONMAIN 106 #define IDI_ICONMAIN 106
#define IDD_DIALOGCONNECTING 107
#define IDC_STATICTITLE 1001 #define IDC_STATICTITLE 1001
#define IDC_BUTTONEXIT 1003 #define IDC_BUTTONEXIT 1003
#define IDC_BUTTONCONNECT 1005 #define IDC_BUTTONCONNECT 1005
@ -12,6 +13,8 @@
#define IDC_ICONMAIN 1007 #define IDC_ICONMAIN 1007
#define IDC_EDITSCREENNAME 1008 #define IDC_EDITSCREENNAME 1008
#define IDC_STATICDESC 1009 #define IDC_STATICDESC 1009
#define IDC_STATICADDRESS 1010
#define IDC_PROGRESS 1011
#define ID_FILE_EXIT 40001 #define ID_FILE_EXIT 40001
#define ID_HELP_ABOUT 40002 #define ID_HELP_ABOUT 40002
@ -19,9 +22,9 @@
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #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_COMMAND_VALUE 40003
#define _APS_NEXT_CONTROL_VALUE 1010 #define _APS_NEXT_CONTROL_VALUE 1012
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif

View File

@ -42,24 +42,24 @@ namespace wc {
} }
void Application::run() { 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); 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; INT_PTR result = NULL;
MainDlgInput* input = new MainDlgInput{ this, -1, -1 }; MainDlgInput* input = new MainDlgInput{ this, -1, -1 };
while (result = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOGMAIN), nullptr, (DLGPROC)mainDlgProc, reinterpret_cast<LPARAM>(input))) { while (result = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOGMAIN), nullptr, reinterpret_cast<DLGPROC>(mainDlgProc), reinterpret_cast<LPARAM>(input))) {
//Then create a Chat with the collected input... //Then create a Chat with the collected input
MainDlgOutput* output = reinterpret_cast<MainDlgOutput*>(result); MainDlgOutput* output = reinterpret_cast<MainDlgOutput*>(result);
const auto [address, screenname, x, y] = *output; const auto [address, screenname, x, y] = *output;
delete output; delete output;
{ {
Chat chat(address, screenname); 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 }; input = new MainDlgInput{ this, x, y };
} }
@ -134,13 +134,13 @@ namespace wc {
case WM_INITDIALOG: { case WM_INITDIALOG: {
MainDlgInput* in = reinterpret_cast<MainDlgInput*>(lParam); MainDlgInput* in = reinterpret_cast<MainDlgInput*>(lParam);
auto [appTemp, xPos, yPos] = *in; auto [appTemp, xPos, yPos] = *in;
app = appTemp;
delete in; delete in;
app = appTemp;
SetWindowText(dlg, app->m_appName.c_str()); SetWindowText(dlg, app->m_appName.c_str());
SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN)))); SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN))));
if (xPos < 0) { if (xPos == -1 && yPos == -1) {
POINT pt = { }; POINT pt = { };
GetCursorPos(&pt); GetCursorPos(&pt);
MONITORINFO mi = { }; MONITORINFO mi = { };
@ -171,7 +171,7 @@ namespace wc {
int addressSize = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITADDRESS)); int addressSize = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITADDRESS));
int screennameSize = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITSCREENNAME)); int screennameSize = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITSCREENNAME));
if (!addressSize || !screennameSize) { 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<LPARAM>(&balloon)); SendDlgItemMessage(dlg, addressSize ? IDC_EDITSCREENNAME : IDC_EDITADDRESS, EM_SHOWBALLOONTIP, NULL, reinterpret_cast<LPARAM>(&balloon));
return TRUE; return TRUE;
} }
@ -204,7 +204,7 @@ namespace wc {
return FALSE; return FALSE;
case WM_HOTKEY: case WM_HOTKEY:
if (wParam != 1) if (wParam != 1 || GetForegroundWindow() != dlg)
return FALSE; return FALSE;
[[fallthrough]]; [[fallthrough]];
case WM_CLOSE: case WM_CLOSE:

View File

@ -2,19 +2,43 @@
#include "Chat.h" #include "Chat.h"
#include "StrConv.h" #include "StrConv.h"
#include "../resource.h"
#define IDT_CHECKCONN 1
namespace wc { namespace wc {
struct ConnDlgInput {
Chat* chat;
int xPos, yPos;
};
Chat::Chat(std::wstring address, std::wstring screenname) Chat::Chat(std::wstring address, std::wstring screenname)
: m_address(address) : m_address(address)
, m_screenname(screenname) , 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<DLGPROC>(connDlgProc), reinterpret_cast<LPARAM>(input));
netThread.join();
}
void Chat::runNetThread() {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
addrinfo* destInfo = nullptr; addrinfo* destInfo = nullptr;
if (getaddrinfo(toStr(m_address).c_str(), "9430", nullptr, &destInfo) != 0) { 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); MessageBox(nullptr, L"Error: Could not resolve host or invalid address!", L"Error", MB_ICONERROR);
m_connectionError = true;
return; return;
} }
@ -22,42 +46,21 @@ namespace wc {
if (sock == INVALID_SOCKET) { if (sock == INVALID_SOCKET) {
MessageBox(nullptr, L"Error: could not create network socket!", L"Error", MB_ICONERROR); MessageBox(nullptr, L"Error: could not create network socket!", L"Error", MB_ICONERROR);
freeaddrinfo(destInfo); freeaddrinfo(destInfo);
m_connectionError = true;
return; return;
} }
if (connect(sock, destInfo->ai_addr, static_cast<int>(destInfo->ai_addrlen)) != 0) { if (connect(sock, destInfo->ai_addr, static_cast<int>(destInfo->ai_addrlen)) != 0) {
int errorCode = WSAGetLastError(); std::wstring errorStr = getErrorString();
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;
}
MessageBox(nullptr, std::format(L"Error: Could not connect - {}", errorStr).c_str(), L"Error", MB_ICONERROR); MessageBox(nullptr, std::format(L"Error: Could not connect - {}", errorStr).c_str(), L"Error", MB_ICONERROR);
freeaddrinfo(destInfo); freeaddrinfo(destInfo);
closesocket(sock); closesocket(sock);
m_connectionError = true;
return; return;
} }
freeaddrinfo(destInfo); freeaddrinfo(destInfo);
m_connected = true;
std::string data; std::string data;
while (data != "end") { while (data != "end") {
@ -68,6 +71,63 @@ namespace wc {
closesocket(sock); 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<ConnDlgInput*>(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() { Chat::~Chat() {
} }

View File

@ -8,11 +8,17 @@ namespace wc {
public: public:
Chat(std::wstring address, std::wstring screenname); Chat(std::wstring address, std::wstring screenname);
void run(); void run(int xPos, int yPos);
~Chat(); ~Chat();
private: 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_address;
const std::wstring m_screenname; const std::wstring m_screenname;
bool m_connected;
bool m_connectionError;
}; };
} }