Win32 - How to get input from specific windows class? - c++

I am using this windows class as an input box for my choose player name window http://www.codeproject.com/Articles/13330/Using-Dialog-Templates-to-create-an-InputBox-in-C --I read the entire description provided with the codeproject submission but none of it describes how I can actually output the input from the box. Can anyone tell me how I can do this? For example, user inputs name 'bob'. Message box appears says "hey user your name is " ...
GetWindowText(GetDlgItem(..., ...), storage_var, 16);
How can I fill in these parameters assuming that is how you would get input using this windows class? What values would I put in there, how would this work? All help is appreciated, thanks!
EDIT
This is how I am calling it:
char buf[256] = " ";
WIN32INPUTBOX_PARAM param;
param.szTitle = "[RESOURCE] PING!";
param.szPrompt = "PONG!";
param.szResult = buf;
param.nResultSize = MAX_PATH;
param.DlgTemplateName = MAKEINTRESOURCE(101);
CWin32InputBox::InputBoxEx(&param);
CWin32InputBox::InputBox("Testing", "enter detail"
, buf, 256, true);
Following that how would i get input into a variable from that input box?

As #RetiredNinja mentioned in his comment, you need to use the parameter, like
char buf[100] = "";
CWin32InputBox::InputBox("hello", "what?", buf, 100, false);
MessageBox(hDlg, buf, "You entered this", MB_OK);
EDIT
The code above is for a "straight" Win-API without MFC.
If you are using MFC, (please edit the question and add the mfc tag), the code would look like:
char buf[100] = "";
CWin32InputBox::InputBox("hello", "what?", buf, 100, false);
MessageBox(buf, "You entered this", MB_OK);

Related

How to create a list of Keyboards. Extract KLID from HKL?

Windows 10 / C++ / Win32
I need to make a list of 'installed' Keyboards.
The components of my 'list' needs to contain:
The HKL for the keyboard.
The KLID for the keyboard.
The values of the registry values obtained from:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts
Example: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000409
Value: Layout File
Value: Layout Text
The only way I am aware of enumerating Keyboards is via GetKeyboardLayoutList(), which returns a list of HKL's.
Methodology which works for 'standard' keyboards (HKL's 04090409, 04070407,..).
TCHAR Buffer[50];
TCHAR Buffer2[50];
HKL LoadedKeyboardLayout;
// Hkl: 04090409
_stprintf_s(Buffer, (sizeof(Buffer)/sizeof(TCHAR)), _T("%08X"), (((UINT)Hkl >> 16) & 0xFFFF));
// Buffer: "0000409"
LoadedKeyboardLayout = LoadKeyboardLayout(Buffer, (UINT)0);
// It Loads
ActivateKeyboardLayout(LoadedKeyboardLayout, KLF_SETFORPROCESS);
// It Activates
GetKeyboardLayoutName(Buffer2);
// Buffer2: "00000409"
// I can now fish the registry HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000409
This DOES not work when the 'device identifier' is NOT 0000.
From LoadKeyboardLayout() documentation:
The name of the input locale identifier to load. This name is a string composed of the hexadecimal value of the Language Identifier (low word) and a device identifier (high word). For example, U.S. English has a language identifier of 0x0409, so the primary U.S. English layout is named "00000409". Variants of U.S. English layout (such as the Dvorak layout) are named "00010409", "00020409", and so on.
If one creates a 'Custom' keyboard, I find it is impossible to get the 'device identifier' from the custom keyboards HKL.
For instance:
Create a Custom Keyboard US with MKLCS.
Install it.
The 'KLID' will be 'A0000409'.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\a0000409
The HKL will be 0xF0C00409 (as returned within the HKL list generated by GetKeyboardLayoutList()).
In order to load the keyboard with LoadKeyboardLayout(), one needs 'A0000409'.
It does not seem possible to create A0000409 from F0C00409.
I also created my own keyboard layout without MKLCS.
I arbitrarily named it 00060409.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00060409
It's HKL is FFFE0409 (as returned within the HKL list generated by GetKeyboardLayoutList()).
It does not seem possible to create 00060409 from FFFE0409.
With all of that said, how does one obtain a KLID from an HKL?
Or, is there another way I can go about creating my list of installed keyboards?
//================================================================
11/25/2020 Addition.
Thank you Rita.
It seems as if GetKeyboardLayoutList() creates a list of 'Loaded' keyboard layouts.
System loaded keyboard layouts, 0x0409409,....
Keyboard Layouts installed via MKLCS installation.
It seems that any Keyboards defined within the following registry keys will get loaded at boot.
HKEY_CURRENT_USER\Keyboard Layout
Note the Preload and Substitute value's.
(Note there are many other 'Keyboard Layout' keys spread around within the registry, so I am
not sure if HKEY_CURRENT_USER\Keyboard Layout is the actual registry key that defines the
PreLoad - Substitutes.
HKEY_USERS\.DEFAULT\Keyboard Layout
HKEY_USERS\S-1-5-18 (My User Account)
HKEY_LOCAL_MACHINE\SYSTEM\Keyboard Layout
)
So there is no doubt in my mind that Rita's example works due to the fact that her HKEY_CURRENT_USER\Keyboard Layout contains the following entries:
Preload:
1 d0010804
Substitutes:
d0010804 a0000804
The entries may have been put there by the MKLCS installer?
Or perhaps the action of adding the keyboard via Settings->Time & Language->Click on Preferred Language->Options->Add a Keyboard
From ActivateKeyboardLayout() documentation:
The input locale identifier must have been loaded by a previous call to the LoadKeyboardLayout function.
Since a0000804 (HKL: F0C00804) is actually already loaded ActivateKeyboardLayout() works.
Since my KLID: 00060409 is not referenced within any of the X\Keyboard Layout Preload and Substitutes
I must physically call LoadKeyBoardLayout(L"00060409") in order for it to appear within the GetKeyboardList() HKL's.
Thanks again Rita.
how does one obtain a KLID from an HKL?
There seems no direct method out of box to achieve it.
A workaround is retrieving a list of HKLs, then active a layout via a HKL, then get its KLID. The following is an example:
int cnt = GetKeyboardLayoutList(sizeof(hklArr)/sizeof(hklArr[0]), hklArr);
if(cnt > 0)
{
printf("keyboard list: \n");
for (UINT i = 0; i < cnt; i++)
{
printf("%x\n", (LONG_PTR)hklArr[i]);
if (ActivateKeyboardLayout(hklArr[i], KLF_SETFORPROCESS))
{
WCHAR pName[KL_NAMELENGTH];
if (GetKeyboardLayoutName(pName))
{
wprintf(L"layout name (KLID): %s\n", pName);
}
}
}
}
Result like this:
Update:
Update 2: Share my creating and installing steps.
I use Keyboard Layout Creator 1.4.
Load an existing keyboard for testing purpose. (You can modify based on it or create your own completely.)
Valid and test keyboard to make sure it works as you expected. Then build DLL and setup package.
Run setup.exe generated by step 2. After installation complete you will see the related preload keyboard layout item in registry.
There is no safe way to do this since it is not documented and can be changed after Windows updates.
Proper algorithm is posted here.
Here is my code that is working on my Windows 10 Version 21H2 (November 2021 Update) so far:
// Returns KLID string of size KL_NAMELENGTH
// Same as GetKeyboardLayoutName but for any HKL
// https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values
BOOL GetKLIDFromHKL(HKL hkl, _Out_writes_(KL_NAMELENGTH) LPWSTR pwszKLID)
{
bool succeded = false;
if ((HIWORD(hkl) & 0xf000) == 0xf000) // deviceId contains layoutId
{
WORD layoutId = HIWORD(hkl) & 0x0fff;
HKEY key;
CHECK_EQ(::RegOpenKeyW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", &key), ERROR_SUCCESS);
DWORD index = 0;
while (::RegEnumKeyW(key, index, pwszKLID, KL_NAMELENGTH) == ERROR_SUCCESS)
{
WCHAR layoutIdBuffer[MAX_PATH] = {};
DWORD layoutIdBufferSize = sizeof(layoutIdBuffer);
if (::RegGetValueW(key, pwszKLID, L"Layout Id", RRF_RT_REG_SZ, nullptr, layoutIdBuffer, &layoutIdBufferSize) == ERROR_SUCCESS)
{
if (layoutId == std::stoul(layoutIdBuffer, nullptr, 16))
{
succeded = true;
DBGPRINT("Found KLID 0x%ls by layoutId=0x%04x", pwszKLID, layoutId);
break;
}
}
++index;
}
CHECK_EQ(::RegCloseKey(key), ERROR_SUCCESS);
}
else
{
WORD langId = LOWORD(hkl);
// deviceId overrides langId if set
if (HIWORD(hkl) != 0)
langId = HIWORD(hkl);
std::swprintf(pwszKLID, KL_NAMELENGTH, L"%08X", langId);
succeded = true;
DBGPRINT("Found KLID 0x%ls by langId=0x%04x", pwszKLID, langId);
}
return succeded;
}
Also you can use this code to enumerate layout profiles with KLID in LAYOUTORTIPPROFILE.szId:
typedef struct tagLAYOUTORTIPPROFILE {
DWORD dwProfileType;
LANGID langid;
CLSID clsid;
GUID guidProfile;
GUID catid;
DWORD dwSubstituteLayout;
DWORD dwFlags;
WCHAR szId[MAX_PATH];
} LAYOUTORTIPPROFILE;
// Flags used in LAYOUTORTIPPROFILE::dwProfileType
#define LOTP_INPUTPROCESSOR 1
#define LOTP_KEYBOARDLAYOUT 2
// Flags used in LAYOUTORTIPPROFILE::dwFlags.
#define LOT_DEFAULT 0x0001
#define LOT_DISABLED 0x0002
std::vector<LAYOUTORTIPPROFILE> EnumLayoutProfiles()
{
// http://archives.miloush.net/michkap/archive/2008/09/29/8968315.html
// https://learn.microsoft.com/en-us/windows/win32/tsf/enumenabledlayoutortip
typedef UINT(WINAPI* EnumEnabledLayoutOrTipFunc)(LPCWSTR pszUserReg, LPCWSTR pszSystemReg, LPCWSTR pszSoftwareReg, LAYOUTORTIPPROFILE* pLayoutOrTipProfile, UINT uBufLength);
static EnumEnabledLayoutOrTipFunc EnumEnabledLayoutOrTip = reinterpret_cast<EnumEnabledLayoutOrTipFunc>(::GetProcAddress(::LoadLibraryA("input.dll"), "EnumEnabledLayoutOrTip"));
if (!EnumEnabledLayoutOrTip)
return {};
const UINT count = EnumEnabledLayoutOrTip(nullptr, nullptr, nullptr, nullptr, 0);
std::vector<LAYOUTORTIPPROFILE> layouts;
layouts.resize(count);
const UINT written = EnumEnabledLayoutOrTip(nullptr, nullptr, nullptr, layouts.data(), count);
CHECK_EQ(count, written);
return layouts;
}
The LAYOUTORTIPPROFILE.szId string format of the layout is:
<LangID>:<KLID>
The string format of the text service profile (IME) is:
<LangID>:{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
More info here.

want it to be trim my TCHAR * from end only

TCHAR* pszBackupPath;
m_Edt_ExportPath.GetWindowText(pszBackupPath, dwcchBackupPath);
StrTrim(pszBackupPath, L" ");
StrTrim(pszBackupPath, L"\\"); //this line has issue
iRet = _tcslen(pszBackupPath);
boRet = PathIsNetworkPath(pszBackupPath);
if (FALSE == boRet)
{
// MessageBox with string "Entered path is network path.
}
boRet = PathIsDirectory(pszBackupPath);
if (FALSE == boRet)
{
// MessageBox with string "Entered path is not a valid directory.
}
This is a part of my code in MFC.
I am passing a network path from UI. But because of StrTrim(pszBackupPath, L"\\") "\\" get trimmed from start and end. But I want it to be trimmed from end only.
I don't know any direct API. Please suggest.
There is a simple function to do that: PathRemoveBackslash (or PathCchRemoveBackslash for Windows 8 and later).

Get the "Key Usage" from Certificate

What API can I use to get the "Key Usage" from a certificate. I Specifically want to know if a given certificate has "Digital Signature" or not.
Below screenshot is the detail of a certificate in windows. I need the API that gives me the "Key Usage".
The code is for windows and I am writing my code in C++.
Thank you
Sam
Start with CertOpenStore, then call CertFindCertificateInStore in a loop until you find the certificate you are interested in.
The returned CERT_CONTEXT contains a pointer to a CERT_INFO struct. You will then want to walk the rgExtension member which is an array of CERT_EXTENSION objects. The one you care about has pszObjId set to szOID_KEY_USAGE_RESTRICTION, which will then give you this data: CERT_KEY_USAGE_RESTRICTION_INFO where the RestrictedKeyUsage member has the bit flags you are interested in.
You can also look at the szOID_KEY_USAGE extension, which will use the same bit flags, but the msdn documentation states that those fields are
advisory field[s], only, and does not imply that usage of the key is restricted
to the purpose indicated
Depending on what you need the information for, you could use either extension.
With the help of Josh Poley, I found the answer. Thank you Josh
bool CertHasDigitalSignature(PCCERT_CONTEXT pCert)
{
bool retVal(false);
CERT_EXTENSION* keyUsage;
keyUsage = CertFindExtension(szOID_KEY_USAGE, pCert->pCertInfo->cExtension, pCert->pCertInfo->rgExtension);
if(NULL != keyUsage)
{
DWORD strSz(0);
if(CryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, szOID_KEY_USAGE, keyUsage->Value.pbData ,keyUsage->Value.cbData, NULL, &strSz))
{
std::wstring Buff;
Buff.resize((strSz / sizeof(wchar_t)) + 1);
if(CryptFormatObject(X509_ASN_ENCODING, 0, 0, NULL, szOID_KEY_USAGE, keyUsage->Value.pbData ,keyUsage->Value.cbData, (void*)Buff.data(), &strSz))
{
if (std::wstring::npos != Buff.find(L"Digital Signature"))
retVal = true;
}
}
}
return retVal;
}

How do I get the Service Display name in C++?

I am trying to get the display name of the running service using c++. I was trying to use the GetServiceDisplayName function but it does not seem to be working, not sure why.
TTServiceBegin( const char *svcName, PFNSERVICE pfnService, bool *svc, PFNTERMINATE pfnTerm,
int flags, int argc, char *argv[], DWORD dynamiteThreadWaitTime )
{
SC_HANDLE serviceStatusHandle;
DWORD dwSizeNeeded = 0 ;
TCHAR* szKeyName = NULL ;
serviceStatusHandle=OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE ,SC_MANAGER_ALL_ACCESS);
GetServiceDisplayName(serviceStatusHandle,svcName, NULL, &dwSizeNeeded);
if(dwSizeNeeded)
{
szKeyName = new char[dwSizeNeeded+1];
ZeroMemory(szKeyName,dwSizeNeeded+1);
if(GetServiceDisplayName(serviceStatusHandle ,svcName,szKeyName,&dwSizeNeeded)!=0)
{
MessageBox(0,szKeyName,"Got the key name",0);
}
}
When i run this code, i can never see the value of szKeyName in my debugger and it goes into the if block for the message box but never displays the message box. Not sure why?
Anyway to get this to work to get the display name of the service or any other/easier way to accomplish that task?
You need to use the WTSSendMessage instead of the MessageBox to interact with the active session.
WTS_SESSION_INFO* pSessionInfo = NULL;
DWORD dwSessionsCount = 0;
if(WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwSessionsCount))
{
for(int i=0; i<(int)dwSessionsCount; i++)
{
WTS_SESSION_INFO &si = pSessionInfo[i];
if(si.State == WTSActive)
{
DWORD dwIdCurrentSession = si.SessionId;
std::string strTitle = "Hello";
std::string strMessage = "This is a message from the service";
DWORD dwMsgBoxRetValue = 0;
if(WTSSendMessage(
WTS_CURRENT_SERVER_HANDLE,
dwIdCurrentSession,
(char*)strTitle.c_str(),
strTitle.size(),
(char*)strMessage.c_str(),
strMessage.size(),
MB_RETRYCANCEL | MB_ICONINFORMATION | MB_TOPMOST,
60000,
&dwMsgBoxRetValue,
TRUE))
{
switch(dwMsgBoxRetValue)
{
case IDTIMEOUT:
// Deal with TimeOut...
break;
case IDCANCEL:
// Deal With Cancel....
break;
}
}
else
{
// Deal With Error
}
break;
}
}
WTSFreeMemory(pSessionInfo);
}
The message box will not be visible on Windows Vista and later due to a change that has services running in a separate session (Session 0 Isolation) that does not have access to a desktop so the message box would not be visible to you, the logged on user.
On Window XP and earlier, you need to tick the Allow service to interact with desktop checkbox under the Log On tab in the service's properties dialog for your service to make message box appear.
Instead, you could write the service name out to a file or run a user application that accepts the name of the service to query and have it query and display the service name (I just tried with the posted code and it works correctly, displaying the message box).

Launch default email client to open a "send email" window with a pre-selected file attachment

I need to add a "Create and email" feauture to our app. Our program creates an output file, and I must then launch the default email client to open a "write email" window, and with the output file preselected as an attachment.
I've seen other programs do it, even if the default client is Thunderbird instead of Outlook.
I ended up using MAPI to achieve it. I used LoadLibrary and GetProcAddress to get the needed functions.
The code I used is this:
bool MailSender::Send(HWND hWndParent, LPCTSTR szSubject)
{
if (!m_hLib)
return false;
LPMAPISENDMAIL SendMail;
SendMail = (LPMAPISENDMAIL) GetProcAddress(m_hLib, "MAPISendMail");
if (!SendMail)
return false;
vector<MapiFileDesc> filedesc;
for (std::vector<attachment>::const_iterator ii = m_Files.begin(); ii!=m_Files.end(); ii++)
{
MapiFileDesc fileDesc;
ZeroMemory(&fileDesc, sizeof(fileDesc));
fileDesc.nPosition = (ULONG)-1;
fileDesc.lpszPathName = (LPSTR) ii->path.c_str();
fileDesc.lpszFileName = (LPSTR) ii->name.c_str();
filedesc.push_back(fileDesc);
}
std::string subject;
if (szSubject)
subject = utf16to8(szSubject).c_str();
else
{
for (std::vector<attachment>::const_iterator ii = m_Files.begin(); ii!=m_Files.end(); ii++)
{
subject += ii->name.c_str();
if (ii+1 != m_Files.end())
subject += ", ";
}
}
MapiMessage message;
ZeroMemory(&message, sizeof(message));
message.lpszSubject = (LPSTR) subject.c_str();
message.nFileCount = filedesc.size();
message.lpFiles = &filedesc[0];
int nError = SendMail(0, (ULONG)hWndParent, &message, MAPI_LOGON_UI|MAPI_DIALOG, 0);
if (nError != SUCCESS_SUCCESS && nError != MAPI_USER_ABORT && nError != MAPI_E_LOGIN_FAILURE)
return false;
return true;
}
Using the mailto scheme may be a solution but it's going to be tricky due to restrictions on what fields are considered safe (see the RFC 2368 and 6067 for the full details if you want to go that route).
Another solution would be to figure out what email client is installed and - wherever possible - launch it and specify all you need via command line. See here for Thunderbird & here for Outlook.
You can use the following command to start the start the default client app with attachment
"Path to default mail client.exe" -mail -compose subject='Subject',attachment='File path',body='body'"
Path to default mail client-> can be taken from registry path
HKEY_LM\SOFTWARE\Clients\Mail\Email Client Name\shell\open\command
Mail Client Name -> can be taken from
HKEY_LM\Software\Clients\Mail