Win32 child windows not getting mouse clicks

Started by
3 comments, last by Galapaegos 17 years, 8 months ago
I'm writing a plug-in for another application. In my plug-in, I can create a settings window, when handed a parent window HWND. What I do is create an "empty" window (WS_CHILD style) to sit inside the parent HWND, and then create my controls (a ListView and a Button) inside this empty window. So far so good; this works. However, I can't get mouse clicking to dispatch to the controls. Clicking the windows does nothing. Keyboard input works; I can keyboard navigate and activate the button with spacebar (and scroll the list view); I just can't click. So, what's causing the mouse messages to not get to the children? The sad thing is that I recall having had this problem a few years back, but I'm drawing a blank on what the cause was at the time. Googling doesn't work, because all the words I can think of are too common. Here's some code; the host is setting up the parent window:

	t.style = WS_POPUPWINDOW|WS_DLGFRAME|DS_MODALFRAME|DS_CENTER;
	t.cx = 100;
	t.cy = 100;
	DialogBoxIndirectParam (GetModuleHandle (0), &t, 0, (DLGPROC)EditorProc, (LPARAM)plugin);


INT_PTR CALLBACK EditorProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_INITDIALOG :
		{
			SetWindowText (hwnd, "The Title");
			SetTimer (hwnd, 1, 20, 0);

			if(plugin)
			{
				plugin->dispatcheropen(hwnd);
				ERect* eRect = 0;
				effect->getRect(&eRect);
				if(eRect)
				{
					int width = eRect->right - eRect->left;
					int height = eRect->bottom - eRect->top;
					if(width < 100)
						width = 100;
					if(height < 100)
						height = 100;

					RECT wRect;
					SetRect (&wRect, 0, 0, width, height);
					AdjustWindowRectEx (&wRect, GetWindowLong (hwnd, GWL_STYLE), FALSE, GetWindowLong (hwnd, GWL_EXSTYLE));
					width = wRect.right - wRect.left;
					height = wRect.bottom - wRect.top;

					SetWindowPos (hwnd, HWND_TOP, 0, 0, width, height, SWP_NOMOVE);
				}
			}
		}
		break;

// removed CLOSE and TIMER handlers...

	}

	return 0;
}

Here is how my plug-in handles the open() call:


// this is slightly paraphrased, as there's really a wrapper class involved

bool Editor::open(void *ptr)
{
  PluginBase::open(ptr);
  //  ptr is a HWND
  window_ = ::CreateWindowEx(
    WS_EX_LEFT | WS_EX_CONTROLPARENT,
    myClass_,
    "Editor",
    WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN,
    0,
    0,
    500,
    300,
    (HWND)ptr,
    0,
    hInstance,
    someWrapper_);

  // listView styles are WS_VISIBLE | WS_CHILD | LVS_REPORT | LVS_NOSORTHEADER | 
  //    LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_TABSTOP;
  // listView exStyles are WS_EX_LEFT | WS_EX_ACCEPTFILES;
  listView_ = ... wrapper function ...
  listView_->enableExtendedStyles(LVS_EX_FULLROWSELECT | LVS_EX_FLATSB | 
      LVS_EX_TWOCLICKACTIVATE | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES);
  listView_->addColumn("A", 40); // wrappers for ListView_InsertColumn()
  listView_->addColumn("B", 40);
  listView_->addColumn("C", 40);
  listView_->addColumn("D", 40);
  listView_->addColumn("File", 400);

  for (int i = 0; i < 128; ++i) {
    listView_->addRow(i);  // wrapper for ListView_InsertRow()
  }

  button_ = ::CreateWindowEx(
    WS_EX_LEFT,
    WC_BUTTON,
    "Push Me!",
    WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON | BS_CENTER | WS_TABSTOP,
    10,
    270,
    100,
    25,
    window_,
    0,
    hInstance,
    0);

  HCURSOR hc = (HCURSOR)::LoadImage(0, (LPCTSTR)OCR_NORMAL, IMAGE_CURSOR, 0, 0, LR_SHARED);
  ::SetCursor(hc);
  return true;
}


Window class registration for the top window is:

  // registering class on load-up
  INITCOMMONCONTROLSEX iccex;
  memset(&iccex, 0, sizeof(iccex));
  iccex.dwSize = sizeof(iccex);
  iccex.dwICC = ICC_BAR_CLASSES | ICC_LINK_CLASS | ICC_STANDARD_CLASSES | 
      ICC_USEREX_CLASSES | ICC_LISTVIEW_CLASSES;
  ::InitCommonControlsEx(&iccex);
  WNDCLASSEX wcex;
  memset(&wcex, 0, sizeof(wcex));
  wcex.cbSize = sizeof(wcex);
  wcex.style = CS_DROPSHADOW | CS_OWNDC;
  wcex.lpfnWndProc = &Win32Window::wndProc;
  wcex.cbClsExtra = 0;
  wcex.cbWndExtra = 0;
  wcex.hInstance = (HINSTANCE)hInstance;
  wcex.hIcon = 0;
  wcex.hCursor = (HCURSOR)::LoadImage(0, (LPCTSTR)OCR_NORMAL, IMAGE_CURSOR, 0, 0, LR_SHARED);
  wcex.hbrBackground = (HBRUSH)::GetStockObject(COLOR_BACKGROUND+1);
  wcex.lpszMenuName = 0;
  wcex.lpszClassName = "jwSP-class";
  wcex.hIconSm = 0;
  myClass_ = ::RegisterClassEx(&wcex);


LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  LONG_PTR lp = ::GetWindowLongPtr(hWnd, GWL_USERDATA);
  if (!lp && msg == WM_NCCREATE) {
    lp = reinterpret_cast<LONG_PTR>(((CREATESTRUCT const *)lParam)->lpCreateParams);
  }
  Win32Window * wp = reinterpret_cast<Win32Window *>(lp);
  LRESULT ret = 0;
  if (wp != NULL) {
    if (msg == WM_NCCREATE) {
      wp->window_->setWindow(wp);
    }
    bool x = wp->window_->wndProc(msg, wParam, lParam, &ret);
    if (msg == WM_DESTROY) {
      wp->destroyed_ = true;
      if (!wp->deleted_) {
        delete wp;
      }
    }
    //  Warning! Window may have been deleted at this point!
    if (x) {
      // the wrapper wndProc just returns false, so this path is never taken
      // (confirmed with a breakpoint)
      return ret;
    }
  }
  //  Warning! Window may have been deleted at this point!
  return ::DefWindowProc(hWnd, msg, wParam, lParam);
}

enum Bool { True, False, FileNotFound };
Advertisement
first thing i would do is check Spy++ to see who is getting the messages. check the button or the listview first and try clicking, see what happens. if nothing, try the child containter. if nothing, try the dialog parent. if the dialog parent is getting all the mouse messages, call GetCapture too see if the dialog has the capture. if it does, you might have a stray SetCapture somewhere. also, check to make sure the child container isn't disabled, that would cause the parent to receive all mouse messages as well.
Y-Go
Thanks for the suggestions. I've already checked that there is no stray capture, and I've already checked that the windows are not disabled (in fact, I added a superfluous EnableWindow() when creating the window), but I'll check with Spy++ what happens to the messages.
enum Bool { True, False, FileNotFound };
Nothing like waking up fresh in the morning to fix a problem. I had set the parent of the child windows to the wrong window (the top level window) so the "container" window was on top of the children and catching all the messages. Stupid bug, like all bugs once you find them :-) Thanks for the Spy++ suggestion, btw.
enum Bool { True, False, FileNotFound };
hplus0603,

Is the button and listview children to the window titled "EDITOR"? If it is, I would suggest making just a "STATIC" with the WS_GROUP style, I've found those to be better containers. Also, is this your own homebrew window library?

-brad
-brad

This topic is closed to new replies.

Advertisement