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