Subclassing an Edit control with SHAutoComplete applied - winapi

I'm new, so sorry if the question isn't posed exactly as you're get used to.
I inevitably need to subclass an Edit control for which SHAutoComplete() has been called like this:
// initialization
if FAILED( CoInitialize(NULL) ) exit(1);
// creation of an Edit control
HWND hEdit=CreateWindow( WC_EDIT, ... );
// calling SHAutoComplete - I essentially understand this as a subclassing behind the scenes
SHAutoComplete( hEdit , SHACF_AUTOSUGGEST_FORCE_ON|SHACF_FILESYSTEM );
// subclassing an Edit box for which SHAutoComplete has been called
WNDPROC autoCompleteWndProc=SubclassWindow( hEdit , __myNewWndProc__ ); // using macro
Suppose the __myNewWndProc__ function looks like a classic window procedure:
LRESULT CALLBACK __myNewWndProc__(HWND hEdit, UINT msg, WPARAM wParam, LPARAM lParam){
// handle subclass-specific messages
switch (msg){ ... }
// handle SHAutoComplete-specific messages
return autoCompleteWndProc(hEdit,msg,wParam,lParam); // <-- here's the problem (read further)
}
The problem is, it doesn't work. The application crashes with error:
Process returned -1073741819 (0xC0000005)" (access violation)
pointing the problem at line marked in the above listing.
The question is what am I doing wrong?
(I've experienced the same problem when subclassing from ComboBoxEx, but I managed to work around it, but can't find any trick with the SHAutoComplete() problem.)

SubclassWindow() is a wrapper for SetWindowLongPtr():
#define SubclassWindow(hwnd, lpfn) \
((WNDPROC)SetWindowLongPtr((hwnd), GWLP_WNDPROC, (LPARAM)(WNDPROC)(lpfn)))
When you use that type of subclassing, you MUST use CallWindowProc() to call the previous window procedure when needed, DO NOT call the procedure directly:
LRESULT CALLBACK __myNewWndProc__(HWND hEdit, UINT msg, WPARAM wParam, LPARAM lParam)
{
//...
// handle SHAutoComplete-specific messages
return CallWindowProc(autoCompleteWndProc,hEdit,msg,wParam,lParam);
}
The reason for that is stated in the documentation:
SetWindowLongPtr function
Calling SetWindowLongPtr with the GWLP_WNDPROC index creates a subclass of the window class used to create the window. An application can subclass a system class, but should not subclass a window class created by another process. The SetWindowLongPtr function creates the window subclass by changing the window procedure associated with a particular window class, causing the system to call the new window procedure instead of the previous one. An application must pass any messages not processed by the new window procedure to the previous window procedure by calling CallWindowProc. This allows the application to create a chain of window procedures.
CallWindowProc function:
lpPrevWndFunc [in]
Type: WNDPROC
The previous window procedure. If this value is obtained by calling the GetWindowLong function with the nIndex parameter set to GWL_WNDPROC or DWL_DLGPROC, it is actually either the address of a window or dialog box procedure, or a special internal value meaningful only to CallWindowProc.
You are probably running into the latter case, which will crash trying to call something that is not directly callable.
With that said, you should not be using SetWindowLongPtr() to subclass. Use SetWindowSubClass() instead. Read the following articles for more details:
Subclassing Controls
Safer subclassing

Related

How from an Handle can I retrieve the component name?

In my app, I catch all event via SetWindowsHookEx and when a user clicks on a button I retrieve an hwnd that I guess is the handle of the Tbutton.
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
DWORD lPrivate;
} MSG, *P
Now how can I from this hwnd retrieve the button name (or better the Delphi object representing the button?).
Maybe I can also retrieve the component via the POINT pt; ?
You can use FindControl, which will retrieve the object instance if the window is created by a control that belongs to the same instance of the VCL that calls the function. Since Name is published in TComponent, you can access the property regardless of the actual class type.
Every windowed VCL control has its object instance address stored in the API window's property list, along with properties containing information of module address, process id, thread id. This makes it possible for the VCL to backtrack a control from the window it created.

Is there a way to set minimum size without WM_GETMINMAXINFO?

I decided to create and use windows using a base class like this:
class Window
{
private:
static LRESULT WINAPI WindowProc(HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam);
protected:
virtual LRESULT onMessageNameGoesHere(/*parameters*/)
{
// Default handling
};
public:
// Other functions
};
So all windows are inherited from this class. This is WindowProc.
LRESULT WINAPI Window::WindowProc(HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam)
{
Window *window = (Window*)GetWindowLongPtr(_hWnd, GWLP_USERDATA);
switch (_uMsg)
{
case WM_SOMEMESSAGE:
return window->onMessageNameGoesHere();
case WM_NCCREATE:
SetWindowLongPtr(_hWnd, GWLP_USERDATA, LONG(LPCREATESTRUCT(_lParam)->lpCreateParams));
return true;
case WM_GETMINMAXINFO:
return window->onGetMinMaxInfo((LPMINMAXINFO)_lParam);
default:
return DefWindowProc(_hWnd, _uMsg, _wParam, _lParam);
}
}
WM_NCCREATE stores a pointer to the class associated to the window in GWLP_USERDATA. The problem is that WM_GETMINMAXINFO is received before WM_NCCREATE does, making it crash. (Yes, I know I need some code to avoid that)
So is there a way to set the minimum and maximum window size without WM_GETMINMAXINFO or maybe make that message be sent before WM_NCCREATE does?
Feel free to ask for more detail or for some more explanation.
I believe the answer is "no". This is one of the many places where the Windows OOP model has an impedance mismatch with that of C++.
The only solution I can think of is to use RAII to save/restore the context pointer in thread-local storage (make sure to save what was already there to avoid reentrancy isues) and to retrieve it as soon as your message handler is called. On Windows XP you can try __declspec(thread) or explicitly do this via TlsAlloc/TlsSetValue; on Windows Vista or later you might want to use FlsAlloc/FlsSetValue although I'm not sure if fibers can mess with things here...

Hooking a window with SetWinEventHook sometimes doesn't work

I wrote some code to watch for window title changes. It works fine with different windows in my Windows 7. I use SetWinEventHook like that:
SetWinEventHook(EVENT_OBJECT_NAMECHANGE,
EVENT_OBJECT_NAMECHANGE,
0,
WinEventCallback,
processId,
threadId,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS | WINEVENT_SKIPOWNTHREAD);
Callback:
void CALLBACK WinEventCallback(HWINEVENTHOOK hWinEventHook,
DWORD dwEvent,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime)
{
qDebug("Window %p", hwnd);
...
GetWindowText(hwnd, ...);
}
For one specific window I see the debug message "Window 0x0" all the time, e.g. I get the window handle set to zero in the callback. In this case GetWindowText fails. All other windows work fine. The question is why? I don't see anything extraordinary in Spy++:
Not all events generated may be associated with a window, especially for something as generic as a name change. The hook documentation specifically states that NULL windows are possible, so simply ignore them if your hook logic is window-oriented. If you are seeing a window change its title but you are getting a NULL window in your callback, then either it is not a real window, or there was an issue marshaling the window to your callback, or something like that.
The problem comes for the WinEventCallback's signature you are using.
Fix it by using this one: WinEventCallback(IntPtr hWinEventHook, uint iEvent, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)

KeyPress with multiple modifiers not working in QWidget

I have added an override for my main widget's keyPressEvent:
void MainWindow::keyPressEvent(QKeyEvent* e)
{
if (e->key() == Qt::Key_F11)
{
if (e->modifiers() & Qt::AltModifier && e->modifiers() & Qt::ControlModifier)
{
// do stuff
}
}
}
The problem is that it does not work. If I try the AltModifier or ControlModifier alone it works (while changing the second condition of course), but not for both of them. The key() won't equal to Qt::Key_F11 while I do press F11. I'm using windows.
Edit: checked with logging and the result is that Ctrl+Alt+F11 and Ctrl+Alt+F12 do not send a key event (while other Ctrl+Alt+Fxx keys do).
Oook, so I managed to solve it though I'm not exactly pleased with the solution. At least there is no mystery and it works :).
The reason why I didn't receive the hotkeys Ctrl+Alt+F11 and Ctrl+Alt+F12
They were registered as global hotkeys. I managed to find this out using the ActiveHotkeys program of the fellow stackoverflow member moodforaday (thanks a lot for it!). Apparently there is no documented way to find out which program registered a particular hotkey (and it didn't do anything on my system). See moodforaday's thread about the issue.
The solution
One of the answers in the aforementioned thread led me to another question. Efotinis' answer was absolutely perfect for me. I did not have experience with setting up low-level keyboard hooks, but it was not nearly as difficult as it sounds. For future's sake, here is how I did it in my Qt application:
In my mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
// ... code
private:
void tryLogin();
friend LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wparam, LPARAM lparam);
};
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wparam, LPARAM lparam);
In my mainwindow.cpp:
// setting up the hook in the constructor
SetWindowsHookEx(WH_KEYBOARD_LL,
LowLevelKeyboardProc,
NULL,
0);
The hook code (mostly from efotinis' answer):
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wparam, LPARAM lparam)
{
KBDLLHOOKSTRUCT* kllhs = reinterpret_cast<KBDLLHOOKSTRUCT*>(lparam);
if (code == HC_ACTION)
{
if (wparam == WM_KEYDOWN && kllhs->vkCode == VK_F12 &&
(GetAsyncKeyState(VK_MENU) < 0 && GetAsyncKeyState(VK_CONTROL) < 0))
{
MainWindow* w = dynamic_cast<MainWindow*>(qApp->activeWindow());
if (NULL != w)
{
w->tryLogin(); // this should not be blocking!
return 1;
}
}
}
return CallNextHookEx(0, code, wparam, lparam);
}
As you can see, we get the pointer to the application window from the global QApplication object. We use dynamic_cast so in the active window happens to not be a MainWindow instance we would get a NULL pointer.
If you are wondering why the GetAsyncKeyState calls are checked for < 0, it's because this function returns with MSB set if the key is down. And when the MSB is set, the SHORT number is negative (on x86/x64 and compatible platforms). If windows ever gets ported to a platform where signed integers are represented differently, this code might break. The absolutely proper way would be to create a 16-bit mask and use that to check the MSB, but I'm lazy to do that. :)
One thing to note is that when you call a function from your hook, the Qt event loop has just begun processing. That means until you don't return from your function, it will block the UI (freezing it for a few seconds). If you wanted to show a dialog like I did, instead of exec(), call raise, activateWindow and show, while setting the window modality of the dialog to modal (in its constructor maybe).
You can unregister the hook with UnHookWindowsHookEx if you want to (which happens when the module containing the hook is unloaded). To do this, save the return value of the SetWindowsHookEx call.

Create a native Windows window in JNA and some GetWindowLong with GWL_WNDPROC

Good day,
I have been using JNA for a while to interact with the Windows API and now I am stuck when creating a window. As far as I have done the following:
1. Have created a child window of an existing window and obtained a valid handler to it.
2. Understood that every window in Windows has a non-stop message-dispatch loop.
3. Understood that the best way to include my window in the message-dispatch loop is to use something like the following code (not mine, but that is what I would do as well):
final LONG_PTR prevWndProc = new LONG_PTR(User32.INSTANCE.GetWindowLong(hwnd, User32.GWL_WNDPROC)); //this is to obtain a pointer to the WNDPROC of the parent window, which we are going to need later
wndProcCallbackListener = new WndProcCallbackListener()
{
public LRESULT callback(HWND hWnd, int uMsg, WPARAM uParam, LPARAM lParam)
{
if (uMsg == WTSAPI.WM_POWERBROADCAST)
{
System.out.println("WM_POWERBROADCAST Event: hWnd="+hwnd+", uMsg="+uMsg+", uParam="+uParam+", lParam="+lParam);
}
else if (uMsg == WTSAPI.WTS_SESSION_CHANGE)
{
System.out.println("WTS_SESSION_CHANGE Event: hWnd="+hwnd+", uMsg="+uMsg+", uParam="+uParam+", lParam="+lParam);
}
//Call the window's actual WndProc so the events get processed.
return User32.INSTANCE.CallWindowProc(prevWndProc, hWnd, uMsg, uParam, lParam);
}
};
//Set the WndProc function to use our callback listener instead of the window's one.
int result = User32.INSTANCE.SetWindowLong(hwnd, User32.GWL_WNDPROC, wndProcCallbackListener);
However, my problem is when I call the GetWindowLong() for the parent window (my first line of code) I get a 0 for the pointer which indicated the function did not complete successfully. A subsequent call to GetLastError() and a quick check in the error codes give me an 'Access is denied' error. This, of course, is logical, since I am trying from my own thread to access the address of the WNDPROC of another, but I was wondering if there is any way (there should be, of course) to circumvent that.
Any pointers? (pun intended)
Do not use GetLastError() after a JNA call. JNA & JNI may call other APIs that may change the last error. Declare SetWindowLong with the clause throws LastErrorException, like this:
int SetWindowLongA(int hWnd, int nIndex, WndProcCallbackListener dwNewLong)
throws LastErrorException;
Notice the 'A' after the name. It makes explicit use of ANSI version. You could use SetWindowLongW as well.
Make sure your callback implements both Callback and StdCall. I prefer using primitive types as much as possible, because this makes mapping fast and obvious to JNA:
public interface WndProcCallbackListener extends Callback, StdCall {
int callback(int hWnd, int Msg, int wParam, int lParam);
}

Resources