In MFC RegisterHotKey function don't respond - winapi

In MFC RegisterHotKey function don't respond from Dll but works fine if i put same code in exe.
i am using same code which works in exe and putting it in Dll.
Also making sure that Dll gets load and othere changes are reflecting when i run exe.

You are using the same code for registering a hotkey in your DLL as in your EXE. This is your problem. See documentation for RegisterHotKey:
An application must specify an id value in the range 0x0000 through 0xBFFF. A shared DLL must specify a value in the range 0xC000 through 0xFFFF (the range returned by the GlobalAddAtom function). To avoid conflicts with hot-key identifiers defined by other shared DLLs, a DLL should use the GlobalAddAtom function to obtain the hot-key identifier.
To use RegisterHotKey from a shared DLL, you need to generate an id value. To get a value in the correct range, call GlobalAddAtom with a string parameter (see About Atom Tables: String Atoms). To create a unique id, pass the string representation of a GUID.

// Putting in message map
ON_MESSAGE(WM_HOTKEY, OnHotKey)
//Demographic Bar HotKey (putting in create or init)
RegisterHotKey(GetSafeHwnd(), GlobalAddAtom("SHIFT+CTRL+ALT+D"), MOD_SHIFT | MOD_CONTROL | MOD_ALT, 'D');
//source file
LRESULT CMainFrame::OnHotKey(WPARAM wParam, LPARAM lParam)
{
int hotKeyId = (int)wParam;
CString atomName;
GlobalGetAtomName(hotKeyId, atomName.GetBuffer(20), 20);
atomName.ReleaseBuffer();
if (atomName.Compare("SHIFT+CTRL+ALT+D") == 0)
{
SetPaneFocused(1); //Hard-coding 1 & 2 as place holders. Actual pane id should be here
}
else if (atomName.Compare("SHIFT+CTRL+ALT+M") == 0)
{
SetPaneFocused(2);
}
return S_OK;
}

Related

Detect Alt-Tab/Task Switching/ForegroundStaging Window accurately

Given a valid hwnd, how can we verify if it is indeed the alt-tab window?
One of my previous methods was to get the class of the window that the hwnd belongs to, then compare it to these values: MultitaskingViewFrame, ForegroundStaging, TaskSwitcherWnd and TaskSwitcherOverlayWnd.
However, I've come to realise that class names are not unique across the system, and indeed one can RegisterClassEx a class with the same name as the above names, which means my method above would give false positives.
I found a working solution to the problem: additionally, filter by process path using GetWindowModuleFileNameW.
rough pseudocode:
if window.class() in [..] && GetWindowModuleFileNameW(window.hwnd) == "C:\Windows\explorer.exe" {
ignore()
}
Processes cannot fake their path, so this works.
I recommend using the SetWinEventHook function to get the active display information correctly.
HWINEVENTHOOK SetWinEventHook(
DWORD eventMin,
DWORD eventMax,
HMODULE hmodWinEventProc,
WINEVENTPROC pfnWinEventProc,
DWORD idProcess,
DWORD idThread,
DWORD dwFlags
);
DWORD eventMin,
DWORD eventMax,
It is sufficient to give the constants EVENT_SYSTEM_FOREGROUND as arguments.
If I press alt-tab, the window switches fast but the callback is fired
for the the Task Switcher window and some other invisible window with
class ForegroundStaging.
For invisible windows, you can use IsWindowVisible to filter.
For the the Task Switcher window, you can compare their title names to filter.
Some code:
void __stdcall Wineventproc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD idEventThread, DWORD dwmsEventTime)
{
if (event == EVENT_SYSTEM_FOREGROUND)
{
if (IsWindowVisible(hwnd))
{
TCHAR title[512] = {};
int index = GetWindowText(hwnd, title, 512);
if (_tcsncmp(title, TEXT("Task Switching"), 14))
{
title[index] = L'\n';
title[index + 1] = L'\0';
OutputDebugString(title);
}
}
}
}
but I also need to account for rogue processes that try to masquerade
as ForegroundStaging etc.
This is a complicated question. No antivirus or protection technology is perfect. It takes time to identify and block malicious sites and applications, or trust newly released programs and certificates.  With almost 2 billion websites on the internet and software continuously updated and released, it's impossible to have information about every single site and program.
In other words, it is not easy to efficiently identify the true identity of each unknown application.
Refer: Unknown – Unrecognized software

Creating a shortcut on Win10 fails accessdenied

I have implemented the creation of a shortcut as defined in this article on Shell Links by MSDN
MSDN Shell Links
Here is what I implemented
CreateLink - Uses the Shell's IShellLink and IPersistFile interfaces
to create and store a shortcut to the specified object.
Returns the result of calling the member functions of the interfaces.
Parameters:
lpszPathObj - Address of a buffer that contains the path of the object,
including the file name.
lpszPathLink - Address of a buffer that contains the path where the
Shell link is to be stored, including the file name.
lpszDesc - Address of a buffer that contains a description of the
Shell link, stored in the Comment field of the link
properties.
HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc)
{
HRESULT hres;
IShellLink* psl;
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(lpszPathObj);
psl->SetDescription(lpszDesc);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
return hres;
I call it as:
r = CreateLink("c:\\TT\\TT.exe", "C:\\Users\\Public\\Desktop\\TT.lnk", "TT Program");
This works great on a WIN7 machine but fails on a WIN10
This is the code line that is failing:
hres = ppf->Save(wsz, TRUE);
hres == AccessDenied;
I have found other system calls that work on a Win7 but fails on Win10 and it usually comes down to some undocumented change.
Has Win10 tightened privileges on the DeskTop?
Any suggestions on addressing this on a Win10 machine?
Thanks.

GetModuleHandleEx usage example. WTL internationalisation

I am trying to do internationalization in a WTL GUI application .. in my drop down selection change handler (which is used for language selection I do something like this):
int selected = (int)::SendMessage(m_cbLang, CB_GETCURSEL,0,0);
HMODULE hmod;
int retCode = 0;
switch(selected)
{
case 0:
retCode =::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, NULL, &hmod);
ATL::_AtlBaseModule.SetResourceInstance(hmod);
break;
case 1:
retCode =::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, L"GuiLibOther.dll", &hmod);
ATL::_AtlBaseModule.SetResourceInstance(hmod);
break;
}
return S_OK;
Now, I really don't know how to use this function, although it is here , I don t know what the lpModuleName represents. The "GuiLibOther.dll" is a dll which contains the entire interface in another language.. all resources translated to another language.. I want the interface to change the language imediatelly after another language is selected. is this the right way?
Case 0 return hmod = NULL
First of all you don't want to use the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS flag unless you're passing the address of some item in the DLL, which in this case you're not.
Second the documentation implies that the DLL must already be loaded before you call GetModuleHandleEx. If you haven't linked it in to your .exe so that it's automatically loaded, you must use LoadLibrary.
The need to use LoadLibrary suggests a simplification:
static HMODULE hmodExe = INVALID_HANDLE;
static HMODULE hmodDLL1 = INVALID_HANDLE;
switch(selected)
{
case 0:
if (hmodExe == INVALID_HANDLE)
retCode =::GetModuleHandleEx(0, NULL, &hmodExe);
ATL::_AtlBaseModule.SetResourceInstance(hmodExe);
break;
case 1:
if (hmodDLL1 == INVALID_HANDLE)
hmodDLL1 = LoadLibrary(L"GuiLibOther.dll");
ATL::_AtlBaseModule.SetResourceInstance(hmodDLL1);
break;
This should let you switch resource libraries dynamically without extra overhead.

Force GetKeyNameText to english

The Win32 function GetKeyNameText will provide the name of keyboard keys in the current input locale.
From MSDN:
The key name is translated according to the layout of the currently
installed keyboard, thus the function may give different results for
different input locales.
Is it possible to force the input locale for a short amount of time? Or is there another alternative to GetKeyNameText that will always return the name in English?
Update: This answer does not work. It actually modifies the keyboard settings of the user. This appear to be a behavior change between Windows versions.
CString csLangId;
csLangId.Format( L"%08X", MAKELANGID( LANG_INVARIANT, SUBLANG_NEUTRAL ) );
HKL hLocale = LoadKeyboardLayout( (LPCTSTR)csLangId, KLF_ACTIVATE );
HKL hPrevious = ActivateKeyboardLayout( hLocale, KLF_SETFORPROCESS );
// Call GetKeyNameText
ActivateKeyboardLayout( hPrevious, KLF_SETFORPROCESS );
UnloadKeyboardLayout( hLocale );
WARNING: GetKeyNameText is broken (it returns wrong A-Z key names for non-english keyboard layouts since it uses MapVirtualKey with MAPVK_VK_TO_CHAR that is broken), keyboard layout dlls pKeyNames and pKeyNamesExt text is bugged and outdated. I cannot recommend dealing with this stuff at all. :)
If you're really-really want to get this info - then you can load and parse it manually from keyboard layout dll file (kbdus.dll, kbdger.dll etc).
There is a bunch of undocumented stuff involved:
In order to get proper keyboard layout dll file name first you need to convert HKL to KLID string. You can do this via such code:
// Returns KLID string of size KL_NAMELENGTH
// Same as GetKeyboardLayoutName but for any HKL
// https://docs.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;
}
Then with KLID string you need to go to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts\%KLID% registry path and read Layout File string from it.
Load this dll file from SHGetKnownFolderPath(FOLDERID_System, ...) (usually C:\Windows\System32) with LoadLibrary() call.
Next you need to do GetProcAddress(KbdDllHandle, "KbdLayerDescriptor") - you're receive pointer that can be casted to PKBDTABLES.
There is kbd.h header in Windows SDK that have KBDTABLES struct definition (there is some stuff involved to use proper KBD_LONG_POINTER size for x32 code running on x64 Windows. See my link to Gtk source at the end).
You have to look at pKeyNames and pKeyNamesExt in it to get scan code -> key name mapping.
Long story short: The GTK toolkit have the code that doing all this(see here and here). Actually they are building scan code -> printed chars tables from Windows keyboard layout dlls.

SHGetFileInfo on the public desktop

I'm having an issue with using SHGetFileInfo on the public desktop and files in the public desktop. I'll focus on the actual desktop folder (CSIDL_COMMON_DESKTOPDIRECTORY or usually "C:\Users\Public\Desktop"). Also - I've started seeing this behavior only recently, but I can't pinpoint the exact change which made it faulty. The actual call to ShGetFileInfo has not changed (as far as I can tell).
So I have this (I've omitted intermediate error checks to shorten - the function calls return with success):
SHFILEINFOW info;
uint32_t return_value = 0;
uint32_t flags = SHGFI_TYPENAME|SHGFI_ICON|SHGFI_SMALLICON|SHGFI_SYSICONINDEX;
uint32_t attributes = FILE_ATTRIBUTE_NORMAL;
wchar_t *path = L"C:\\Users\\Public\\Desktop";
return_value = SHGetFileInfoW(path, attributes, &info, sizeof(SHFILEINFOW), flags);
printf("[%ls] %u ", path, return_value);
This returns 0 as the return value. If I populate path using:
SHGetFolderPathW(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, 0, path)
I get the same result. But if I use the pidl, as in:
LPITEMIDLIST pidl = NULL;
SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &pidl);
return_value = SHGetFileInfoW((LPCWSTR) pidl, attributes, &info, sizeof(SHFILEINFOW), flags | SHGFI_PIDL);
Then I get something which I expect, a handle to the system small icon list.
I can't tell what I'm doing wrong - and it only happens on this specific folder. I actually need icons for the items inside the directory, so using the pidl doesn't seem to be an option right now. Any ideas on what is the expected way to retrieve icons from the common desktop?
--
I should mention this behavior happens on Windows Vista - using the path populated by SHGetFolderPathW on XP works fine
I had the same problem. It can be fixed by calling the function CoInitialize from OLE32.DLL when the program starts.
CoInitialize(0);
return_value = SHGetFileInfoW(path, attributes, &info, sizeof(SHFILEINFOW), flags);

Resources