winapi - 如何通过 OCM_ 消息处理未处理的 Win32 消息反射到子级控件

标签 winapi controls messaging

我在 CodeProject 上发现了以下内容。这是有意义的,除非子类控件不处理 OCM_ 消息,这意味着原始消息的默认处理永远不会发生。是否有一个优雅的解决方案,而不必总是将该函数发送的消息与子类 Windows 过程同步?

LRESULT DefParentProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
  switch (umsg) {
    case WM_NOTIFY:
    {
      NMHDR* nmhdr = (NMHDR*)lparam;
      if (nmhdr->hwndFrom != NULL)
        return SendMessage(nmhdr->hwndFrom, umsg + OCM__BASE, wparam, lparam);
      break;
    }

    // All of these provide the control's HHWND in LPARAM
    case WM_COMMAND:
    case WM_CTLCOLORBTN:
    case WM_CTLCOLOREDIT:
    case WM_CTLCOLORDLG:
    case WM_CTLCOLORLISTBOX:
    case WM_CTLCOLORMSGBOX:
    case WM_CTLCOLORSCROLLBAR:
    case WM_CTLCOLORSTATIC:
    case WM_VKEYTOITEM:
    case WM_CHARTOITEM:
      if (lparam != 0)
        return SendMessage((HWND)lparam, umsg + OCM__BASE, wparam, lparam);
      break;

  // All of these provide ID of the control in WPARAM:
    case WM_DRAWITEM:
    case WM_MEASUREITEM:
    case WM_DELETEITEM:
    case WM_COMPAREITEM:
      if (wparam != 0) {
        HWND hwndControl = GetDlgItem(hwnd, wparam);
        if (hwndControl)
          return SendMessage(hwndControl, umsg + OCM__BASE, wparam, lparam);
      }
      break;

    // Note we do not reflect WM_PARENTNOTIFY -> OCM_PARENTNOTIFY as that 
    // usually does not make much sense.
  }

  return DefWindowProc(hwnd, umsg, wparam, lparam);
}

最佳答案

这里并没有真正的干净解决方案。

您可以确保在针对未处理的 OCM_... 消息调用 DefWindowProc() 时,所有子控件都会减去 OCM__BASE

LRESULT WINAPI DefChildProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
  switch (umsg) {
    ...
  }

  if ((umsg >= OCM__BASE) && (umsg <= OCM__MAX)) {
    umsg -= OCM__BASE;
  }

  return DefWindowProc(hwnd, umsg, wparam, lparam);
}

否则,您可以让每个 OCM_... 消息携带一个指向其 WPARAMLPARAM 中的结构的指针,其中该结构包含真实的 WPARAM/LPARAM 和输出 LRESULT,然后每个子控件可以在给定的情况下返回 TRUE OCM_... 消息已处理。如果 SendMessage(OCM_...) 返回 FALSE,则父级可以使用原始 WM_... 消息调用 DefWindowProc()。 p>

struct OCMInfo
{
  LPARAM lParam;
  LRESULT lResult;
};

LRESULT WINAPI DefParentProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
  switch (umsg) {
    case WM_NOTIFY:
    {
      NMHDR* nmhdr = (NMHDR*)lparam;
      if (nmhdr->hwndFrom != NULL)
      {
        OCMInfo info;
        info.lParam = lParam;
        info.lResult = 0;
        if (SendMessage(nmhdr->hwndFrom, umsg + OCM__BASE, wparam, (LPARAM)&info))
          return info.lResult;
      }
      break;
    }

    // All of these provide the control's HHWND in LPARAM
    case WM_COMMAND:
    case WM_CTLCOLORBTN:
    case WM_CTLCOLOREDIT:
    case WM_CTLCOLORDLG:
    case WM_CTLCOLORLISTBOX:
    case WM_CTLCOLORMSGBOX:
    case WM_CTLCOLORSCROLLBAR:
    case WM_CTLCOLORSTATIC:
    case WM_VKEYTOITEM:
    case WM_CHARTOITEM:
      if (lparam != 0)
      {
        OCMInfo info;
        info.lParam = lParam;
        info.lResult = 0;
        if (SendMessage((HWND)lparam, umsg + OCM__BASE, wparam, (LPARAM)&info))
          return info.lResult;
      }
      break;

  // All of these provide ID of the control in WPARAM:
    case WM_DRAWITEM:
    case WM_MEASUREITEM:
    case WM_DELETEITEM:
    case WM_COMPAREITEM:
      if (wparam != 0) {
        HWND hwndControl = GetDlgItem(hwnd, wparam);
        if (hwndControl)
        {
          OCMInfo info;
          info.lParam = lParam;
          info.lResult = 0;
          if (SendMessage(hwndControl, umsg + OCM__BASE, wparam, (LPARAM)&info))
            return info.lResult;
        }
      }
      break;

    // Note we do not reflect WM_PARENTNOTIFY -> OCM_PARENTNOTIFY as that 
    // usually does not make much sense.
  }

  return DefWindowProc(hwnd, umsg, wparam, lparam);
}

LRESULT WINAPI DefChildProc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
  switch (umsg) {
    case OCM__NOTIFY:
    {
      OCMInfo* info = (OCMInfo*)lparam;
      NMHDR* nmhdr = (NMHDR*)(info->lparam);
      if (...) {
        ...
        info->lResult = ...;
        return TRUE;
      }
      break;
    }

    case OCM__COMMAND:
    {
      OCMInfo* info = (OCMInfo*)lparam;
      if (...) {
        ...
        info->lResult = ...;
        return TRUE;
      }
      break;
    }

    ...
  }

  return DefWindowProc(hwnd, umsg, wparam, lparam);
}

关于winapi - 如何通过 OCM_ 消息处理未处理的 Win32 消息反射到子级控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56780239/

相关文章:

HTML5 禁用默认控件

android - 使用 Smack API 的基于 XMPP 的消息传递应用程序的正确架构

MongoDB - 从每个对话中获取最后一条消息?

c++ - 在 win32 进程崩溃时防止模态对话框

c++ - USB hid 设备插入/移除检测 winapi

文件路径控制

node.js - zeroMQ vs node.js vs beanstalkd vs Twisted

c++ - 将 2 个 int 值从子进程传递给父进程的方法

linux - 我可以将 O_DIRECT 用于写入请求以避免在电源故障期间丢失数据吗?

controls - VAL语言与工业机器人速度控制