Reputation: 331
Problem:
I have a console chat. When I am typing a message and another person sends a message, their message gets printed right after the last character i typed, breaking it.
Example:
"HellAndrew: Hi!o!"
I try to type "Hello!", but "Andrew" interferes with a "Hi!"
How I'd like to handle this:
I was thinking that before printing a message from another client I copy the text I currently have in my standard input, print the other user's text then put the text back in the standard input, a row lower.
I tried using ReadConsoleInput/WriteConsoleInput APIs, but it does not do what I want and adds a significant (>10s) delay.
ReadConsoleInputW(GetStdHandle(STD_INPUT_HANDLE), Inputs, 100, &Count);
//printing
WriteConsoleInputW(GetStdHandle(STD_INPUT_HANDLE), Inputs, 100, &Count);
I cannot spot any other console APIs on MSDN that I can use. Perhaps I am using the others above wrong somehow.
I would appreciate some help in using these. Thanks!
Upvotes: 1
Views: 347
Reputation: 6289
After researching your question, I made the following test and can get the expected effect.
After reading another process string, use WriteConsoleOutputCharacter to write characters in different positions.
WriteConsoleOutputCharacterA(hStdOut, lpszString, strlen(lpszString), { 0,0 }, &dwWritten);
The coordinates of the cursor can be modified according to the actual situation, such as to achieve message scrolling.
Note: You can use SetConsoleCursorPosition
to locate to another position to accept the input stream firstly.
Like this,
coord.X = 0;
coord.Y = 10;
SetConsoleCursorPosition(hStdOut, coord);
ReadFile(hStdIn, strMessage, 256, &dwRead, NULL);
Updated:
This is the sample I tested and I attach a quick gif demo.
Server.cpp
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <thread>
using namespace std;
DWORD dwWritten;
DWORD num;
DWORD dwRead;
char strMessage[256];
HWND h_client;
void td1();
COORD coord;
SHORT i = 0;
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (message == WM_DESTROY) {
PostQuitMessage(0);
}
if (message == WM_COPYDATA)
{
COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;
if (pcds->dwData == 1)
{
CHAR* lpszString = (CHAR*)(pcds->lpData);
WriteConsoleOutputCharacterA(hStdOut, lpszString, strlen(lpszString)-2, { 0,i++ }, &dwWritten);
}
if (i > 24)
{
system("cls");
i = 0;
coord.X = 0;
coord.Y = 25;
SetConsoleCursorPosition(hStdOut, coord);
printf("----------------------------------------------------------------------------------------------------------\n");
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
};
HINSTANCE hinst;
int main() {
HWND hwnd;
hinst = GetModuleHandle(NULL);
// create a window class:
WNDCLASS wc = {};
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = L"win32";
// register class with operating system:
RegisterClass(&wc);
// create and show window:
hwnd = CreateWindow(L"win32", L"Server", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
std::thread t1(td1);
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, SW_SHOW);
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void td1()
{
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
while (1)
{
h_client = FindWindow(L"win32", L"Client");
if (h_client)
{
break;
}
}
coord.X = 0;
coord.Y = 25;
SetConsoleCursorPosition(hStdOut, coord);
printf("----------------------------------------------------------------------------------------------------------");
while (1)
{
coord.X = 0;
coord.Y = 26;
SetConsoleCursorPosition(hStdOut, coord);
memset(strMessage, 0, 256);
ReadFile(hStdIn, strMessage, 256, &dwRead, NULL);
SetConsoleCursorPosition(hStdOut, coord);
for (int i = strlen(strMessage); i > 0; i--)
{
putchar(32);
}
COPYDATASTRUCT cds;
cds.dwData = 1; // can be anything
cds.cbData = sizeof(CHAR) * strlen(strMessage);
cds.lpData = strMessage;
SendMessage(h_client, WM_COPYDATA, (WPARAM)h_client, (LPARAM)(LPVOID)&cds);
}
}
Client.cpp
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <thread>
using namespace std;
DWORD dwWritten;
DWORD dwRead;
char strMessage[256];
HWND h_server;
SHORT i = 0;
COORD coord;
void td1();
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
if (message == WM_DESTROY) {
PostQuitMessage(0);
}
if (message == WM_COPYDATA)
{
COPYDATASTRUCT* pcds = (COPYDATASTRUCT*)lParam;
if (pcds->dwData == 1)
{
CHAR* lpszString = (CHAR*)(pcds->lpData);
int len = pcds->cbData;
WriteConsoleOutputCharacterA(hStdOut, lpszString, len - 2, { 0,i++ }, &dwWritten);
}
if (i > 24)
{
system("cls");
i = 0;
coord.X = 0;
coord.Y = 25;
SetConsoleCursorPosition(hStdOut, coord);
printf("----------------------------------------------------------------------------------------------------------\n");
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
HINSTANCE hinst;
int main() {
HWND hwnd;
hinst = GetModuleHandle(NULL);
// create a window class:
WNDCLASS wc = {};
wc.lpfnWndProc = WndProc;
wc.hInstance = hinst;
wc.lpszClassName = L"win32";
// register class with operating system:
RegisterClass(&wc);
// create and show window:
hwnd = CreateWindow(L"win32", L"Client", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
std::thread t1(td1);
if (hwnd == NULL) {
return 0;
}
ShowWindow(hwnd, SW_SHOW);
MSG msg = {};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void td1()
{
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
while (1)
{
h_server = FindWindow(L"win32", L"Server");
if (h_server)
{
break;
}
}
coord.X = 0;
coord.Y = 25;
SetConsoleCursorPosition(hStdOut, coord);
printf("----------------------------------------------------------------------------------------------------------");
while (1)
{
coord.X = 0;
coord.Y = 26;
SetConsoleCursorPosition(hStdOut, coord);
memset(strMessage, 0, 256);
ReadFile(hStdIn, strMessage, 256, &dwRead, NULL);
SetConsoleCursorPosition(hStdOut, coord);
for (int i = strlen(strMessage); i > 0; i--)
{
putchar(32);
}
COPYDATASTRUCT cds;
cds.dwData = 1; // can be anything
cds.cbData = sizeof(CHAR) * (strlen(strMessage) + 1);
cds.lpData = strMessage;
SendMessage(h_server, WM_COPYDATA, (WPARAM)h_server, (LPARAM)(LPVOID)&cds);
}
}
In fact, the code on the client and server is almost the same. I did it by sending WM_COPYDATA
message.
This only applies to two different processes on the same computer. For the console chat of two machines, it is necessary to rely on the TCP protocol.
Upvotes: 2