Connect to any port and add quick start
This commit is contained in:
parent
d232437f08
commit
8f66edfa04
Binary file not shown.
@ -22,16 +22,18 @@
|
||||
#define IDC_BUTTONSEND 1014
|
||||
#define IDC_BUTTONDISCONNECT 1015
|
||||
#define IDC_STATICREMOTEINFO 1017
|
||||
#define IDC_STATICLISTENPORT 1018
|
||||
#define ID_FILE_EXIT 40001
|
||||
#define ID_HELP_ABOUT 40002
|
||||
#define ID_HELP_QUCKSTART 40003
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 113
|
||||
#define _APS_NEXT_COMMAND_VALUE 40003
|
||||
#define _APS_NEXT_CONTROL_VALUE 1018
|
||||
#define _APS_NEXT_COMMAND_VALUE 40004
|
||||
#define _APS_NEXT_CONTROL_VALUE 1019
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
@ -20,17 +20,19 @@ namespace wc {
|
||||
|
||||
struct MainDlgOutput {
|
||||
std::wstring address;
|
||||
std::wstring port;
|
||||
std::wstring screenname;
|
||||
int xPos, yPos;
|
||||
SOCKET inSock;
|
||||
};
|
||||
|
||||
Application::Application(std::string& appName, std::string& appVersion)
|
||||
Application::Application(const std::string& appName, const std::string& appVersion, const int defaultPort)
|
||||
: m_appName(appName.begin(), appName.end())
|
||||
, m_appVersion(appVersion.begin(), appVersion.end())
|
||||
, m_running(true)
|
||||
, m_defaultPort(defaultPort)
|
||||
, m_listenPort()
|
||||
, m_running(false)
|
||||
, m_inSocket(INVALID_SOCKET)
|
||||
, m_inAddress()
|
||||
{
|
||||
std::wcout << std::format(L"{} {}\n", m_appName, m_appVersion);
|
||||
|
||||
@ -51,17 +53,21 @@ namespace wc {
|
||||
//First, start a thread to listen for incoming connections
|
||||
std::thread listenThread(&Application::startListen, this);
|
||||
|
||||
//And wait until we are successfully listening
|
||||
while (!m_running)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
//Then, run the main dialog to get needed input for outgoing connections
|
||||
INT_PTR result = NULL;
|
||||
MainDlgInput* input = new MainDlgInput{ this, -1, -1 };
|
||||
while (result = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOGMAIN), nullptr, reinterpret_cast<DLGPROC>(mainDlgProc), reinterpret_cast<LPARAM>(input))) {
|
||||
//Create a Chat with the collected input or the incoming connection
|
||||
MainDlgOutput* output = reinterpret_cast<MainDlgOutput*>(result);
|
||||
const auto [address, screenname, x, y, inSocket] = *output;
|
||||
const auto [address, port, screenname, x, y, inSocket] = *output;
|
||||
delete output;
|
||||
|
||||
{
|
||||
Chat chat(address, screenname);
|
||||
Chat chat(address, port, screenname);
|
||||
chat.run(x, y, inSocket);
|
||||
}
|
||||
|
||||
@ -74,9 +80,6 @@ namespace wc {
|
||||
}
|
||||
|
||||
void Application::startListen() {
|
||||
addrinfo* hostInfo = nullptr;
|
||||
getaddrinfo("::", "9430", nullptr, &hostInfo);
|
||||
|
||||
SOCKET sock = socket(AF_INET6, SOCK_STREAM, NULL);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
MessageBox(nullptr, L"Error: could not create network socket!", L"Error", MB_ICONERROR);
|
||||
@ -87,16 +90,23 @@ namespace wc {
|
||||
unsigned long no = 0;
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>(&no), sizeof(no));
|
||||
|
||||
while (bind(sock, hostInfo->ai_addr, static_cast<int>(hostInfo->ai_addrlen)) != 0) {
|
||||
freeaddrinfo(hostInfo);
|
||||
getaddrinfo("::", "9431", nullptr, &hostInfo);
|
||||
}
|
||||
int tryPort = m_defaultPort - 1;
|
||||
addrinfo* hostInfo = nullptr;
|
||||
|
||||
do {
|
||||
freeaddrinfo(hostInfo);
|
||||
tryPort++;
|
||||
getaddrinfo("::", std::to_string(tryPort).c_str(), nullptr, &hostInfo);
|
||||
} while (bind(sock, hostInfo->ai_addr, static_cast<int>(hostInfo->ai_addrlen)) != 0);
|
||||
|
||||
m_listenPort = tryPort;
|
||||
freeaddrinfo(hostInfo);
|
||||
listen(sock, 1);
|
||||
|
||||
ioctlsocket(sock, FIONBIO, &yes);
|
||||
|
||||
m_running = true;
|
||||
|
||||
sockaddr_in6 remoteAddr = { };
|
||||
int remoteSize = sizeof(remoteAddr);
|
||||
SOCKET conSock = INVALID_SOCKET;
|
||||
@ -160,8 +170,9 @@ namespace wc {
|
||||
HFONT font = CreateFontIndirect(&lFont);
|
||||
SendMessage(GetDlgItem(dlg, IDC_STATICTITLE), WM_SETFONT, reinterpret_cast<LPARAM>(font), NULL);
|
||||
SetDlgItemText(dlg, IDC_STATICDESC, L"A simple Windows chat app");
|
||||
SendDlgItemMessage(dlg, IDC_EDITADDRESS, EM_SETCUEBANNER, TRUE, reinterpret_cast<LPARAM>(L"Address"));
|
||||
SendDlgItemMessage(dlg, IDC_EDITADDRESS, EM_SETCUEBANNER, TRUE, reinterpret_cast<LPARAM>(L"Address(/Port)"));
|
||||
SendDlgItemMessage(dlg, IDC_EDITSCREENNAME, EM_SETCUEBANNER, TRUE, reinterpret_cast<LPARAM>(L"User"));
|
||||
SetDlgItemText(dlg, IDC_STATICLISTENPORT, std::format(L"Listening on port {}", app->m_listenPort).c_str());
|
||||
|
||||
SetTimer(dlg, IDT_CHECKINCONN, 100, nullptr);
|
||||
|
||||
@ -186,17 +197,43 @@ namespace wc {
|
||||
screenname.resize(screennameSize);
|
||||
GetDlgItemText(dlg, IDC_EDITSCREENNAME, screenname.data(), static_cast<int>(screenname.size() + 1));
|
||||
|
||||
//Check port if present
|
||||
std::wstring port;
|
||||
size_t portStart = address.find(L"/");
|
||||
if (portStart != std::wstring::npos) {
|
||||
port = address.substr(portStart + 1);
|
||||
address.resize(portStart);
|
||||
bool isANumber = std::all_of(port.begin(), port.end(), [](wchar_t in) {return std::isdigit(in); });
|
||||
|
||||
if (port.empty() || !isANumber || std::stoi(port) < 1024 || std::stoi(port) > 49151) {
|
||||
EDITBALLOONTIP balloon = { .cbStruct = sizeof(balloon), .pszTitle = L"Alert", .pszText = L"An invalid port was entered." };
|
||||
SendDlgItemMessage(dlg, IDC_EDITADDRESS, EM_SHOWBALLOONTIP, NULL, reinterpret_cast<LPARAM>(&balloon));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
port = std::to_wstring(app->m_defaultPort);
|
||||
|
||||
RECT dlgRect = { };
|
||||
GetWindowRect(dlg, &dlgRect);
|
||||
EndDialog(dlg, reinterpret_cast<INT_PTR>(new MainDlgOutput{ address, screenname, dlgRect.left, dlgRect.top, INVALID_SOCKET }));
|
||||
EndDialog(dlg, reinterpret_cast<INT_PTR>(new MainDlgOutput{ address, port, screenname, dlgRect.left, dlgRect.top, INVALID_SOCKET }));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case ID_HELP_ABOUT: {
|
||||
MessageBox(dlg, std::format(L"{} {}\nGrayson Riffe 2023", app->m_appName, app->m_appVersion).c_str(), L"About", MB_OK);
|
||||
case ID_HELP_QUCKSTART: {
|
||||
std::wstring helpStr = L"To start a chat, start the program on both computers\n"
|
||||
"and enter the IP address or hostname of one into the other's address box.\n\n"
|
||||
"If the program is not listening on the default port of {}, the\n"
|
||||
"other computer must enter this port when connecting to it.";
|
||||
std::wstring defPortStr = std::to_wstring(app->m_defaultPort);
|
||||
MessageBox(dlg, std::vformat(helpStr, std::make_wformat_args(defPortStr)).c_str(), L"Quick Start", MB_OK);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case ID_HELP_ABOUT:
|
||||
MessageBox(dlg, std::format(L"{} {}\nGrayson Riffe 2023", app->m_appName, app->m_appVersion).c_str(), L"About", MB_OK);
|
||||
return TRUE;
|
||||
|
||||
case IDC_BUTTONEXIT:
|
||||
case ID_FILE_EXIT:
|
||||
case IDCANCEL: //Escape key press
|
||||
@ -225,7 +262,7 @@ namespace wc {
|
||||
|
||||
MainDlgOutput* out = reinterpret_cast<MainDlgOutput*>(result);
|
||||
|
||||
EndDialog(dlg, reinterpret_cast<INT_PTR>(new MainDlgOutput{ app->m_inAddress, out->screenname, dlgRect.left, dlgRect.top, tempSock }));
|
||||
EndDialog(dlg, reinterpret_cast<INT_PTR>(new MainDlgOutput{ app->m_inAddress, std::wstring(), out->screenname, dlgRect.left, dlgRect.top, tempSock }));
|
||||
delete out;
|
||||
return TRUE;
|
||||
}
|
||||
@ -269,7 +306,7 @@ namespace wc {
|
||||
|
||||
std::wstring buffer(inputLength, 0);
|
||||
GetDlgItemText(dlg, IDC_EDITSCREENNAME, buffer.data(), static_cast<int>(buffer.size() + 1));
|
||||
EndDialog(dlg, reinterpret_cast<INT_PTR>(new MainDlgOutput{ std::wstring(), buffer, NULL, NULL, INVALID_SOCKET }));
|
||||
EndDialog(dlg, reinterpret_cast<INT_PTR>(new MainDlgOutput{ std::wstring(), std::wstring(), buffer, NULL, NULL, INVALID_SOCKET }));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
namespace wc {
|
||||
class Application {
|
||||
public:
|
||||
Application(std::string& appName, std::string& appVersion);
|
||||
Application(const std::string& appName, const std::string& appVersion, const int defaultPort);
|
||||
|
||||
void run();
|
||||
|
||||
@ -19,6 +19,8 @@ namespace wc {
|
||||
|
||||
const std::wstring m_appName;
|
||||
const std::wstring m_appVersion;
|
||||
const int m_defaultPort;
|
||||
int m_listenPort;
|
||||
bool m_running;
|
||||
|
||||
std::atomic<SOCKET> m_inSocket;
|
||||
|
@ -13,8 +13,9 @@ namespace wc {
|
||||
int xPos, yPos;
|
||||
};
|
||||
|
||||
Chat::Chat(std::wstring address, std::wstring screenname)
|
||||
Chat::Chat(std::wstring address, std::wstring port, std::wstring screenname)
|
||||
: m_address(address)
|
||||
, m_port(port)
|
||||
, m_screenname(screenname)
|
||||
, m_remoteScreenname(1000, 0)
|
||||
, m_connected(false)
|
||||
@ -45,7 +46,7 @@ namespace wc {
|
||||
SOCKET sock = inSocket;
|
||||
if (sock == INVALID_SOCKET) {
|
||||
addrinfo* destInfo = nullptr;
|
||||
if (getaddrinfo(toStr(m_address).c_str(), "9430", nullptr, &destInfo) != 0) {
|
||||
if (getaddrinfo(toStr(m_address).c_str(), toStr(m_port).c_str(), nullptr, &destInfo) != 0) {
|
||||
MessageBox(nullptr, L"Error: Could not resolve host or invalid address!", L"Error", MB_ICONERROR);
|
||||
m_connectionError = true;
|
||||
return;
|
||||
@ -128,7 +129,7 @@ namespace wc {
|
||||
break;
|
||||
|
||||
case WSAECONNREFUSED:
|
||||
out = L"Connection refused (WinChat may not be running on remote host)";
|
||||
out = L"Connection refused";
|
||||
break;
|
||||
|
||||
case WSAENETUNREACH:
|
||||
@ -158,7 +159,7 @@ namespace wc {
|
||||
|
||||
SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN))));
|
||||
SetWindowPos(dlg, nullptr, in->xPos + 100, in->yPos + 100, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
SetDlgItemText(dlg, IDC_STATICADDRESS, chat->m_address.c_str());
|
||||
SetDlgItemText(dlg, IDC_STATICADDRESS, std::format(L"{} on port {}", chat->m_address, chat->m_port).c_str());
|
||||
SendDlgItemMessage(dlg, IDC_PROGRESS, PBM_SETMARQUEE, TRUE, NULL);
|
||||
|
||||
SetTimer(dlg, IDT_CHECKCONN, 100, nullptr);
|
||||
@ -184,7 +185,7 @@ namespace wc {
|
||||
ChatDlgInput* in = reinterpret_cast<ChatDlgInput*>(lParam);
|
||||
chat = in->chatPtr;
|
||||
|
||||
SetWindowText(dlg, std::format(L"{} - WinChat", chat->m_remoteScreenname).c_str());
|
||||
SetWindowText(dlg, std::format(L"Chat with {}", chat->m_remoteScreenname).c_str());
|
||||
SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN))));
|
||||
SetWindowPos(dlg, nullptr, in->xPos - 50, in->yPos - 50, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
SendDlgItemMessage(dlg, IDC_EDITCHATINPUT, EM_SETCUEBANNER, TRUE, reinterpret_cast<LPARAM>(L"Message"));
|
||||
@ -210,7 +211,7 @@ namespace wc {
|
||||
GetDlgItemText(dlg, IDC_EDITCHATINPUT, buffer.data(), static_cast<int>(buffer.size() + 1));
|
||||
chat->m_sendQueue.push(buffer);
|
||||
|
||||
chat->addMessage(dlg, std::format(L"{} - {}", chat->m_screenname, buffer).c_str());
|
||||
chat->addMessage(dlg, std::format(L"{} - {}", chat->m_screenname, buffer));
|
||||
|
||||
SetDlgItemText(dlg, IDC_EDITCHATINPUT, L"");
|
||||
|
||||
@ -233,7 +234,7 @@ namespace wc {
|
||||
std::wstring remoteStr;
|
||||
while (!chat->m_recvQueue.empty()) {
|
||||
remoteStr = chat->m_recvQueue.pop();
|
||||
chat->addMessage(dlg, std::format(L"{} - {}", chat->m_remoteScreenname, remoteStr).c_str());
|
||||
chat->addMessage(dlg, std::format(L"{} - {}", chat->m_remoteScreenname, remoteStr));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -8,7 +8,7 @@
|
||||
namespace wc {
|
||||
class Chat {
|
||||
public:
|
||||
Chat(std::wstring address, std::wstring screenname);
|
||||
Chat(std::wstring address, std::wstring port, std::wstring screenname);
|
||||
|
||||
void run(int xPos, int yPos, SOCKET socket);
|
||||
|
||||
@ -21,6 +21,7 @@ namespace wc {
|
||||
void addMessage(HWND dlg, std::wstring str);
|
||||
|
||||
const std::wstring m_address;
|
||||
const std::wstring m_port;
|
||||
const std::wstring m_screenname;
|
||||
std::wstring m_remoteScreenname;
|
||||
bool m_connected;
|
||||
|
@ -3,13 +3,12 @@
|
||||
#include "Application.h"
|
||||
|
||||
#define APPNAME "WinChat"
|
||||
#define DEFAULTPORT 9430
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string appName = APPNAME;
|
||||
std::string appVer = APPVERSION;
|
||||
|
||||
{
|
||||
wc::Application app(appName, appVer);
|
||||
wc::Application app(APPNAME, APPVERSION, DEFAULTPORT);
|
||||
app.run();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user