TreeView Controls - HTREEVIEW - winapi

I'm new to win32 API programming and I try to understand source code of treeview from codeproject.
But I really don't understand this :
BOOL TreeView::DoNotify(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// blah blah
HTREEVIEW Selected = (HTREEITEM)SendDlgItemMessage(hWnd,ID_TREE,TVM_GETNEXTITEM,TVGN_CARET,(LPARAM)Selected);
// halb halb
}
It doesn't work ( Selected is used without initializing) until I declare Selected as global variable.
Thanks for reading this and I need your help .

TVM_GETNEXTITEM with TVGN_CARET does not use the LParam (So you can just pass NULL). You can verify this by looking at the macro for the same action:
#define TreeView_GetSelection(hwnd) TreeView_GetNextItem(hwnd, NULL, TVGN_CARET)

Related

How does lparam and wparam work in this specific code example?

I'm reading at some coding examples from Microsoft. And get confused by this combined key part.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_SYSKEYDOWN:
if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000)
{
//Do something
}
}
}
Here is what I don't understand, this code is about switching the application between fullscreen and windowed when pressing Alt+Enter. I get that WM_SYSKEYDOWN is holding Alt, and VK_RETURN is pressing Enter. So when they put together it means pressing Enter while holding Alt, but how do these two parameters work? Why Enter is in wParam and what does the lParam part on the right mean? What does the value of lParam represents? Please help.
I have another thing I'd like to ask.
Why it uses 0x60000000? It is a 31 bit start with 2 "1"s followed by 29 "0"s. From the document provided by tkausl, the 31th bit of WM_SYSKEYDOWN is always 0, so with a "&" operator, there should be no way the output will have a "1" at that bit, so why not just use 0x20000000 which should give the exactly same result?

How can I get the mouse cursor type in windows (default, hand, wait, resize etc)?

I would like to receive a notification when the mouse cursor change from arrow to hour glass etc.
Until now I managed to get notified for mouse position change events, but I can not figure out how to get the cursor type. It looks like the PCURSORINFO struct does not contain any information about the cursor type.
This is the code I have until now:
static LRESULT CALLBACK WinEventCallback(_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam)
{
PCURSORINFO curInfo;
curInfo->cbSize = sizeof(curInfo);
GetCursorInfo(curInfo);
}
void MouseCursorHook::setMouseCursorHook()
{
HHOOK evntHook = SetWindowsHookEx(WH_MOUSE_LL,
WinEventCallback,
GetModuleHandle(0),
0
);
}
First off, your call to GetCursorInfo() is wrong. You are passing it an uninitialized pointer. It should be like this instead:
CURSORINFO curInfo = {};
curInfo.cbSize = sizeof(curInfo);
GetCursorInfo(&curInfo);
Second, CURSORINFO has a hCursor field. You can compare that against the return value of LoadCursor()/LoadImage() to see if a standard cursor is being used or not. You will have to compare each standard cursor individually, though.

WINAPI keyboards detect other application hotkeys

Goal : I want to know that the user did or did't press on some hotkeys that i want to know it, like i want to know he/she press Ctrl + N on chrome
i try to detect the application hotkeys, like maybe chrome Ctrl + N is open new tab.
How winapi can detect this?
i have seen some article that said WM_KEYUP + WM_KEYDOWN, but the wParam one times can get one WM_KEYUP or WM_KEYDOWN, how implement it ?
int main(int argc, char *argv[])
{
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProc, hInstance, 0);
hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, hInstance, 0);
while (GetMessage(&message,NULL,0,0)) {
TranslateMessage( &message );
DispatchMessage( &message );
}
UnhookWindowsHookEx(hHook);
UnhookWindowsHookEx(hMouseHook);}
KeyBoardHookProc(int nCode, WPARAM wParam, LPARAM lParam){
KBDLLHOOKSTRUCT cKey = *((KBDLLHOOKSTRUCT*)lParam);
.................
if(wParam == WM_KEYUP)
{
kp.HandlekeyboardInfo(lpszName, buffer);
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
Thanks for helping!!
There are a few different ways you can do this. The easiest is probably to register a hotkey within your application and let windows notify you when the key combination is pressed.
RegisterHotKey
Another method would be to register a keyboard hook. All keypresses will be passed to your application, but you'll have to determine what keys were pressed. If you go this route, make sure to call CallNextHookEx().
SetWindowsHookEx

Why can't I bind to winproc?

I am trying to use C++11 to solve my favorite pointer problem
LRESULT CALLBACK renderMan::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
//some code
WNDPROC crazy = bind(&renderMan::WindowProc,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4);
The error
1>renderman.cpp(50): error C2440: 'initializing' : cannot convert from 'std::_Bind<_Forced,_Ret,_Fun,_V0_t,_V1_t,_V2_t,_V3_t,_V4_t,_V5_t,<unnamed-symbol>>' to 'WNDPROC'
1> with
1> [
1> _Forced=true,
1> _Ret=LRESULT,
1> _Fun=std::_Pmf_wrap<LRESULT (__cdecl glSurface::* )(HWND,UINT,WPARAM,LPARAM),LRESULT,glSurface,HWND,UINT,WPARAM,LPARAM,std::_Nil,std::_Nil,std::_Nil>,
1> _V0_t=glSurface *const ,
1> _V1_t=std::_Ph<1> &,
1> _V2_t=std::_Ph<2> &,
1> _V3_t=std::_Ph<3> &,
1> _V4_t=std::_Ph<4> &,
1> _V5_t=std::_Nil,
1> <unnamed-symbol>=std::_Nil
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
The Problem
A WNDPROC is a pointer to a function with a certain signature using the __stdcall calling convention.
std::bind returns a function object not a function pointer. Although, at the source code level, the function object can be used almost identically to a function pointer, the fact remains that it is a completely different type. No amount of casting will solve this.
Since you're binding a this pointer with the renderMan::WindowProc method, it's clear that renderMan::WindowProc is not a static member function, and thus it uses the thiscall calling convention. So even if you could get a pointer to it and hand it to Windows, Windows wouldn't call it with the right calling convention.
Solutions
The most common way to handle this is to have a nonmember function (or static member function) registered as the WNDPROC. That function looks up the this pointer associated with the window, and forwards it to your member function.
LRESULT CALLBACK WndProcHelper(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
renderMan *that = LookUpPointer(hwnd);
assert(that != nullptr);
return that->WndProc(hwnd, msg, wp, lp);
}
The details of LookUpPointer will vary depending on your approach. It sounds like you solved it just by having a global variable and thus just one window instance.
If you need multiple windows instantiated from this window class, you could maintain a global (or class-static) table mapping the HWNDs to the renderMan pointers. When you create a new instance, you add it to the table, and then you have a simple implementation for LookUpPointer:
std::map<HWND, renderMan*> g_windows;
renderMan *LookUpPointer(HWND hwnd) {
// If there isn't an entry for hwnd in the map, then this will
// will create one, associating it with nullptr.
return g_windows[hwnd];
}
This can have some chicken and egg problems, though, since you will get some messages during the CreateWindow call, before you've gotten the HWND back and had a chance to add it and the pointer to the map. For example:
// ... inside a renderMan constructor ...
m_hwnd = CreateWindow(L"renderMan", /* ... */);
g_windows[m_hwnd] = this; // already too late for some messages
Another common approach, which solves the chicken and egg problem, is to stash the renderMan pointer in the creation parameters, and have special logic in your WndProcHelper to add it to the map during creation.
// ... inside the renderMan constructor ...
m_hwnd = CreateWindow(L"renderMan", /* ... */, reinterpret_cast<LPVOID>(this));
// ... and then ...
LRESULT CALLBACK WndProcHelper(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
static std::map<HWND, renderMan*> windows; // still static, but not global :-)
LRESULT result = 0;
renderMan *that = nullptr;
if (msg == WM_NCCREATE) {
auto pCreateStruct = reinterpret_cast<const CREATESTRUCT*>(lp);
that = reinterpret_cast<renderMan*>(pCreateStruct->lpCreateParams);
windows[hwnd] = that;
} else {
that = windows[hwnd];
}
if (that != nullptr) {
result = that->WndProc(hwnd, msg, wp, lp);
}
if (msg == WM_NCCDESTROY) {
windows.erase(hwnd);
}
return result;
}
Caution: This is simplistic code without enough error checking for the purposes of illustrating the idea. A clean and complete implementation would handle errors more gracefully, log unexpected things (like missing entries), etc.
C API's with callbacks almost always provide a "user data" field for this purpose -- passing your own context structure or object (i.e. the 'this' pointer) through to the callback.
In this case, the userdata does exist, which means there's no need for any std::map shenanigans, however it is kind of hidden away. The APIs that you're looking for are:
SetWindowLongPtr( hwnd, GWLP_USERDATA, your_user_data )
your_user_data = GetWindowLongPtr( hwnd, GWLP_USERDATA )
WNDPROC is a function pointer while the result of bind is a function object. and as the compiler says, it can´t be converted to WNDPROC.
you could do:
auto crazy = bind(.....)
std::function<LRESULT CALLBACK(HWND, UINT, WPARAM, LPARAM)> crazy = bind(...)
but i guess that doesn´t solve your problem. i think there´s no way to do this without a free function. maybe like this:
std::function<LRESULT CALLBACK(HWND, UINT, WPARAM, LPARAM)> crazy;
LRESULT CALLBACK myWindowProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
{
if(!crazy)
return (LRESULT)nullptr;
return crazy(hwnd,Msg,wParam,lParam)
}
//and then somewhere in your renderMan:
crazy = bind(&renderMan::WindowProc,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4);
// wherever you want:
SetWindowLongA( hwnd, GWL_WNDPROC, ( LONG )myWindowProc );
The solution was to use a global variable. That way the constructor binds the this variable to another variable like that. This works for a singleton pattern, although I feel my initial question remains unanswered.

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