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.

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

@ -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

@ -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<LPARAM>(input))) {
//Then create a Chat with the collected 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
MainDlgOutput* output = reinterpret_cast<MainDlgOutput*>(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<MainDlgInput*>(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<LPARAM>(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<LPARAM>(&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:

@ -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<DLGPROC>(connDlgProc), reinterpret_cast<LPARAM>(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<int>(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<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() {
}

@ -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;
};
}