Hooking Win32 windows creation/resize/querying sizes - c++

I'm trying to "stretch" an existing application.
The goal is to make an existing application become larger without changing the code of that application.
A cosntraint is that the stretched application will not "notice" it, so if the application query a created window size it'll see the original size and not the resized size.
I managed to resize the windows using SetWindowsHookEx:
HHOOK hMessHook = SetWindowsHookEx(WH_CBT,CBTProc, hInst, 0);
And:
LRESULT CALLBACK CBTProc( __in int nCode,
__in WPARAM wParam,
__in LPARAM lParam)
{
if (HCBT_CREATEWND == nCode)
{
CBT_CREATEWND *WndData = (CBT_CREATEWND*) lParam;
// Calculate newWidth and newHeight values...
WndData->lpcs->cx = newWidth;
WndData->lpcs->cy = newHeight;
}
CallNextHookEx(hMessHook, nCode, wParam, lParam);
}
The problem I'm facing is that I'm unable to the make the stretched application see the original sizes.
For example, if a .NET form is created:
public class SimpleForm : Form
{
public SimpleForm()
{
Width = 100;
Height = 200;
}
}
And later the size is queried:
void QuerySize(SimpleForm form)
{
int width = form.Width;
int height = form.Height;
}
I'd like width and height be 100 and 200 and not the resized values. I was unable to find the right hook which queries the size of an existing window.
What is the right way to hook window size querying?

Unfortunately, queries for window size aren't handled by messages -- they are direct API calls such as GetWindowRect -- so they can't be intercepted by standard Windows hooks. You might want to look into the Detours API, which allows you to hook arbitrary Win32 functions. (You can find a tutorial on Detours here)

Related

What information does dwExtraInfo hold for the PMOUSEHOOKSTRUCT?

LRESULT CALLBACK LowLevelMouseProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
BOOL fpassmove = FALSE;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_MOUSEMOVE: // how do i catch a dx instead of a cursor points?
PMOUSEHOOKSTRUCT me = (PMOUSEHOOKSTRUCT)lParam;
printf("x:%d\ny:%d\nextrainfo:%04X\n", me->pt.x,me->pt.y, me->dwExtraInfo );
break;
}
}
return(fpassmove ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}
int main()
{
// Install the low-level keyboard & mouse hooks
HHOOK hhkLowLevelMouse = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, 0, 0);
// Keep this app running until we're told to stop
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) { //this while loop keeps the hook
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelMouse);
return(0);
}
I am looking at all mouse moment from a global hook, and I'm trying to find the dx and dy of the mouse event, And I was hoping to find it in "dwExtraInfo". However, I have no idea how to make sense of the data inside "dwExtraInfo".
the windows documentation is not helpful in telling me what the data in dwExtraInfo means
dwExtraInfo
Type: ULONG_PTR
Additional information associated with the message.
Could not find any documentation on dwExtraInfo directly, but found something related: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessageextrainfo:
Return value
Type: LPARAM
The return value specifies the extra information. The meaning of the
extra information is device specific.
One example of such device specific extra information is Pen gestures: https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages
Distinguishing Pen Input from Mouse and Touch
When your application receives a mouse message (such as
WM_LBUTTONDOWN), it may call the GetMessageExtraInfo function to
evaluate whether the message originated from a pen or a mouse device.
The value returned from GetMessageExtraInfo needs to be mask-checked
against 0xFFFFFF00, and then compared with 0xFF515700. The following
definitions may make this clearer:
#define MI_WP_SIGNATURE 0xFF515700
#define SIGNATURE_MASK 0xFFFFFF00
#define IsPenEvent(dw) (((dw) & SIGNATURE_MASK) == MI_WP_SIGNATURE
If the comparison is true, then this mouse message was generated by a
Tablet PC pen or touch screen. In all other cases, you can assume that
this message was generated by a mouse device.
The lower 8 bits returned from GetMessageExtraInfo are variable. Of
those bits, 7 (the lower 7, masked by 0x7F) are used to represent the
cursor ID, zero for the mouse or a variable value for the pen ID.
Additionally, in Windows Vista, the eighth bit, masked by 0x80, is
used to differentiate touch input from pen input (0 = pen, 1 = touch).

C++: Trying to hook a message box and change its position

I recently started coding in C++ and I am very new to it. (I code in Javascript, PHP, Java and Obj-C more often)
I'm practicing how to hook a message box and change its position. This is what I have in my .cpp file (after reading this SO post).
#include <iostream>
#pragma comment(lib,"User32.lib")
#include <windows.h>
HHOOK hhookCBTProc = 0;
LRESULT CALLBACK pfnCBTMsgBoxHook(int nCode, WPARAM wParam, LPARAM lParam){
if (nCode == HCBT_CREATEWND)
{
CREATESTRUCT *pcs = ((CBT_CREATEWND *)lParam)->lpcs;
if ((pcs->style & WS_DLGFRAME) || (pcs->style & WS_POPUP))
{
HWND hwnd = (HWND)wParam;
SetWindowPos(hwnd, HWND_TOP,130,122, 0, 0,SWP_NOSIZE);
}
}
return (CallNextHookEx(hhookCBTProc, nCode, wParam, lParam));
}
int main(void)
{
hhookCBTProc = SetWindowsHookEx(WH_CBT,pfnCBTMsgBoxHook,
0, GetCurrentThreadId());
int sResult = MessageBox ( NULL, "Hooked!", "oh my", MB_OK );
UnhookWindowsHookEx(hhookCBTProc);
return 0;
}
For some reason the position of the message box isn't changing. Where did it go wrong?
(I know I can create a customized window or dialog. But I am doing it this way because I want to learn how to hook a message box and where I did wrong.)
Firstly you should check in the debugger that your hook is actually being called, if you haven't already.
Secondly, at the time the HCBT_CREATEWND hook event is triggered, the window has only just been created - the system has yet to size and position it. It will do this with the values in the CREATESTRUCT after the hook returns - overriding your SetWindowPos call.
See the docs from MSDN on the lParam value for this particular hook event:
Specifies a long pointer to a CBT_CREATEWND structure containing
initialization parameters for the window. The parameters include the
coordinates and dimensions of the window. By changing these
parameters, a CBTProc hook procedure can set the initial size and
position of the window.
Therefore, the correct way to use this hook to change a window's position is to modify the values in the CREATESTRUCT directly.
Also note that it's quite possible that the dialog manager sizes and positions the window after creation, so if you find that this still isn't working for you, you may need to try watching for the HCBT_MOVESIZE event instead.
From the docs
At the time of the HCBT_CREATEWND notification, the window has been
created, but its final size and position may not have been determined
and its parent window may not have been established.
Maybe try hooking into CBT_ACTIVATE instead.

CTabCtrl SetItemRect?

I want to change the size of the tabs.
We have added a closing cross to our tabs, but it conflicts spaciously with the text of the tab.
So far I have realized the following:
GetItemRect(int i, RECT* rc) gives me the rect. What I really would like is a SetItemRect.
SetItem cannot be used as the item does not contain its size. It is calculated based upon the contents I give it.
I could add a space char in the end of the string, but that's just against the natural order of things. I will not tweak pixels with CStrings.
SetSize is supposed to set the size of a tab (all tabs?). But I cannot find out where to put it that does not trigger a redraw, which sparks an infinite loop if I put it with the WM_PAINT case.
This is where I custom draw the contents of the tab, but I cannot resize them here:
LRESULT CSkinnedTabCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_PAINT: {
...
CPaintDC dc(this);
INT nCount = GetItemCount();
for (INT i = 0; i < nCount; i++) {
CRect rc;
GetItemRect(i, rc);
DrawItem(dc, i, rc);
}
return TRUE;
}
Where do I set the size of the tabs, and how?
IIRC you need to overwrite WM_NCCALCSIZE message.

Accessing multiple Editboxes in MFC

I am writing a MFC program in which I have a a lot of Editboxes and I want to get all their text values and put them in a container. How can I achieve this without writing a line for each ID. I'm using this code for each ID:
CEdit *edit;
edit = reinterpret_cast<CEdit *>(GetDlgItem(IDC_NAME1));
But if I use that method I would have to write it 45 times. That doesn't seem right.
Is there a way of getting all the Editboxes in a container so I can use them that way or something like that?
You can certainly create an array (or other container) or pointers to CEdit: CEdit edits[45]; If the values of IDC_NAME1 through IDC_NAME45 are contiguous, you can just do something like:
for (int i=0; i<45; i++)
names[i] = reinterpret_cast<CEdit *>(GetDlgItem(IDC_NAME1 + i));
If those identifiers may not be contiguous, then you can put them in an array, and just index into that array as needed.
One caution: unless they're something like a grid of otherwise nearly identical edit controls, 45 on a screen may well be a bit much. If they are like a grid, you might want to look at one of the many available grid controls instead.
You do not have to use controls IDs.
Use EnumChildWindows and get test only for edit controls. Snippet follows.
Add following in dialog’s header:
afx_msg LRESULT OnFoundEdit(WPARAM wParam, LPARAM lParam);
And this to cpp:
#define WM_U_FOUND_EDIT WM_APP + 0x100
BEGIN_MESSAGE_MAP(CEditCtrlFishingDlg, CDialog)
ON_MESSAGE(WM_U_FOUND_EDIT, OnFoundEdit)
.
.
.
.
END_MESSAGE_MAP()
Write this line in the place you want to start edit text collection:
EnumChildWindows(m_hWnd, EnumChildProc, (LPARAM)m_hWnd);
Enum child procedure:
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
{
CString csBuffer;
LPTSTR pBuf = csBuffer.GetBufferSetLength(MAX_PATH);
GetClassName(hwnd, pBuf, MAX_PATH);
csBuffer.ReleaseBuffer();
if(!csBuffer.CompareNoCase(_T("edit")))
{
SendMessage((HWND)lParam, WM_U_FOUND_EDIT, 0, (LPARAM)hwnd);
}
return TRUE;
}
and the handler:
LRESULT YourDlg::OnFoundEdit(WPARAM wParam, LPARAM lParam)
{
CWnd *pWnd = FromHandle((HWND)lParam);
CString csTxt;
pWnd->GetWindowText(csTxt);
// do what you need with text here
return 0;
}

crash on ShowWindow()

I am developing a Notepad++ plugin.
I have a simple dialog box, which is created using CreateDialogParam(). It is initially hidden.
After a menu click, I call ShowWindow() with SW_SHOW on its handle, which results in this exception:
c000041d
Upon debugging , I found that these two messages are sent to my dialog just before crash
WM_SHOWWINDOW
WM_WINDOWPOSCHANGING
Both of them, I am not handling. Here is my dlgproc code. Any idea why it would happen ?
BOOL CALLBACK StaticDialog::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG :
{
// Get the additional init data
StaticDialog *pStaticDlg = (StaticDialog *)(lParam);
// Store the handle in the object
pStaticDlg->_hSelf = hwnd;
::SetWindowLongPtr(hwnd, GWL_USERDATA, (long)lParam);
// Store the co-ordinates in the object
::GetWindowRect(hwnd, &(pStaticDlg->_rc));
// Forward the message for further processing
pStaticDlg->run_dlgProc(message, wParam, lParam);
// TRUE if it processed the message
return TRUE;
}
default :
{
// Retrieve the user data
StaticDialog *pStaticDlg = (StaticDialog *)(::GetWindowLongPtr(hwnd, GWL_USERDATA));
if (!pStaticDlg)
return FALSE;
// Send the message for further processing
return pStaticDlg->run_dlgProc(message, wParam, lParam);
// return FALSE if it processed the message
}
}
}
BOOL CALLBACK MarkDownViewDialog::run_dlgProc( UINT Message, WPARAM wParam, LPARAM lParam)
{
switch (Message)
{
case WM_INITDIALOG:
{
EmbedBrowserObject(this->_hSelf);
DisplayHTMLPage(this->_hSelf,L"http://www.microsoft.com");
DisplayHTMLStr(this->_hSelf, L"<H2><CENTER>HTML string test</CENTER></H2><P><FONT COLOR=RED>This is a <U>HTML string</U> in memory.</FONT>");
break;
}
default:
break;
}
return FALSE;
}
The dialog box is created through plugin mechanism of Notpead++. I am putting the source code from its file StaticDialog.cpp. The control goes through else block in code below.
void StaticDialog::create(int dialogID, bool isRTL, bool isModeles)
{
if (isRTL)
{
DLGTEMPLATE *pMyDlgTemplate = NULL;
HGLOBAL hMyDlgTemplate = makeRTLResource(dialogID, &pMyDlgTemplate);
_hSelf = ::CreateDialogIndirectParam(_hInst, pMyDlgTemplate, _hParent, (DLGPROC)dlgProc, (LPARAM)this);
::GlobalFree(hMyDlgTemplate);
}
else
_hSelf = ::CreateDialogParam(_hInst, MAKEINTRESOURCE(dialogID), _hParent, (DLGPROC)dlgProc, (LPARAM)this);
//int i=GetLastError();
if (!_hSelf)
{
//systemMessage(_T("StaticDialog"));
return;
}
if (isModeles) {
_isModeles = isModeles;
::SendMessage(_hParent, NPPM_MODELESSDIALOG, MODELESSDIALOGADD, (WPARAM)_hSelf);
}
}
My entire solution source code is hosted here:
https://github.com/madhur/Npp-Markdown-Viewer
Issue Resolution
Here is what I have done to troubleshoot the problem:
Created a Win32 project in which I create a dialog box and put exactly same source code to embed browser control in WM_INITDIALOG and it works. This Win32 project links with the same static library, which the original source code is linking with. This is the source of the sample project mail file:
https://github.com/madhur/Npp-Markdown-Viewer/blob/master/dll/example/example.c
The static library I referenced above, is nothing but it contains functions to embed browser control in HWND and to render either an URL or string. I have taken the source from here: http://www.codeguru.com/Cpp/I-N/ieprogram/article.php/c4379
This is the source of static library main file:
https://github.com/madhur/Npp-Markdown-Viewer/blob/master/dll/dll.c
If I comment this single line, the plugin works, basically it loads the dialog box without the Browser control in it:
EmbedBrowserObject(this->_hSelf);
The actual exception in Visual Studio is raised on this line:
return pStaticDlg->run_dlgProc(message, wParam, lParam);