Help - Search - Members - Calendar
Full Version: [win32] Problem with subclassing
Hydrogenaudio Forums > Hosted Forums > foobar2000 > Development - (fb2k)
mixcherry
I've got my Playlists Dropdown plugin (see here) and I want to add context-menu to each of the items of the open DropDown List:
IPB Image
I mean, I want a small popup-menu to occur when I click with RMB on some item from the list (say, 'Collection'). The problem is that normally Combo ListBox doesn't react on any button other than LMB (which selects certain item and closes ListBox).

Someone told me that I should 'subclass the ComboBox, then subclass the Combo ListBox on WM_CTLCOLORLISTBOX'. Then I could 'catch' RMB clicks. So I subclassed the ComboBox - see the code below. But now I am stuck.
I don't know how to subclass the ListBox on WM_CTLCOLORLISTBOX. What should be written in place of ???,???,??? (in code below)? How should ListBox Window Procedure (on_listbox_hook) look like - what should it return?

Maybe someone can help me smile.gif

CODE
class playlists_dropdown : public uie::container_ui_extension
{
WNDPROC m_combobox_proc;
protected:
HWND m_hWnd; // <-- handle to my ComboBox window
public:
LRESULT on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp);
LRESULT on_hook(HWND wnd, UINT msg, WPARAM wp, LPARAM lp);
static LRESULT WINAPI hook_proc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp);
}

LRESULT playlists_dropdown::on_message(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_CREATE:
{
m_hWnd = CreateWindowEx(0, WC_COMBOBOX, 0, CBS_DROPDOWNLIST ... );
SetWindowLongPtr(m_hWnd, GWL_USERDATA, (LPARAM) (this));
m_combobox_proc = (WNDPROC) SetWindowLongPtr(m_hWnd, GWL_WNDPROC, (LPARAM) (hook_proc));
}
break;
}
return DefWindowProc(wnd, msg, wp, lp);
}

LRESULT WINAPI playlists_dropdown::hook_proc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
playlists_dropdown * p_this;
p_this = reinterpret_cast< playlists_dropdown * >(GetWindowLongPtr(wnd, GWL_USERDATA));
LRESULT rv = p_this ? p_this->on_hook(wnd, msg, wp, lp) : DefWindowProc(wnd, msg, wp, lp);
return rv;
}

LRESULT playlists_dropdown::on_hook(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_CTLCOLORLISTBOX:
{
/* ??? */
/* ??? */
/* ??? */
}
break;
}
return CallWindowProc(m_combobox_proc, wnd, msg, wp, lp);
}

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */

LRESULT playlists_dropdown::on_listbox_hook(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_RBUTTONUP:
{
/* Show popup-menu */
}
break;
}
return /* ?????? */
}

/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
Acropolis
this is the code snippet:
CODE

WNDPROC old_cb = NULL, old_lb = NULL;

LRESULT CALLBACK lb_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_RBUTTONDOWN:
/* popup your menu here */
break;
}
return CallWindowProc(old_lb, hwnd, uMsg, wParam, lParam);
}

LRESULT CALLBACK cb_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg==WM_CTLCOLORLISTBOX)
{
/* restore the original combo box wndproc */
SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG)old_cb);
/* and hook the list box now, lParam is the windows handle */
old_lb = (WNDPROC) SetWindowLongPtr((HWND)lParam, GWL_WNDPROC, (LONG)lb_proc);
}
return CallWindowProc(old_cb, hwnd, uMsg, wParam, lParam);
}

void main()
{
.....................
.....................
/* hook the combo box */
old_cb = (WNDPROC) SetWindowLongPtr(m_combo, GWL_WNDPROC, (LONG)cb_proc);
.....................
.....................
}
mixcherry
Hi. Thank you for your reply. Unfortunately, the compiler keeps getting me mad with this message:
CODE
error C2440: 'type cast' : cannot convert from 'LRESULT (__stdcall playlists_dropdown::* )(HWND,UINT,WPARAM,LPARAM)' to 'LONG'
        There is no context in which this conversion is possible

This error is caused by this line (@cb_proc):
CODE
old_lb = (WNDPROC) SetWindowLongPtr((HWND)lParam, GWL_WNDPROC, (LONG)lb_proc);
foosion
You should explicitly take the address of lb_proc:
CODE
old_lb = (WNDPROC) SetWindowLongPtr((HWND)lParam, GWL_WNDPROC, (LONG)&lb_proc);
sriram
make lb_proc static ?
Acropolis
QUOTE(sriram @ Aug 24 2006, 06:56) *

make lb_proc static ?


this will work too.
or don't put any WNDPROC functions in C++ class, then will be fine.
mixcherry
First of all, thank you for your answers!

QUOTE(foosion @ Aug 23 2006, 22:51) *
You should explicitly take the address of lb_proc:
CODE
old_lb = (WNDPROC) SetWindowLongPtr((HWND)lParam, GWL_WNDPROC, (LONG)&lb_proc);
That causes another error: error C2276: '&' : illegal operation on bound member function expression.
When I change last parameter from (LONG)&lb_proc to (LONG)&playlists_dropdown::listbox_proc, then it causes the same error C2440 as above.

QUOTE(sriram @ Aug 23 2006, 22:56) *
make lb_proc static ?
Thanks, that worked (I also had to make old_lb static). But what if I want to use some non-static fields/methods of my class inside lb_proc?...

QUOTE(Acropolis @ Aug 24 2006, 01:44) *
or don't put any WNDPROC functions in C++ class, then will be fine.
What exactly do you mean? Should I make old_cb and old_lb *global* (outside the class)? (both variables are of type WNDPROC) This doesn't change anything...

---

After making lb_proc static, I've (finally) been able to catch RMB click on list item. But there's another problem: when I display the popup-menu (using TrackPopupMenu()), the ListBox immediately closes itself... I would like the ListBox window to stay open until I choose something from popup-menu. Is it possible to somehow *block* ListBox (so it doesn't close) AND show popup-menu at the same time?

I'm starting to believe that it is impossible to do such things using standard windows control sad.gif
sriram
QUOTE(mixcherry @ Aug 23 2006, 19:17) *

Thanks, that worked (I also had to make old_lb static). But what if I want to use some non-static fields/methods of my class inside lb_proc?...


you might be able to get away with storing a pointer to your class in GWL_USERDATA, although I don't think it is safe to use in windows you didn't create...

You could also have a static global list to keep track of window handles and class pointers, although there may be a better way wink.gif
kode54
In that case, SetProp/GetProp/RemoveProp.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Invision Power Board © 2001-2008 Invision Power Services, Inc.