How to create a hidden window in C++ - c++

How to create a hidden window ?
The purpose of this window is to receive some messages.

When you create the window, omit the WS_VISIBLE flag and don't call ShowWindow.

In a win32/mfc environment what you need to do is create a class and inherit from CWnd like this:
class HiddenMsgWindow : public CWnd
{
...
}
in the constructor of that class you would instantiate a window like this:
HiddenMsgWindow::HiddenMsgWindow()
{
CString wcn = ::AfxRegisterWndClass(NULL);
BOOL created = this->CreateEx(0, wcn, _T("YourExcellentWindowClass"), 0, 0, 0, 0, 0, HWND_MESSAGE, 0);
}
This gets you a hidden window with a message pump almost ready to rock and roll.
the rest of the story is to provide the linkage between the window messages and the handlers for those messages.
This is done by adding a few macros and a message handler to your implementation file (.cpp) like this:
BEGIN_MESSAGE_MAP(HiddenMsgWindow, CWnd)
ON_MESSAGE(WM_USER + 1, DoNOOP)
END_MESSAGE_MAP()
LRESULT HiddenMsgWindow::DoNOOP(WPARAM wParam, LPARAM lParam)
{
AfxMessageBox(_T("Get Reaaady for a Ruuummmmmmmbllllle!"));
return LRESULT(true);
}
Then you need to fill in the rest of the glue in the header file like this:
class HiddenMsgWindow : public CWnd
{
public:
HiddenMsgWindow();
protected:
afx_msg LRESULT DoNOOP(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
}
And just like magic, you have a hidden window all ready to pump your messages.
In order to use this message window you would instantiate the class retrieve it's handle and send or post messages as desired. Just like this:
HiddenMsgWindow *hmw = new HiddenMsgWindow();
SendMessage(hmw->m_hWnd, WM_USER + 1, 0, 0);

You call CreateWindow() or CreateWindowEx() as usual but don't specify the WS_VISIBLE window style. Of course ShowWindow() should also not be called.

If you don't need to show the window,
as some suggest create the window, omit the WS_VISIBLE flag and don't call ShowWindow.
If not when you call showWindow(), add SW_HIDE parameter.
ShowWindow(hWnd, SW_HIDE);

Ahh, Just came across an issue. If u fail to specify HWND_MESSAGE unexpected behaviours could occur. I have used NULL which is NOT correct. In my case it caused that MS Excel took 10s or more to load an xls file, while it normally takes less then a second when my app was not running!
MSDN says this as someone mentioned before.

Related

Wrong parent HWND in modal dialog

Why do i get desktop as a parent HWND for my modal dialog here?
class CSaveProfileAsDlg:
public CSimpleDialog<IDD_DLG_RESOURCE>
{
....
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&)
{
...
HWND parent = GetParent(); // or GetAncestor(m_hWnd, GA_PARENT);
assert(parent != GetDesktopWindow()); // not ok
...
}
....
}
//somewhere in code
//m_hWnd is some valid HWND
assert(m_hWnd != GetDesktopWindow()); //ok
CSaveProfileAsDlg dlg;
dlg.DoModal(m_hWnd /*as a parent wnd*/);
I can "solve" it by passing corret HWND in CSaveProfileAsDlg ctor, but i'd like to have correct solution.
Thank you!
The documentation is very confusing but I think I found the problem. DoModal internally calls ::DialogBox(), one parameter of which takes a HWND named hWndParent. From the documentation:
hWndParent [in, optional]
Type: HWND
A handle to the window that owns the dialog box.
The keyword here is the word "owns". The section about owned windows confirms this:
Dialog boxes and message boxes are owned windows by default. An application specifies the owner window when calling a function that creates a dialog box or message box.
So we actually talk about the owner window instead of its parent. This makes sense as the dialog is a free floating window and not part of a window hierarchy as "parenthood" would imply.
You can get the owning window by using:
HWND parent = ::GetWindow(m_hWnd, GW_OWNER);
I had a similiar issue. I was wondering why GetParent() return always a different CWnd*.
The right solution is simple, just pass the desired pWnd to the dlg Constructor.
It will be stored in the CDialog member variable m_pParentWnd.
Then you can always get the passed pWnd with this member variable in your Dialog.
//somewhere in code
//pWnd some valid CWnd pointer
CSaveProfileAsDlg dlg (pWnd); // relevant!
dlg.DoModal();
.
class CSaveProfileAsDlg:
public CSimpleDialog<IDD_DLG_RESOURCE>
{
....
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&)
{
...
CWnd* _pWnd = GetParent(); // not ok, returns probably CMainFrame or similiar
CWnd* pWnd = m_pParentWnd; // your parent Wnd
...
}
....
}
I've got two versions of the same application and one of them disables all parent popup windows as it should when DoModal is called. Second version disables only top-level CMainFrame and real parent is stay enabled so I can call modal dialog twice and more.
This happen in CWnd::GetSafeOwner_, line :
hWnd = ::GetLastActivePopup(hWnd);
Firsts version return real parent while second version return CMainFrame.
I've spent one day and could not find the cause of such behaviour. However I've found workaround:
When DoModal is called it Disable CMainFrame so I can disable it's children also:
afx_msg void OnEnable(BOOL bEnable);
ON_WM_ENABLE()
void CMainFrame::OnEnable(BOOL bEnable)
{
std::for_each(m_bars.begin(), m_bars.end(),
[=](const std::pair<EBar, BaseBar*>& bar)
{
bar.second->EnableWindow(bEnable);
});
}

Class method for WndProc

This article explains brilliantly the options to call a class member WndProc. I've seen this response in stackoverflow but the main problem associating class member WndProc after CreateWindow is that some messages will be lost (including the important WM_CREATE) as explained in the mentioned article.
My question: I would like to hear the opinion from an expert on which of the methods exposed below or new one is the best one (performance, maintanability, ...) to create a class member WndProc.
Briefing the two final solutions exposed in the article (suposing that it exists a Window class with WndProc method):
Per-window data with this global pointer storage, protecting it with CRITICAL_SECTION to make it thread safe (extracted from here):
// The helper window procedure
// It is called by Windows, and thus it's a non-member function
// This message handler will only be called after successful SetWindowLong call
// We can assume that pointer returned by GetWindowLong is valid
// It will route messages to our member message handler
LRESULT CALLBACK WndProc2(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
// Get a window pointer associated with this window
Window *w = (Window *) GetWindowLong(hwnd, GWL_USERDATA);
// It should be valid, assert so
_ASSERT(w);
// Redirect messages to the window procedure of the associated window
return w->WndProc(hwnd, msg, wp, lp);
}
// The temporary global this pointer
// It will be used only between CreateWindow is called and the first message is processed by WndProc
// WARNING: it is not thread-safe.
Window *g_pWindow;
// Critical section protecting the global Window pointer
CRITICAL_SECTION g_WindowCS;
// The helper window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
// Stash global Window pointer into per-window data area
SetWindowLong(hwnd, GWL_USERDATA, (long) g_pWindow);
// Unlock global critical section
g_pWindow->HaveCSLock = false;
LeaveCriticalSection(&g_WindowCS);
// Reset the window message handler
SetWindowLong(hwnd, GWL_WNDPROC, (long) WndProc2);
// Dispatch first message to the member message handler
return WndProc2(hwnd, msg, wp, lp);
}
And now we can create the window:
InitializeCriticalSection(&g_WindowCS);
// Enter the critical section before you write to protected data
EnterCriticalSection(&g_WindowCS);
// Set global Window pointer to our Window instance
// Moved the assignment here, where we have exclusive access to the pointer
g_pWindow = &w;
// Set a flag indicating that the window has the critical section lock
// Note: this must be executed after the above assignment
g_pWindow->HaveCSLock = true;
// Create window
// Note: lpParam is not used
HWND hwnd = CreateWindow(TEXT("BaseWnd"), TEXT("Hello, World!"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hinst, 0);
// Leave critical section if window creation failed and our window procedure hasn't released it
if (g_pWindow->HaveCSLock)
LeaveCriticalSection(&g_WindowCS);
// Destroy critical section
// In production code, you'd do this when application terminates, not immediately after CreateWindow call
DeleteCriticalSection(&g_WindowCS);
Using CBT hook procedure (extracted from here):
// The helper window procedure
// It is called by Windows, and thus it's a non-member function
// This message handler will only be called after successful SetWindowLong call from the hook
// We can assume that pointer returned by GetWindowLong is valid
// It will route messages to our member message handler
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
// Get a window pointer associated with this window
Window *w = (Window *) GetWindowLong(hwnd, GWL_USERDATA);
// It should be valid, assert so
_ASSERT(w);
// Redirect messages to the window procedure of the associated window
return w->WndProc(hwnd, msg, wp, lp);
}
// The CBT hook procedure
// It is called during CreateWindow call before WndProc receives any messages
// Its job is to set per-window Window pointer to the one passed through lpParam to CreateWindow
LRESULT CALLBACK CBTProc(int code, WPARAM wp, LPARAM lp)
{
if (code != HCBT_CREATEWND) {
// Ignore everything but create window requests
// Note: generally, HCBT_CREATEWND is the only notification we will get,
// assuming the thread is hooked only for the duration of CreateWindow call.
// However, we may receive other notifications, in which case they will not be passed to other CBT hooks.
return 0;
}
// Grab a pointer passed to CreateWindow as lpParam
std::pair<Window *, HHOOK> *p = (std::pair<Window *, HHOOK> *) LPCBT_CREATEWND(lp)->lpcs->lpCreateParams;
// Only handle this window if it wasn't handled before, to prevent rehooking windows when CreateWindow is called recursively
// ie, when you create windows from a WM_CREATE handler
if (p->first) {
// Stash the associated Window pointer, which is the first member of the pair, into per-window data area
SetWindowLong((HWND) wp, GWL_USERDATA, (long) p->first);
// Mark this window as handled
p->first = 0;
}
// Call the next hook in chain, using the second member of the pair
return CallNextHookEx(p->second, code, wp, lp);
}
And now we can create the window:
// Install the CBT hook
// Note: hook the thread immediately before, and unhook it immediately after CreateWindow call.
// The hook procedure can only process window creation nofitications, and it shouldn't be called for other types of notifications
// Additionally, calling hook for other events is wasteful since it won't do anything useful anyway
HHOOK hook = SetWindowsHookEx(WH_CBT, CBTProc, 0, GetCurrentThreadId());
_ASSERT(hook);
// Create window
// Pass a pair consisting of window object pointer and hook as lpParam
std::pair<Window *, HHOOK> p(&w, hook);
HWND hwnd = CreateWindow(TEXT("BaseWnd"), TEXT("Hello, World!"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hinst, &p);
// Unhook first
UnhookWindowsHookEx(hook);
I personally would not use either of these methods. The global variable approach works, but feels dirty. Especially with the lock. And the CBT hook is, well over the top. Although it points in the right direction.
The standard way to pass state information to your window procedure during creation is through lpParam parameter of CreateWindow or CreateWindowEx. So the technique is as follows:
Pass your instance pointer in the lpParam parameter of CreateWindow or CreateWindowEx.
Read this value in your WM_NCCREATE handler. That message supplies the information as part of the CREATESTRUCT struct.
Still in WM_NCCREATE call SetWindowLongPtr to set the user data of the window to the instance pointer.
All future calls to the window procedure can now obtain the instance pointer by calling GetWindowLongPtr.
Raymond Chen illustrates the details here: How can I make a WNDPROC or DLGPROC a member of my C++ class?

Why constructor doesn't execute all the code using WinAPI?

This is my class constructor:
ActionButton::ActionButton(CallbackFunction function, void* param, HWND parent, int x, int y, int heigth, int width) :
m_function(function), m_parameters(param), m_window(NULL)
{
HWND m_window = CreateWindowEx(0, L"Action button", NULL, WS_CHILD | WS_VISIBLE,
x, y, width, heigth, parent, NULL, NULL, NULL);
DWORD dw = GetLastError();
SetWindowLongPtr(m_window, GWLP_USERDATA, (LONG_PTR)this);
ShowWindow(m_window, SW_NORMAL);
}
I used debuger and found that it executes CreateWindowEx() but after pressing F11 program jumped off the constructor (and I'm using only one thread). Is something wrong with my code?
After CreateWindowEx there is executing window procedure with parameters e.g WM_CREATE, so step after CreateWindowEx is not in constructor, after executing a few window procedure callbacks it goes back into constructor.
While executing CreateWindow[Ex] the system calls the window procedure associated with the window class for several messages (WM_GETMINMAXINFO, WM_NCCREATE, WM_NCCALCSIZE, WM_CREATE) before it returns. While the window procedure handles these messages the GWLP_USERDATA is not yet set. The system however guarantees, that GWLP_USERDATA is zero-initialized so you can safely query and handle the uninitialized GWLP_USERDATA.
If you want to set GWLP_USERDATA before CreateWindow[Ex] returns you will have to set up a CBT hook hook using SetWindowsHookEx and handle the HCBT_CREATEWND event. This lets you store any data attached to a HWND before the window procedure gets called with a WM_NCCREATE message.
Unrelated to your question, GWLP_USERDATA is fairly unreliable. A lot of applications will store their own data there, overwriting each other's data. Since this seems to be a private window class that you control you should allocate space in the Extra Window Memory instead and store your data there.

Add visible window titles to combobox MFC

I want to add visible window titles to a combobox. Here is my source:
BOOL CALLBACK EnumWindowsProc(HWND hWnd, long lParam)
{
TCHAR buff[255];
CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_PROCESS);
if (IsWindowVisible(hWnd))
{
GetWindowText(hWnd, buff, 254);
pComboBox->AddString(buff);
}
return TRUE;
}
void CFindProcess::OnDropdownComboProcess()
{
EnumWindows(EnumWindowsProc, 0);
}
but I get error:
error C2660: 'GetDlgItem' : function does not take 1 arguments 60
How I can correctly add titles to combo?
MFC objects are thread-sensitive, GetDlgItem works well in the thread that created the object, probably the main UI thread. Function EnumWindows probably creates a worker thread to access the callback function, and that is why GetDlgItem failed to get a valid handle of the combobox.
To access the combobox properly in another thread, you have to use the static function: CWnd::FromHandle with the raw handle of the combobox object as follows:
BOOL CALLBACK EnumWindowsProc(HWND hWnd, long lParam)
{
if (IsWindowVisible(hWnd))
{ TCHAR szBuffer[255];
INT nLength = GetWindowText(hWnd, szBuffer, 254);
if (nLength>0)
{ // only add windows that has a caption
CComboBox *pComboBox = (CComboBox*)CWnd::FromHandle((HWND)lParam);
pComboBox->AddString(szBuffer);
}
}
return TRUE;
}
// call EnumWindows --------------------
CComboBox *pComboBox = (CComboBox *)GetDlgItem(IDC_COMBO1);
// passing the raw handle of the combobox as parameter
EnumWindows(EnumWindowsProc, (LPARAM)pComboBox->m_hWnd);
Firstly, your GetDlgItem has two parameters, and the first is a handle to the dialog box that contains the control.
So it expects a HWND parameter of the dialog that contains this control, I would presume that will be the HWND you pass as a parameter to your function.
CComboBox* pComboBox = (CComboBox*)GetDlgItem(hWnd,IDC_COMBO_PROCESS);
^^^^ added parameter
If you look at EnumWindows in MSDN, you'll see you have to pass a callback and it has a HWND parameter, if you look at what this parameter is for it says:
A handle to a top-level window.
This is exactly what you have to pass to GetDlgItem.
Also, you should check the return value of GetWindowText as this returns the number of characters written to the buff you passed it.
int ret = GetWindowText(hWnd, buff, 254);
if (ret > 0) pComboBox->AddString(buff); // only add non-empty strings.
In addition to what user #mfc has provided, I would not do UI update from a different thread. I believe EnumWindows does not create thread for enumeration. It would call the callbacks within the call-stack of current thread.
This, in turn, means that UI may freeze for a while. Thus, it is recommended to create a thread for enumeration. More over, I would not directly update UI from different thread. May be a vector of string, or a PostMessage (on each iteration) I would have used.
It is true that EnumWindows may perform quite fast. But when you move to enumerate other (kernel) objects like file, printers, users etc - the UI is definitely going to freeze. So, better practice writing multithreaded code. Initially writing MT-code would be a pain, but later you'd love it, appreciate it, and cannot live without it.

Subclassing an edit control from a user defined class/pointer-to-member-function

I think I've fallen in the same trap as many before me where I try to impose a nice OO methodology on win32 API programming. No MFC, no AFX, I'm not even using VC++, I'm using C::B with gcc.
I think what I'm trying to do is impossible, but since MFC exists (although I'm not using it) there must be some way.
I've created a class to contain several window controls. It implements handlers for WM_CREATE and WM_COMMAND, and keeps track of all the associated data around my small group of controls (ID codes and HWNDs).
It works great for buttons, static controls, even light GDI methods, but it all breaks down when I try to subclass an edit control.
Really, I just want to capture the "enter" key, but as anybody who's been down that road before will attest, when an edit control has focus, the parent window doesn't receive WM_KEYDOWN or WM_COMMAND, we are left to implement our own proc. Super lame.
OK, so subclassing an edit control is fine, if the editProc is global or static. I know that is because SetWindowLongPtr needs a function address, and that concept is nebulous for a member function.
So the object of my class is declared as "static" inside the parent WndProc. But the function is not "static" because then I wouldn't have access to non-static data members (completely defeating the purpose of this exercise). I'm hoping that because the objest is itself static, I should be able to properly define the address of one of its member functions.
Readers that have tried this before will either have given up and used MFC or something else, or perhaps have found a clever work-around.
I'll let this sample code do the rest of the talking: (simplified - will not compile as such)
/**** myprogram.c ****/
#include "MyControlGroup.h"
int winMain(){ // etc... }
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// object is static becuse it only needs to be initialized once
static MyControlGroup myControl;
if (msg == WM_CREATE)
myControl.onWMCreate(hWnd);
else if (msg == WM_COMMAND)
myControl.onWMCommand( wParam, lParam );
else if (msg == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProcW(l_hWnd, l_msg, l_wParam, l_lParam);
}
The header file for my class:
/**** MyControlGroup.h ****/
class MyControlGroup
{
private:
HWND m_hWndParent;
HWND m_hWndEditBox;
int m_editBoxID;
public:
MyControlGroup();
void onWMCreate(HWND);
void onWMCommand(WPARAM, LPARAM);
// want to find a way to pass the address of this function to SetWindowLongPtr
LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
...and the implementation:
/**** MyControlGroup.cpp ****/
static int staticID = 1;
MyControlGroup::MyControlGroup()
{
m_editBoxID = staticID++;
}
void MyControlGroup::onWMCreate(HWND hWnd)
{
// My control group has buttons, static controls, and other stuff which are created here with CreateWindowW. It also has an edit control:
m_hWndEditBox = CreateWindowW(L"EDIT", L"initial text", WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 150, 20, hWnd, (HMENU)m_editBoxID, NULL, NULL);
/*
To subclass the edit control, I need a pointer to my customized proc. That means I
need a pointer-to-member-function, but SetWindowLongPtr needs a pointer to global or
static function (__stdcall or CALLBACK, but not __thiscall).
*/
// I'd like to do something like this, adapted from a great write-up at
// http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
LERSULT (MyControlGroup::*myEditProcPtr)(HWND, UINT, WPARAM, LPARAM);
myEditProcPtr = &MyControlGroup::myEditProc;
// Up to now it compiles ok, but then when I try to pass it to SetWindowLongPtr, I get
// an "invalid cast" error. Any ideas?
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProcPtr);
}
void MyControlGroup::onWMCommand(WPARAM wParam, LPARAM lParam){ /* process parent window messages. Editboxes don't generate WM_COMMAND or WM_KEYDOWN in the parent :''( */}
LRESULT MyControlGroup::myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// process messages like IDOK, WM_KEYDOWN and so on in the edit control
}
Even once I get this done, I'll still need to figure out a way to pass the address of the parent WndProc to myEditProc for the return value, but until I get past this there is no point in worrying about that.
Thanks in advance for reading!
myEditProc needs to be a static function.
Once you've done that you can pass the address of the function directly without going through the intermediate variable:
static LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
...
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProc);
To access your class data from the static function, you can save it in the userdata field of the edit control, e.g.:
// before sub-classing the control
SetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA, (LPARAM)this);
// in the sub-class procedure
MyControlGroup* pThis = (MyControlGroup*)GetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA);
But as #K-ballo suggested, SetWindowSubclass is definitely the way to do this unless you want compatibility with pre-XP. It handles the sub-classing procedure for you automatically, lets you associate a userdata pointer (e.g. this) that is automatically passed to the sub-class procedure, and safely handles removing the sub-class at the end.