Compare commits
No commits in common. "stable" and "v0.1.0" have entirely different histories.
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
.vs/
|
||||
build/
|
||||
version.h
|
||||
*.aps
|
@ -1,48 +0,0 @@
|
||||
@echo off
|
||||
|
||||
echo [Pre Build] Startup
|
||||
|
||||
::Set Version
|
||||
echo [Pre Build] Setting version...
|
||||
|
||||
::First make sure git is in the path
|
||||
where git >nul 2>&1
|
||||
if %errorlevel% neq 0 goto noGit
|
||||
goto yesGit
|
||||
|
||||
:noGit
|
||||
echo [Pre Build] Error: git not found on PATH!
|
||||
exit 1
|
||||
|
||||
::We have git on the command line, so set the version string
|
||||
:yesGit
|
||||
git describe HEAD > temp1
|
||||
git branch --show-current > temp2
|
||||
set /p commit= < temp1
|
||||
set /p branch= < temp2
|
||||
del temp1
|
||||
del temp2
|
||||
|
||||
::If the current branch is stable, don't include it in the version string
|
||||
if "%branch%" == "stable" goto noBranch
|
||||
|
||||
set version=%commit%+%branch%
|
||||
goto testOutput
|
||||
|
||||
:noBranch
|
||||
set version=%commit%
|
||||
|
||||
::Don't touch the version file if it's already up to date
|
||||
:testOutput
|
||||
set /p oldVersion= < src\version.h
|
||||
if "%oldVersion%" == "#define APPVERSION "%version%"" goto sameVersion
|
||||
|
||||
echo #define APPVERSION "%version%"> src\version.h
|
||||
goto continue
|
||||
|
||||
:sameVersion
|
||||
echo [Pre Build] Same version
|
||||
|
||||
:continue
|
||||
echo [Pre Build] Exit
|
||||
exit
|
Binary file not shown.
@ -1,130 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{807f7b0f-884d-4a96-8a2b-57cd89232f61}</ProjectGuid>
|
||||
<RootNamespace>WinChat</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(ProjectDir)build\bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)build\int\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(ProjectDir)build\bin\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)build\int\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>PreBuild.bat</Command>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PreBuildEvent>
|
||||
<Command>PreBuild.bat</Command>
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\Application.cpp" />
|
||||
<ClCompile Include="src\Chat.cpp" />
|
||||
<ClCompile Include="src\main.cpp" />
|
||||
<ClCompile Include="src\pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</PrecompiledHeaderFile>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\StrConv.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="src\Application.h" />
|
||||
<ClInclude Include="src\Chat.h" />
|
||||
<ClInclude Include="src\pch.h" />
|
||||
<ClInclude Include="src\StrConv.h" />
|
||||
<ClInclude Include="src\TSQueue.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="WinChat.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="res\wc.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -1,64 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\Application.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<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">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<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>
|
||||
<ClInclude Include="src\TSQueue.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="WinChat.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="res\wc.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ShowAllFiles>true</ShowAllFiles>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LocalDebuggerWorkingDirectory>$(OutDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
</Project>
|
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB |
@ -1,39 +0,0 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by WinChat.rc
|
||||
//
|
||||
#define IDD_DIALOGMAIN 101
|
||||
#define IDR_MENUMAIN 104
|
||||
#define IDI_ICONMAIN 106
|
||||
#define IDD_DIALOGCONNECTING 107
|
||||
#define IDD_DIALOGCHAT 109
|
||||
#define IDD_DIALOGACCEPTCONNECTION 111
|
||||
#define IDC_STATICTITLE 1001
|
||||
#define IDC_BUTTONEXIT 1003
|
||||
#define IDC_BUTTONCONNECT 1005
|
||||
#define IDC_EDITADDRESS 1006
|
||||
#define IDC_ICONMAIN 1007
|
||||
#define IDC_EDITSCREENNAME 1008
|
||||
#define IDC_STATICDESC 1009
|
||||
#define IDC_STATICADDRESS 1010
|
||||
#define IDC_PROGRESS 1011
|
||||
#define IDC_EDITCHATDISPLAY 1012
|
||||
#define IDC_EDITCHATINPUT 1013
|
||||
#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 40004
|
||||
#define _APS_NEXT_CONTROL_VALUE 1019
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
@ -1,334 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "Application.h"
|
||||
|
||||
#include "../resource.h"
|
||||
#include "Chat.h"
|
||||
#include "StrConv.h"
|
||||
|
||||
//This pragma enables visual styles, which makes dialogs and their controls look modern.
|
||||
#pragma comment(linker,"\"/manifestdependency:type='win32' \
|
||||
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
|
||||
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||
|
||||
#define IDT_CHECKINCONN 1
|
||||
|
||||
namespace wc {
|
||||
struct MainDlgInput {
|
||||
Application* appPtr;
|
||||
int xPos, yPos;
|
||||
};
|
||||
|
||||
struct MainDlgOutput {
|
||||
std::wstring address;
|
||||
std::wstring port;
|
||||
std::wstring screenname;
|
||||
int xPos, yPos;
|
||||
SOCKET inSock;
|
||||
};
|
||||
|
||||
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_defaultPort(defaultPort)
|
||||
, m_listenPort()
|
||||
, m_running(false)
|
||||
, m_inSocket(INVALID_SOCKET)
|
||||
{
|
||||
std::wcout << std::format(L"{} {}\n", m_appName, m_appVersion);
|
||||
|
||||
//Initialize Windows Sockets 2
|
||||
WSADATA data = { };
|
||||
if (WSAStartup(MAKEWORD(2, 2), &data) != 0) {
|
||||
MessageBox(nullptr, L"Error: could not initialize WinSock 2!", L"Error", MB_ICONERROR);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2) {
|
||||
MessageBox(nullptr, L"Error: WinSock version 2.2 not available!", L"Error", MB_ICONERROR);
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::run() {
|
||||
//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, port, screenname, x, y, inSocket] = *output;
|
||||
delete output;
|
||||
|
||||
{
|
||||
Chat chat(address, port, screenname);
|
||||
chat.run(x, y, inSocket);
|
||||
}
|
||||
|
||||
//And repeat until the user exits from the main dialog
|
||||
input = new MainDlgInput{ this, x, y };
|
||||
}
|
||||
|
||||
m_running = false;
|
||||
listenThread.join();
|
||||
}
|
||||
|
||||
void Application::startListen() {
|
||||
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);
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
unsigned long yes = 1;
|
||||
unsigned long no = 0;
|
||||
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>(&no), sizeof(no));
|
||||
|
||||
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;
|
||||
int errorCode = 0;
|
||||
while (m_running) {
|
||||
conSock = accept(sock, reinterpret_cast<sockaddr*>(&remoteAddr), &remoteSize);
|
||||
errorCode = WSAGetLastError();
|
||||
if (errorCode && errorCode != WSAEWOULDBLOCK) {
|
||||
MessageBox(nullptr, L"Error: could not accept connection!", L"Error", MB_ICONERROR);
|
||||
std::exit(1);
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
if (errorCode == WSAEWOULDBLOCK)
|
||||
continue;
|
||||
|
||||
std::string remoteStr(INET6_ADDRSTRLEN, 0);
|
||||
inet_ntop(AF_INET6, &remoteAddr.sin6_addr, remoteStr.data(), INET6_ADDRSTRLEN);
|
||||
remoteStr.resize(remoteStr.find_first_of('\0', 0));
|
||||
|
||||
m_inAddress = toWideStr(remoteStr);
|
||||
m_inSocket = conSock;
|
||||
|
||||
//If the socket isn't dealt with by the other thread in time, we most likely already have a connection
|
||||
//This also prevents connecting to yourself
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
if (m_inSocket != INVALID_SOCKET) {
|
||||
closesocket(m_inSocket);
|
||||
m_inSocket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
closesocket(sock);
|
||||
}
|
||||
|
||||
BOOL CALLBACK Application::mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
static Application* app = nullptr;
|
||||
|
||||
switch (msg) {
|
||||
case WM_INITDIALOG: {
|
||||
MainDlgInput* in = reinterpret_cast<MainDlgInput*>(lParam);
|
||||
auto [appPtr, xPos, yPos] = *in;
|
||||
delete in;
|
||||
app = appPtr;
|
||||
|
||||
SetWindowText(dlg, app->m_appName.c_str());
|
||||
SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN))));
|
||||
|
||||
if (xPos == -1 && yPos == -1) {
|
||||
POINT pt = { };
|
||||
GetCursorPos(&pt);
|
||||
MONITORINFO mi = { };
|
||||
mi.cbSize = sizeof(mi);
|
||||
GetMonitorInfo(MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST), &mi);
|
||||
xPos = mi.rcMonitor.left + 100, yPos = mi.rcMonitor.top + 100;
|
||||
}
|
||||
|
||||
SetWindowPos(dlg, nullptr, xPos, yPos, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
SetDlgItemText(dlg, IDC_STATICTITLE, app->m_appName.c_str());
|
||||
LOGFONT lFont = { .lfHeight = 50 };
|
||||
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(/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);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam)) {
|
||||
case IDC_BUTTONCONNECT: {
|
||||
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 screen name." };
|
||||
SendDlgItemMessage(dlg, addressSize ? IDC_EDITSCREENNAME : IDC_EDITADDRESS, EM_SHOWBALLOONTIP, NULL, reinterpret_cast<LPARAM>(&balloon));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
std::wstring address;
|
||||
address.resize(addressSize);
|
||||
GetDlgItemText(dlg, IDC_EDITADDRESS, address.data(), static_cast<int>(address.size() + 1));
|
||||
std::wstring screenname;
|
||||
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, port, screenname, dlgRect.left, dlgRect.top, INVALID_SOCKET }));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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: {
|
||||
std::wstring aboutStr = L"{} {}\nCopyright Grayson Riffe 2023\ngraysonriffe.com";
|
||||
MessageBox(dlg, std::vformat(aboutStr, std::make_wformat_args(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
|
||||
PostMessage(dlg, WM_CLOSE, NULL, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
case WM_TIMER:
|
||||
if (wParam == IDT_CHECKINCONN && app->m_inSocket != INVALID_SOCKET) {
|
||||
KillTimer(dlg, IDT_CHECKINCONN);
|
||||
SOCKET tempSock = app->m_inSocket;
|
||||
app->m_inSocket = INVALID_SOCKET;
|
||||
RECT dlgRect = { };
|
||||
GetWindowRect(dlg, &dlgRect);
|
||||
MainDlgInput acceptInput = { app, dlgRect.left, dlgRect.top };
|
||||
|
||||
INT_PTR result = DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOGACCEPTCONNECTION), dlg, reinterpret_cast<DLGPROC>(acceptDlgProc), reinterpret_cast<LPARAM>(&acceptInput));
|
||||
|
||||
if (result == IDCANCEL) {
|
||||
closesocket(tempSock);
|
||||
SetTimer(dlg, IDT_CHECKINCONN, 100, nullptr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MainDlgOutput* out = reinterpret_cast<MainDlgOutput*>(result);
|
||||
|
||||
EndDialog(dlg, reinterpret_cast<INT_PTR>(new MainDlgOutput{ app->m_inAddress, std::wstring(), out->screenname, dlgRect.left, dlgRect.top, tempSock }));
|
||||
delete out;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
case WM_CLOSE:
|
||||
EndDialog(dlg, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CALLBACK Application::acceptDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
static Application* app = nullptr;
|
||||
|
||||
switch (msg) {
|
||||
case WM_INITDIALOG: {
|
||||
MainDlgInput* in = reinterpret_cast<MainDlgInput*>(lParam);
|
||||
app = in->appPtr;
|
||||
|
||||
SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast<LPARAM>(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN))));
|
||||
SetWindowPos(dlg, nullptr, in->xPos + 30, in->yPos + 30, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
|
||||
|
||||
SetDlgItemText(dlg, IDC_STATICREMOTEINFO, app->m_inAddress.c_str());
|
||||
SendDlgItemMessage(dlg, IDC_EDITSCREENNAME, EM_SETCUEBANNER, TRUE, reinterpret_cast<LPARAM>(L"User"));
|
||||
|
||||
//Get the attention of the user
|
||||
FLASHWINFO fw = { .cbSize = sizeof(fw), .hwnd = GetParent(dlg), .dwFlags = FLASHW_TRAY | FLASHW_TIMERNOFG };
|
||||
FlashWindowEx(&fw);
|
||||
MessageBeep(MB_OK);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam)) {
|
||||
case IDOK: {
|
||||
int inputLength = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITSCREENNAME));
|
||||
if (!inputLength) {
|
||||
EDITBALLOONTIP balloon = { .cbStruct = sizeof(balloon), .pszTitle = L"Alert", .pszText = L"You must enter a screen name." };
|
||||
SendDlgItemMessage(dlg, IDC_EDITSCREENNAME, EM_SHOWBALLOONTIP, NULL, reinterpret_cast<LPARAM>(&balloon));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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(), std::wstring(), buffer, NULL, NULL, INVALID_SOCKET }));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case IDCANCEL:
|
||||
EndDialog(dlg, wParam);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Application::~Application() {
|
||||
WSACleanup();
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace wc {
|
||||
class Application {
|
||||
public:
|
||||
Application(const std::string& appName, const std::string& appVersion, const int defaultPort);
|
||||
|
||||
void run();
|
||||
|
||||
~Application();
|
||||
private:
|
||||
void startListen();
|
||||
static BOOL CALLBACK mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
static BOOL CALLBACK acceptDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
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;
|
||||
std::wstring m_inAddress;
|
||||
};
|
||||
}
|
@ -1,272 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "Chat.h"
|
||||
|
||||
#include "StrConv.h"
|
||||
#include "../resource.h"
|
||||
|
||||
#define IDT_CHECKCONN 2
|
||||
#define IDT_UPDATECHAT 3
|
||||
|
||||
namespace wc {
|
||||
struct ChatDlgInput {
|
||||
Chat* chatPtr;
|
||||
int xPos, yPos;
|
||||
};
|
||||
|
||||
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)
|
||||
, m_connectionError(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Chat::run(int xPos, int yPos, SOCKET socket) {
|
||||
//Run net thread to connect and communicate
|
||||
std::thread netThread(&Chat::runNetThread, this, socket);
|
||||
|
||||
//Show connection dialog until net thread connects unless the listen thread already did that
|
||||
ChatDlgInput input = { this, xPos, yPos };
|
||||
if (!m_connected)
|
||||
DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOGCONNECTING), nullptr, reinterpret_cast<DLGPROC>(connDlgProc), reinterpret_cast<LPARAM>(&input));
|
||||
|
||||
//Either way now, if we're connected, open the chat window
|
||||
if (m_connected)
|
||||
DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOGCHAT), nullptr, reinterpret_cast<DLGPROC>(chatDlgProc), reinterpret_cast<LPARAM>(&input));
|
||||
|
||||
netThread.join();
|
||||
}
|
||||
|
||||
void Chat::runNetThread(SOCKET inSocket) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
SOCKET sock = inSocket;
|
||||
if (sock == INVALID_SOCKET) {
|
||||
addrinfo* destInfo = nullptr;
|
||||
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;
|
||||
}
|
||||
|
||||
sock = socket(destInfo->ai_family, SOCK_STREAM, NULL);
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
unsigned long yes = 1;
|
||||
unsigned long no = 0;
|
||||
ioctlsocket(sock, FIONBIO, &no);
|
||||
|
||||
//Send and receive screen names
|
||||
send(sock, reinterpret_cast<const char*>(m_screenname.c_str()), static_cast<int>(m_screenname.size()) * sizeof(wchar_t), NULL);
|
||||
int bytesRemoteScreenname = recv(sock, reinterpret_cast<char*>(m_remoteScreenname.data()), 1000, NULL);
|
||||
|
||||
if (!bytesRemoteScreenname || WSAGetLastError() == WSAECONNRESET) {
|
||||
MessageBox(nullptr, L"The remote host denied the connection.", L"Error", MB_ICONERROR);
|
||||
m_connectionError = true;
|
||||
closesocket(sock);
|
||||
return;
|
||||
}
|
||||
|
||||
m_remoteScreenname.resize(bytesRemoteScreenname / 2);
|
||||
ioctlsocket(sock, FIONBIO, &yes);
|
||||
|
||||
m_connected = true;
|
||||
|
||||
std::wstring recvBuffer(2000, 0);
|
||||
std::wstring sendStr;
|
||||
int bytesRecvd = 0;
|
||||
while (m_connected && !m_connectionError) {
|
||||
while (!m_sendQueue.empty()) {
|
||||
sendStr = m_sendQueue.pop();
|
||||
send(sock, reinterpret_cast<const char*>(sendStr.c_str()), static_cast<int>(sendStr.size()) * sizeof(wchar_t), NULL);
|
||||
}
|
||||
|
||||
bytesRecvd = recv(sock, reinterpret_cast<char*>(recvBuffer.data()), 2000, NULL);
|
||||
|
||||
if (!bytesRecvd) {
|
||||
m_connected = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
||||
recvBuffer.resize(bytesRecvd / 2);
|
||||
m_recvQueue.push(recvBuffer);
|
||||
recvBuffer.assign(2000, 0);
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
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";
|
||||
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: {
|
||||
ChatDlgInput* in = reinterpret_cast<ChatDlgInput*>(lParam);
|
||||
chat = in->chatPtr;
|
||||
|
||||
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, 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);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case WM_TIMER:
|
||||
if (wParam == IDT_CHECKCONN && (chat->m_connected || chat->m_connectionError)) {
|
||||
EndDialog(dlg, 0);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CALLBACK Chat::chatDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
static Chat* chat = nullptr;
|
||||
|
||||
switch (msg) {
|
||||
case WM_INITDIALOG: {
|
||||
ChatDlgInput* in = reinterpret_cast<ChatDlgInput*>(lParam);
|
||||
chat = in->chatPtr;
|
||||
|
||||
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"));
|
||||
|
||||
SetDlgItemText(dlg, IDC_EDITCHATDISPLAY, std::format(L"Connected to {} at {}", chat->m_remoteScreenname, chat->m_address).c_str());
|
||||
|
||||
SetTimer(dlg, IDT_UPDATECHAT, 100, nullptr);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam)) {
|
||||
case IDC_BUTTONSEND: {
|
||||
int inputLength = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITCHATINPUT));
|
||||
if (!inputLength) {
|
||||
EDITBALLOONTIP balloon = { .cbStruct = sizeof(balloon), .pszTitle = L"Alert", .pszText = L"Enter your message here." };
|
||||
SendDlgItemMessage(dlg, IDC_EDITCHATINPUT, EM_SHOWBALLOONTIP, NULL, reinterpret_cast<LPARAM>(&balloon));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
std::wstring buffer(inputLength, 0);
|
||||
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));
|
||||
|
||||
SetDlgItemText(dlg, IDC_EDITCHATINPUT, L"");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
case IDC_BUTTONDISCONNECT:
|
||||
case IDCANCEL:
|
||||
PostMessage(dlg, WM_CLOSE, NULL, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
case WM_TIMER:
|
||||
if (wParam == IDT_UPDATECHAT) {
|
||||
if (!chat->m_connected)
|
||||
EndDialog(dlg, 0);
|
||||
|
||||
std::wstring remoteStr;
|
||||
while (!chat->m_recvQueue.empty()) {
|
||||
remoteStr = chat->m_recvQueue.pop();
|
||||
chat->addMessage(dlg, std::format(L"{} - {}", chat->m_remoteScreenname, remoteStr));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
case WM_CLOSE:
|
||||
chat->m_connected = false;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void Chat::addMessage(HWND dlg, std::wstring in) {
|
||||
SCROLLINFO si = { .cbSize = sizeof(si), .fMask = SIF_POS | SIF_PAGE | SIF_RANGE };
|
||||
GetScrollInfo(GetDlgItem(dlg, IDC_EDITCHATDISPLAY), SB_VERT, &si);
|
||||
|
||||
std::wstring buffer(GetWindowTextLength(GetDlgItem(dlg, IDC_EDITCHATDISPLAY)), 0);
|
||||
GetDlgItemText(dlg, IDC_EDITCHATDISPLAY, buffer.data(), static_cast<int>(buffer.size() + 1));
|
||||
buffer += std::format(L"\r\n\r\n{}", in);
|
||||
SetDlgItemText(dlg, IDC_EDITCHATDISPLAY, buffer.c_str());
|
||||
|
||||
//If scrolled to the bottom before adding the text
|
||||
if (static_cast<int>(si.nPage) + si.nPos > si.nMax)
|
||||
SendDlgItemMessage(dlg, IDC_EDITCHATDISPLAY, EM_LINESCROLL, 0, si.nMax);
|
||||
else
|
||||
SendDlgItemMessage(dlg, IDC_EDITCHATDISPLAY, EM_LINESCROLL, 0, si.nPos);
|
||||
}
|
||||
|
||||
Chat::~Chat() {
|
||||
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "TSQueue.h"
|
||||
|
||||
namespace wc {
|
||||
class Chat {
|
||||
public:
|
||||
Chat(std::wstring address, std::wstring port, std::wstring screenname);
|
||||
|
||||
void run(int xPos, int yPos, SOCKET socket);
|
||||
|
||||
~Chat();
|
||||
private:
|
||||
void runNetThread(SOCKET inSocket);
|
||||
std::wstring getErrorString();
|
||||
static BOOL CALLBACK connDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
static BOOL CALLBACK chatDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
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;
|
||||
bool m_connectionError;
|
||||
|
||||
TSQueue<std::wstring> m_sendQueue;
|
||||
TSQueue<std::wstring> m_recvQueue;
|
||||
};
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "StrConv.h"
|
||||
|
||||
namespace wc {
|
||||
std::string toStr(const std::wstring& in) {
|
||||
std::string out;
|
||||
out.resize(in.size() + 1);
|
||||
size_t tempSize = 0;
|
||||
wcstombs_s(&tempSize, out.data(), out.size(), in.c_str(), out.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
std::wstring toWideStr(const std::string& in){
|
||||
return std::wstring(in.begin(), in.end());
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace wc {
|
||||
std::string toStr(const std::wstring& in);
|
||||
std::wstring toWideStr(const std::string& in);
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
namespace wc {
|
||||
template<typename T>
|
||||
class TSQueue {
|
||||
public:
|
||||
TSQueue()
|
||||
: m_m()
|
||||
, m_q()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void push(T t) {
|
||||
std::lock_guard lock(m_m);
|
||||
m_q.push(t);
|
||||
}
|
||||
|
||||
T pop() {
|
||||
std::lock_guard lock(m_m);
|
||||
T t = std::move(m_q.front());
|
||||
m_q.pop();
|
||||
return t;
|
||||
}
|
||||
|
||||
bool empty() {
|
||||
std::lock_guard lock(m_m);
|
||||
return m_q.empty();
|
||||
}
|
||||
|
||||
~TSQueue() { }
|
||||
private:
|
||||
std::mutex m_m;
|
||||
std::queue<T> m_q;
|
||||
};
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
#include "pch.h"
|
||||
#include "version.h"
|
||||
#include "Application.h"
|
||||
|
||||
#define APPNAME "WinChat"
|
||||
#define DEFAULTPORT 9430
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
{
|
||||
wc::Application app(APPNAME, APPVERSION, DEFAULTPORT);
|
||||
app.run();
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1 +0,0 @@
|
||||
#include "pch.h"
|
@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
//STL
|
||||
#include <iostream>
|
||||
#include <format>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <queue>
|
||||
|
||||
//Windows
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <CommCtrl.h>
|
||||
#include <WinSock2.h>
|
||||
#include <WS2tcpip.h>
|
@ -1,25 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.7.34024.191
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinChat", "WinChat\WinChat.vcxproj", "{807F7B0F-884D-4A96-8A2B-57CD89232F61}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{807F7B0F-884D-4A96-8A2B-57CD89232F61}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{807F7B0F-884D-4A96-8A2B-57CD89232F61}.Debug|x64.Build.0 = Debug|x64
|
||||
{807F7B0F-884D-4A96-8A2B-57CD89232F61}.Release|x64.ActiveCfg = Release|x64
|
||||
{807F7B0F-884D-4A96-8A2B-57CD89232F61}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1E26CF85-CF33-4C67-AFFE-1CF6C8612DEA}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Loading…
x
Reference in New Issue
Block a user