I use the function "FillConsoleOutputCharacter" but the application stoped working - c++

I want to make a console application, so i searched for Windows API, and get this code, but it stoped working when i run it, what should i do?
Source code:
#include "windows.h"
#include "stdio.h"
#include <conio.h> //console i/o
int main()
{
HANDLE hOut;
// 获取标准输出设备句柄
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
// 窗口信息
CONSOLE_SCREEN_BUFFER_INFO bInfo;
// 获取窗口信息
GetConsoleScreenBufferInfo(hOut, &bInfo );
printf("\n\nThe soul selects her own society,\n");
printf("Then shuts the door;\n");
printf("On her devine majority\n");
printf("Obtrude no more.\n\n");
_getch();
COORD pos = {0, 0};
// 向窗口中填充字符以获得清屏的效果
FillConsoleOutputCharacter(hOut, ' ', bInfo.dwSize.X * bInfo.dwSize.Y, pos, NULL);
// 关闭标准输出设备句柄
CloseHandle(hOut);
return 0;
}
Could someone tell me how to solve? PLZPLZ!!

You are passing NULL to the lpNumberOfCharsWritten parameter of FillConsoleOutputCharacter(), but the documentation says:
lpNumberOfCharsWritten [out]
A pointer to a variable that receives the number of characters actually written to the console screen buffer.
It does not say that NULL is valid for that parameter. So give it what it wants - a pointer to a variable, eg:
DWORD dwNumWritten;
FillConsoleOutputCharacter(hOut, ' ', bInfo.dwSize.X * bInfo.dwSize.Y, pos, &dwNumWritten);

Related

Can't change console application window title with virtual terminal sequences

I read this article by Microsoft about using of console virtual terminal sequences.
I followed this sequence to change the window title:
ESC ] 2 ; <string> BEL
I also tried:
ESC ] 0 ; <string> BEL
But it doesn't change the title.
This is my code:
#include <stdio.h>
#include <wchar.h>
#include <windows.h>
int main()
{
// https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
// Set output mode to handle virtual terminal sequences
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hOut == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
DWORD dwMode = 0;
if (!GetConsoleMode(hOut, &dwMode))
{
return GetLastError();
}
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(hOut, dwMode))
{
return GetLastError();
}
// Try some Set Graphics Rendition (SGR) terminal escape sequences
wprintf(L"hello");
wprintf(L"\x1b]2;titel\x07");
return 0;
}
It doesn't change the console window title.
The Microsoft document suggests:
Note that these sequences are OSC “Operating system command” sequences, and not a CSI like many of the other sequences listed, and as such starts with “\x1b]”, not “\x1b[”. As OSC sequences, they are ended with a String Terminator represented as and transmitted with ESC \ (0x1B 0x5C). BEL (0x7) may be used instead as the terminator, but the longer form is preferred.
It wouldn't be the first time MS didn't implement something. Try Esc \ - it's worked for me.
That said, I have noticed during debugging that the window title doesn't change immediately and since you terminate the program right after the sequence, you might not be seeing the effect.

How to translate a virtual-key code to char (depending on locale)?

I am playing around with translating user's keystrokes between the different installed languages on their Windows machine.
I found this article about virtual-key codes, and how they map to characters, and also this function to perform the mapping. But it doesn't seem to work like I expected it to.
This is my attempt at sending the virtual-key code of "A" (which is 0x41), and translating it to the character "ש" in the Hebrew keyboard (which is what pressing that key outputs to the screen, while the user is on the Hebrew keyboard layout). It still prints only "A", regardless of my current active layout.
#include <windows.h>
#include <iostream>
#include <stdlib.h>
#include <tchar.h>
int main()
{
HKL lpList[2];
GetKeyboardLayoutList(2, lpList); // returns {0x04090409 , 0xf03d040d} on my machine, which is {en-US, he-IL}
HKL hkl = lpList[1]; // sets to he-IL
char ch = MapVirtualKeyEx(0x41, MAPVK_VK_TO_CHAR, hkl); //0x41 is the Virtual Key of the keyboard button 'A'
std::cout << "ch: " << ch << std::endl; //prints "ch: A", I want it to print "ch: ש"
}
What am I missing? Is there some other way to achieve what I am trying to do?
I just tried
UINT VKCode = LOBYTE(VkKeyScan('ש')); // returns 0xbf
UINT ScanCode = MapVirtualKeyEx(VKCode, MAPVK_VK_TO_VSC, hkl); // returns 0x35
UINT VKCode2 = MapVirtualKeyEx(ScanCode, MAPVK_VSC_TO_VK, hkl); // once again 0xbf - unsurprisingly
TCHAR ch = MapVirtualKeyEx(VKCode2, MAPVK_VK_TO_CHAR, hkl); // now it returns '.'
So I convert char -> vk -> sc -> vk -> char, and end up with a different character than the one I started with. Maybe there is a different way to convert a `virtual-key code* to char?
You can use ToUnicodeEx API.
And if you want to output characters correctly, you can refer to: How to print Latin characters to the C++ console properly on Windows?
I created a sample and used the following code:
int main()
{
SetConsoleOutputCP(1256);
_setmode(_fileno(stdout), _O_U16TEXT);
HKL lpList[2];
GetKeyboardLayoutList(2, lpList);
HKL hkl = lpList[1]; // sets to he-IL
UINT VKCode = (VkKeyScanExW(L'ש',hkl));
UINT ScanCode = MapVirtualKeyExW(VKCode, MAPVK_VK_TO_VSC, hkl);
UINT VKCode2 = MapVirtualKeyExW(ScanCode, MAPVK_VSC_TO_VK, hkl);
TCHAR ch1 = MapVirtualKeyExW(VKCode2, MAPVK_VK_TO_CHAR, hkl);
BYTE uKeyboardState[256];
WCHAR oBuffer[5] = {};
//Initialization of KeyBoardState
for (int i = 0; i < 256; ++i)
{
uKeyboardState[i] = 0;
}
TCHAR buffer[1024];
ToUnicodeEx(VKCode, ScanCode, uKeyboardState, buffer, 1024, 0, hkl);
wcout << buffer;
return 0;
}
And it works for me:
According to the documentation pages (MapVirtualKeyExA function and MapVirtualKeyExW function) the function returns an UINT and not a char:
UINT MapVirtualKeyW(
UINT uCode,
UINT uMapType
);
Depending on your projact settings you'll need to inerpret this result either as char or as wchar_t, that's the reason.
You can overcome this, if you use TCHAR ch = ..., and let the project settings expand the TCHAR macro to the correct type properly.
The harder part is to decide if you need to use std::cout or std::wcout (std::cout, std::wcout). You could use some type check (e.g. if(std::is_same(ch,wchar_t)) { ... } else { ... }) to do this properly.

Getfriendlyname of a secondary monitor

I need to get device name of a secondary monitor. However when I simply try to retrieve device name, the output is DISPLAY1, DISPLAYV1 and etc.
However I require the name displayed when we check the screen resolution like the Displayname mentioned here:
Firstly I am not sure from where I can obtain this string. On reading a bit I guess it is the friendlyname of the device. However I am not sure since on calling EnumDisplaySetting() has been giving me Unhandled Exception: Could not access memory location when this function is called. So I have not been able to verify what the friendly name is exactly. And I believe that the unhandled exception is caused due to improper allocation of memory to the DISPLAY_DEVICE for driverextra in the DISPLAY_DEVICE. I believe this is because of this:
The function fails if iModeNum is greater than the index of the display device's last graphics mode.
mentioned here
Also I did not understand how much memory needs to be allocated to to
DISPLAY_DEVICE->dmDriverExtra as it has been mention in the same link:
Before calling EnumDisplaySettings, set the dmSize member to sizeof(DEVMODE), and set the dmDriverExtra member to indicate the size, in bytes, of the additional space available to receive private driver data.
So my question is manifold:
1) How much memory needs to be allocated to dmDriverExtra?
2) Is friendlyname the right parameter I need for accessing the name provided in the Display Tab in screen resolution. Or if not what other parameter do I need?
3) Is this unhandled exception caused due to improper memory allocation or is there some other reason for this?
4) Are there any other ways to get access to friendlyname of the secondary monitor?
Updated
I switched to using The PhysicalMonitorAPI instead of GetMonitorInfo. I've combined by original solution with the first. This produces more reasonable output that you would expect (e.g. "Dell UH2313" instead of "\.\Display1").
Technically, you should allocate the array of monitors instead of using a hardcoded array - but I've never seen where dwCount will get initialized to anything greater than 1.
This program compiles just fine in Visual Studio, but you'll need to link with dxva2.lib to pick up the definitions for the PhysicalMonitor APIs.
#include <Windows.h>
#include <PhysicalMonitorEnumerationAPI.h>
#include <string>
#include <iostream>
#include <stdio.h>
BOOL __stdcall MyMonitorEnumProc
(
_In_ HMONITOR hMonitor,
_In_ HDC hdcMonitor,
_In_ LPRECT lprcMonitor,
_In_ LPARAM dwData
)
{
DWORD dwCount = 0;
std::wstring strName(L"Unknown monitor name");
PHYSICAL_MONITOR monitors[100] = {};
MONITORINFOEX info = {};
info.cbSize = sizeof(info);
if (GetMonitorInfo(hMonitor, (LPMONITORINFO)&info))
{
strName = info.szDevice;
}
if (GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, &dwCount) && (dwCount > 0) && (dwCount < ARRAYSIZE(monitors)))
{
if (GetPhysicalMonitorsFromHMONITOR(hMonitor, dwCount, monitors))
{
strName = monitors[0].szPhysicalMonitorDescription;
DestroyPhysicalMonitors(dwCount, monitors);
}
}
std::wcout << L"Monitor: " << strName << std::endl;
return TRUE;
}
void printMonitorNames()
{
EnumDisplayMonitors(NULL, NULL, MyMonitorEnumProc, NULL);
}
int _tmain(int argc, _TCHAR* argv[])
{
printMonitorNames();
return 0;
}
And it's a good bet that the MyMonitorEnumProc will get invoked first for the primary monitor. All other monitors get enumerated next.

can't get current keyboard layout

I have tried GetKeyboardLayoutName() and GetKeyboardLayout() for getting the current keyboard layout, but they both give me the default layout and changing the layout doesn't affect the output!
while(1)
{
Sleep(5);
for(int i = 8; i < 191; i++)
{
if(GetAsyncKeyState(i)&1 ==1)
{
TCHAR szKeyboard[KL_NAMELENGTH];
GetKeyboardLayoutName(szKeyboard);
if(GetAsyncKeyState(i)&1 ==1)
{
TCHAR szKeyboard[KL_NAMELENGTH];
GetKeyboardLayoutName(szKeyboard);
cout << szKeyboard << endl ;
}
}
}
}
It always gives me "00000409" when the default layout is set to English, while I expect it to be "00000429" when I change the layout to Farsi.
My first question here, I used to find all my answers by just searching. But right now I'm driving crazy after hours of searching around and getting nothing...
one thing that you need to notice is that ::GetKeyboardLayout (..) gets the lang for the passed thread identifer as a param.
each input thread can have different input locale lang.
for instance if you put lets IE in the foreground and press Alt+Shift the lang changes to UK. ( you can see it in the taskbar )
now if you will Alt+Tab to another window ( which will be in foregorund ) you will see that lang dont have to stay UK.
so what you need to check is what is the thread id you are passing.
look at this code it will get you the lang for the current active window:
GUITHREADINFO Gti;
::ZeroMemory ( &Gti,sizeof(GUITHREADINFO));
Gti.cbSize = sizeof( GUITHREADINFO );
::GetGUIThreadInfo(0,&Gti);
DWORD dwThread = ::GetWindowThreadProcessId(Gti.hwndActive,0);
HKL lang = ::GetKeyboardLayout(dwThread);
to use GUITHREADINFO you need to define WINVER 0x500.
put this in the stdafx.h before all the include.
#ifdef WINVER
#undef WINVER
#endif
#define WINVER 0x500
source: GetKeyboardLayout not returning correct language ID (WINXP)
The following code is simple and works fine. If you write a command line program, the GetKeyboardLayout API does't work in windows cmd or powershell, you can test it in babun(an open source windows shell).
#include <Windows.h>
int getInputMethod() {
HWND hwnd = GetForegroundWindow();
if (hwnd) {
DWORD threadID = GetWindowThreadProcessId(hwnd, NULL);
HKL currentLayout = GetKeyboardLayout(threadID);
unsigned int x = (unsigned int)currentLayout & 0x0000FFFF;
return ((int)x);
}
return 0;
}

How do you run external programs with parameters without the cmd window showing up in Windows?

I just asked a question earlier today because I wanted to run an executable file that takes parameters from my C++ code and it wasn't working.
It works now, but I'm still having problems since I thought I was going the right way about this, but it seems like what I want to accomplish can't be done the way I'm approaching it...
This is my corrected code from my other question:
#include <stdlib.h>
#include <conio.h>
int main (){
system("\"\"C:\\Users\\Adam\\Desktop\\pdftotext\" -layout \"C:\\Users\\Adam\\Desktop\\week 4.pdf\"\"");
_getch();
}
which is me running "pdftotext -layout myfile.pdf" as if I was running it from a CMD window.
The thing is, I don't actually want the cmd to show up since I have a GUI interface on top of it and I want to display a nicer progress bar instead of seeing the windows pop-up for every file I need to parse.
I looked around and either I don't understand what I'm reading since I'm relatively new to C++, or I just didn't find what I was looking for. I found that using CreateProcess, I should be able to do this, but after copying some code I found somewhere else, the cmd window pops-up anyway.
I'd like it if someone could give me the name of a function I could use to accomplish something like this or if someone could give some example code for this small case in the code I posted since I'm not sure I understand everything as I should, being new to C++ and all.
Edit: As requested in a comment, the code for CreateProcess that I tried is what I found at this url:
http://www.goffconcepts.com/techarticles/development/cpp/createprocess.html
Which is (with my own parameters that I think should go there):
#include <windows.h>
#include <string>
#include <conio.h>
size_t ExecuteProcess(std::wstring FullPathToExe, std::wstring Parameters, size_t SecondsToWait)
{
size_t iMyCounter = 0, iReturnVal = 0, iPos = 0;
DWORD dwExitCode = 0;
std::wstring sTempStr = L"";
/* - NOTE - You should check here to see if the exe even exists */
/* Add a space to the beginning of the Parameters */
if (Parameters.size() != 0)
{
if (Parameters[0] != L' ')
{
Parameters.insert(0,L" ");
}
}
/* The first parameter needs to be the exe itself */
sTempStr = FullPathToExe;
iPos = sTempStr.find_last_of(L"\\");
sTempStr.erase(0, iPos +1);
Parameters = sTempStr.append(Parameters);
/* CreateProcessW can modify Parameters thus we allocate needed memory */
wchar_t * pwszParam = new wchar_t[Parameters.size() + 1];
if (pwszParam == 0)
{
return 1;
}
const wchar_t* pchrTemp = Parameters.c_str();
wcscpy_s(pwszParam, Parameters.size() + 1, pchrTemp);
/* CreateProcess API initialization */
STARTUPINFOW siStartupInfo;
PROCESS_INFORMATION piProcessInfo;
memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);
if (CreateProcessW(const_cast<LPCWSTR>(FullPathToExe.c_str()),
pwszParam, 0, 0, false,
CREATE_DEFAULT_ERROR_MODE, 0, 0,
&siStartupInfo, &piProcessInfo) != false)
{
/* Watch the process. */
dwExitCode = WaitForSingleObject(piProcessInfo.hProcess, (SecondsToWait * 1000));
}
else
{
/* CreateProcess failed */
iReturnVal = GetLastError();
}
/* Free memory */
delete[]pwszParam;
pwszParam = 0;
/* Release handles */
CloseHandle(piProcessInfo.hProcess);
CloseHandle(piProcessInfo.hThread);
return iReturnVal;
}
int main(void){
ExecuteProcess(L"C:\\Users\\Adam\\Desktop\\pdftotext", L"-layout \"C:\\Users\\Adam\\Desktop\\week 4.pdf\"", 0);
_getch();
}
I'm a little bit overwhelmed since it uses some things I've never used before, but I think I understand the core (keyword: think). It doesn't solve my problem, though, because the cmd shows up and by retesting it I actually noticed that the cmd doesn't even run the .exe and doesn't give me an error message.
I hope this bit of code helps... I didn't want to look into it further since it seemed like I wasn't even going in the right direction.
Use CreateProcess instead of system.
--EDIT--
the code for CreateProcess that I tried is what I found at this url:
The code is a mess, I'd advise to avoid that url in future.
At the end of "CreateProcess" article is a link named "Creating Processes", which contains simpler example that is easier to read. Use it as a starting point.
After adding the following lines for siStartupInfo, cmd window won't pop up any more with my own test *.exe.
siStartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
siStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
siStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
siStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
siStartupInfo.wShowWindow = SW_HIDE;
But I have another problem. As I try to run some other executable, whose command line would be
TEST.exe <input-file> output-file
in a cmd window, WaitForSingleObject() return 258, and GetLastError() return 1813 ("The specified resource type cannot be found in the image file.").
See system() and CreateProcess() / CreateProcessW() for more details.
Any ideas would be highly appreciated!
The only way I found how to execute an external program is:
system("start C:\file path\ file");
The only problem is that the file or directory can't have spaces.