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;
}
Related
I want to get the description of a process (the description that is seen in task manager) in Windows using C++.
You most likely want to get the FileDesription field from the version resources of the main .exe file of the program, using the VerQueryValue() API call. Here is an example from that document:
The following example shows how to enumerate the available version languages and retrieve the FileDescription string-value for each language.
Be sure to call the GetFileVersionInfoSize and GetFileVersionInfo functions before calling VerQueryValue to properly initialize the pBlock buffer.
// Structure used to store enumerated languages and code pages.
HRESULT hr;
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
// Read the list of languages and code pages.
VerQueryValue(pBlock,
TEXT("\\VarFileInfo\\Translation"),
(LPVOID*)&lpTranslate,
&cbTranslate);
// Read the file description for each language and code page.
for( i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++ )
{
hr = StringCchPrintf(SubBlock, 50,
TEXT("\\StringFileInfo\\%04x%04x\\FileDescription"),
lpTranslate[i].wLanguage,
lpTranslate[i].wCodePage);
if (FAILED(hr))
{
// TODO: write error handler.
}
// Retrieve file description for language and code page "i".
VerQueryValue(pBlock,
SubBlock,
&lpBuffer,
&dwBytes);
}
Although I read this question, the accepted answer, and the documentation for VerQueryValue, I spent quite a while to understand how to use that VerQueryValue function (since the code example in the docs has no declarations of variables and isn't clear for me at all).
So I decided to put here the code that can be easily run as a working example of the usage of VerQueryValue to get a process description.
#pragma comment(lib,"Version.lib")
#include <iostream>
#include <windows.h>
#include <winver.h>
using namespace std;
int printFileDescriptions(const wchar_t* filename)
{
int versionInfoSize = GetFileVersionInfoSize(filename, NULL);
if (!versionInfoSize) {
return 0;
}
auto versionInfo = new BYTE[versionInfoSize];
std::unique_ptr<BYTE[]> versionInfo_automatic_cleanup(versionInfo);
if (!GetFileVersionInfo(filename, NULL, versionInfoSize, versionInfo)) {
return 0;
}
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *translationArray;
UINT translationArrayByteLength = 0;
if (!VerQueryValue(versionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&translationArray, &translationArrayByteLength)) {
return 0;
}
// You may check GetSystemDefaultUILanguage() == translationArray[i].wLanguage
// if only the system language required
for (unsigned int i = 0; i < (translationArrayByteLength / sizeof(LANGANDCODEPAGE)); i++) {
wchar_t fileDescriptionKey[256];
wsprintf(
fileDescriptionKey,
L"\\StringFileInfo\\%04x%04x\\FileDescription",
translationArray[i].wLanguage,
translationArray[i].wCodePage
);
wchar_t* fileDescription = NULL;
UINT fileDescriptionSize;
if (VerQueryValue(versionInfo, fileDescriptionKey, (LPVOID*)&fileDescription, &fileDescriptionSize)) {
wcout << endl << fileDescription << endl;
}
}
return TRUE;
}
int main()
{
// Set locale of the console to print non-ASCII symbols
SetConsoleOutputCP(GetACP());
SetConsoleCP(GetACP());
wcout.imbue(std::locale("")); // set default global locale
// ----------------------------------------------------
auto path = L"C:\\Windows\\explorer.exe";
printFileDescriptions(path);
wcin.get(); // to prevent console close
}
It's supposed that all WinAPI functions on your system use wchar_t, that is VerQueryValueW is actually used.
The initial version of the code I took here Retrieve File Description an Application VerQueryValue
since Win-7 drag and drop implementation has changed, to make it work I need to enable some stuff using ChangeWindowMessageFilter.
There is a problem. ChangeWindowMessageFilter is valid since Vista, however I need solution for XP as well.
Well, you should try call it dynamically, for that you need LoadLibrary and GetProcAddress.
Sample usage
if (/*IsVista()*/)
{
typedef BOOL (WINAPI *ChangeMessageFilter)(UINT message, DWORD dwFlag);
#define MSGFLT_ADD 1
#define MSGFLT_REMOVE 2
BOOL res = FALSE;
HMODULE user32 = LoadLibrary(L"User32.dll");
if (user32 != NULL)
{
ChangeMessageFilter filter = (ChangeMessageFilter)::GetProcAddress(user32, "ChangeWindowMessageFilter");
if (filter != NULL)
{
res = filter(/*your value*/, MSGFLT_ADD);
}
::FreeLibrary(user32);
}
}
Another thing, you should better use ChangeWindowMessageFilterEx as it is enables messages receiving for only one window, not all project.
I am trying to temporarily install a font to use in the win32 console with
int AddFontResource(LPCTSTR lpszFilename);
and
BOOL WINAPI SetConsoleFont(HANDLE hOutput, DWORD fontIndex)
I got hold of this function from this site.
Although both functions seem to work fine I have no idea how to find the added font index to use with SetConsoleFont.
AddFontResource returns no index value or key to the temporary font.
Here is my relevant code:
#include "Level.h"
#include "ConsoleFont.h" //acquired from above mentioned site
#include <Windows.h>
//-------------------------------------------------------------------------------
void init();
void cleanup();
int main()
{
FileManager *pFileManager = new FileManager(); //unrelated
Level *lvl1 = new Level("filename",pFileManager); //unrelated
///TEMPORARY PLANNING
// using add font resource. how can i get this fonts index value?
int err = AddFontResource(L"Files/gamefont.fnt");
if (err == 0)
{
MessageBox(NULL,L"loading font failed",L"Error",0);
}
else
{
wchar_t message[100];
swprintf_s(message,100,L"AddFontResource returned: %d",err);
MessageBox(NULL,LPTSTR(message),L"error",0);
}
SendMessage(HWND_BROADCAST, WM_FONTCHANGE,0,0);
//acquiring handle to current active screen buffer
HANDLE tempHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (tempHandle == INVALID_HANDLE_VALUE)
{
MessageBox(NULL,L"Failed to aquire Screen Buffer handle",L"Error",0);
}
//I dont know what to set this to. this is the crux of the problem.
DWORD fontIndex = 1;
if (FALSE == SetConsoleFont(tempHandle,fontIndex))
{
MessageBox(NULL,L"loading console font failed",L"Error",0);
}
//draws a house when in correct font
std::cout<<"!!!!!!!!#\n"
<<"!!!!!!!!!\n"
<<"! !! !! !\n"
<<"!!!!!!!!!\n"
<<"! !! !! !\n"
<<"!!!!!!!!!\n"
<<"! !! !! !\n"
<<"!!!!!!!!!\n"
<<"! !! !! !#\n"
<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<<std::endl;
///PLANNING OVERS
bool quit = false;
while(!quit)
{
//still to be implemented
}
err = RemoveFontResource(L"Files/gamefont.fnt");
if (err==0)
{
MessageBox(NULL,L"removing font failed",L"Error",0);
}
return 0;
}
I don't know how to go about finding my new font's index value or even if this is possible using my current method.
If someone knows or has a better method please help me out.
any help or hints are appreciated. It must possible to use a custom font in the win32 Console without fiddling with the registry. I'm sure of it :)
Unfortunately you entered the dark world on Win APIs. There is no documentation (or atleast I could never find it) for a console font table lookup. You can try the method "GetNumberOfConsoleFonts()" to see what is returned. I think the font at index 10 is Lucida Console. You'll have to play around a little. Also, this may not work for the OS version you have. Worked for me on XP. Never had to try on anything else. And honestly, never got it fully working on XP too.
For the registry,
Fonts registries are here:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts
Console registries are here:
HKEY_CURRENT_USER\Console
If you end up modifying the registry, the changes may not be reflected immediately. You need to either restart the console or send a special WM_* message (sorry don't remember the name).
Will be great if you can find a solution/workaround :)
int err = AddFontResource(L"Files/gamefont.fnt");
if (err == 0)
{
MessageBox(NULL,L"loading font failed",L"Error",0);
}
else
{
wchar_t message[100];
swprintf_s(message,100,L"AddFontResource returned: %d",err);
MessageBox(NULL,LPTSTR(message),L"error",0);
}
this is wrong AddFontResource returns the number of fonts loaded, so the code in the ELSE doesn't make sense.
I want to get the description of a process (the description that is seen in task manager) in Windows using C++.
You most likely want to get the FileDesription field from the version resources of the main .exe file of the program, using the VerQueryValue() API call. Here is an example from that document:
The following example shows how to enumerate the available version languages and retrieve the FileDescription string-value for each language.
Be sure to call the GetFileVersionInfoSize and GetFileVersionInfo functions before calling VerQueryValue to properly initialize the pBlock buffer.
// Structure used to store enumerated languages and code pages.
HRESULT hr;
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;
// Read the list of languages and code pages.
VerQueryValue(pBlock,
TEXT("\\VarFileInfo\\Translation"),
(LPVOID*)&lpTranslate,
&cbTranslate);
// Read the file description for each language and code page.
for( i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++ )
{
hr = StringCchPrintf(SubBlock, 50,
TEXT("\\StringFileInfo\\%04x%04x\\FileDescription"),
lpTranslate[i].wLanguage,
lpTranslate[i].wCodePage);
if (FAILED(hr))
{
// TODO: write error handler.
}
// Retrieve file description for language and code page "i".
VerQueryValue(pBlock,
SubBlock,
&lpBuffer,
&dwBytes);
}
Although I read this question, the accepted answer, and the documentation for VerQueryValue, I spent quite a while to understand how to use that VerQueryValue function (since the code example in the docs has no declarations of variables and isn't clear for me at all).
So I decided to put here the code that can be easily run as a working example of the usage of VerQueryValue to get a process description.
#pragma comment(lib,"Version.lib")
#include <iostream>
#include <windows.h>
#include <winver.h>
using namespace std;
int printFileDescriptions(const wchar_t* filename)
{
int versionInfoSize = GetFileVersionInfoSize(filename, NULL);
if (!versionInfoSize) {
return 0;
}
auto versionInfo = new BYTE[versionInfoSize];
std::unique_ptr<BYTE[]> versionInfo_automatic_cleanup(versionInfo);
if (!GetFileVersionInfo(filename, NULL, versionInfoSize, versionInfo)) {
return 0;
}
struct LANGANDCODEPAGE {
WORD wLanguage;
WORD wCodePage;
} *translationArray;
UINT translationArrayByteLength = 0;
if (!VerQueryValue(versionInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&translationArray, &translationArrayByteLength)) {
return 0;
}
// You may check GetSystemDefaultUILanguage() == translationArray[i].wLanguage
// if only the system language required
for (unsigned int i = 0; i < (translationArrayByteLength / sizeof(LANGANDCODEPAGE)); i++) {
wchar_t fileDescriptionKey[256];
wsprintf(
fileDescriptionKey,
L"\\StringFileInfo\\%04x%04x\\FileDescription",
translationArray[i].wLanguage,
translationArray[i].wCodePage
);
wchar_t* fileDescription = NULL;
UINT fileDescriptionSize;
if (VerQueryValue(versionInfo, fileDescriptionKey, (LPVOID*)&fileDescription, &fileDescriptionSize)) {
wcout << endl << fileDescription << endl;
}
}
return TRUE;
}
int main()
{
// Set locale of the console to print non-ASCII symbols
SetConsoleOutputCP(GetACP());
SetConsoleCP(GetACP());
wcout.imbue(std::locale("")); // set default global locale
// ----------------------------------------------------
auto path = L"C:\\Windows\\explorer.exe";
printFileDescriptions(path);
wcin.get(); // to prevent console close
}
It's supposed that all WinAPI functions on your system use wchar_t, that is VerQueryValueW is actually used.
The initial version of the code I took here Retrieve File Description an Application VerQueryValue
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.