5

在 Win32 应用程序中,是否有一条 Windows 消息或一些其他通知,当它被放置到不同的父窗口时,它会被发送到子窗口

4

3 回答 3

3

这很容易在 Windows 窗体应用程序中进行测试。这是我看到的:

msg=0x18 (WM_SHOWWINDOW) hwnd=0x60c60 wparam=0x1 lparam=0x0 result=0x0
msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x60c60 wparam=0x0 lparam=0x563e01c result=0x0
msg=0x85 (WM_NCPAINT) hwnd=0x60c60 wparam=0x1 lparam=0x0 result=0x0
msg=0x14 (WM_ERASEBKGND) hwnd=0x60c60 wparam=0xffffffff930119e8 lparam=0x0 result=0x0
msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x60c60 wparam=0x0 lparam=0x563e01c result=0x0
msg=0xf (WM_PAINT) hwnd=0x60c60 wparam=0x0 lparam=0x0 result=0x0
msg=0xe (WM_GETTEXTLENGTH) hwnd=0x60c60 wparam=0x0 lparam=0x0 result=0x0
msg=0xd (WM_GETTEXT) hwnd=0x60c60 wparam=0x6 lparam=0x3fd7928 result=0x0

WM_SHOWWINDOW 将是检查父级是否更改的好时机。不是 100% 确定这是否是 WF 代码照顾已更改的父级的副作用,可能性相当高。否则没有专门的消息,假设程序已经知道,因为它显式调用了 SetParent 或 SetWindowLongPtr。

于 2010-10-04T21:00:51.250 回答
0

没有专门针对此的单一通知。然而,一些框架,如 Borland 的 VCL,将窗口包装在类中,因此当类对象从一个父对象移动到另一个父对象时(例如,VCL 具有 、 和 通知),它们会发出自己CM_CONTROLLISTCHANGINGCM_CONTROLLISTCHANGE通知CM_CONTROLCHANGE

您能否通过检测父窗口中的更改来提供有关您想要完成的更多信息?

于 2010-10-04T21:20:33.623 回答
0

有点...我在使用 Windows 之间的消息传递之前已经完成了这项工作,并使用了一个线程来监听它们。请记住,您不想从任何线程修改 UI,然后是创建它的线程...

这是父窗口的一些示例代码,它会通过其子窗口之一获得更改通知。在做你所说的事情时,同样的原则也适用。当孩子打开时,父窗口并没有真正发送消息,(它是,但我忘记了当时在想什么)......自从我不得不做这样的事情已经有 10 年了......但是下面的代码是为带有网格的父窗口设计的,以及打开的子“添加/编辑”窗口,当您添加或编辑项目时,它将更新模态编辑窗口后面的父 GRID。这是在 MFC 中设计的,因此您可以想象,您只需在函数调用中添加一些 HWND 变量即可使其在 Win32 下工作,因为 Win32 和 MFC 是如此相互关联。

首先,在父窗口中,我设置了一个线程:

DWORD WINAPI PopulateGridThread(void *ptr)
{
   CMeterReadings *pThis = (CMeterReadings*)ptr;
   pThis->hGridMutex = CreateMutex(NULL, FALSE, "Wims.MeterReadingGridUpdateMutex");
   WaitForSingleObject(pThis->hGridMutex, 0);
   if(WaitForSingleObject(pThis->hGridMutex, 0) != WAIT_OBJECT_0) {
      return -2;
   }
   try {
      if(pThis->m_Get.GetCheck() == FALSE)
      {
         if(pThis->m_Grid.IsEmpty())
         {
            CloseHandle(pThis->hGridMutex);
            CloseHandle(pThis->hThreadHandle);
            pThis->hThreadHandle = INVALID_HANDLE_VALUE;
            pThis->m_DateFilter.EnableWindow(pThis->m_UseDate.GetCheck());
            pThis->m_UseDate.EnableWindow(TRUE);
            pThis->m_MeterFilter.EnableWindow(TRUE);
            return -3;
         }
      }

      pThis->hCursor = LoadCursor(NULL, IDC_APPSTARTING);
      pThis->m_Get.SetCheck(FALSE);
      pThis->m_DateFilter.EnableWindow(FALSE);
      pThis->m_UseDate.EnableWindow(FALSE);
      pThis->m_MeterFilter.EnableWindow(FALSE);
      pThis->m_Grid.PushRow();
      pThis->m_Grid.ResetContent();
      bool        bSuccess = false;
      long        nId = CCommonDialog::GetItemData(pThis->m_MeterFilter);
      bool        bUseDate = pThis->m_UseDate.GetCheck() == TRUE;
      CProDate   dtFilterDate;
      pThis->m_DateFilter.GetTime(dtFilterDate);

      if(nId == NULLCONSTANT || nId == LB_ERR)
      {
          bSuccess  = pThis->m_EquipmentPtr.LoadFirstMeterReading(bUseDate ?   CProDate::GetDateOnly(dtFilterDate) : CProDate::NullDate(), true);
      }
      else
      {
          bSuccess = pThis->m_EquipmentPtr.LoadFirstMeterReadingByMeterId(nId, bUseDate ? CProDate::GetDateOnly(dtFilterDate) : CProDate::NullDate());
   }      
   if(pThis->m_EquipmentPtr.GetRecordsReturned() > 5000) 
   {
      if(ThrowQuestion("This expansion could take a long time.  Do you wish to continue?", pThis) == IDNO)
      {
         bSuccess = false;
      }
   }      
   pThis->m_Get.SetWindowText("&Stop");
   if(bSuccess)
   {
      pThis->m_Grid.Redraw(false);
      do
      {
         pThis->m_Grid.AddGridRow();
         pThis->m_Grid.SetCellFormat(COLUMN_ADJUSTMENT,               "Yes;No");
         pThis->m_Grid.SetCheck(COLUMN_ADJUSTMENT,                    pThis->m_EquipmentPtr.AdjustmentIndc);
         pThis->m_Grid.AddDatesToGrid(pThis->m_EquipmentPtr.ReadingDate,     pThis->m_EquipmentPtr.EffectiveDate);
         pThis->m_Grid.AddTextToGrid(COLUMN_METER,                    pThis->m_EquipmentPtr.MeterDesc);
         /* Cut the rest of the fields, as they aren't important... */
      }
      while(pThis->m_EquipmentPtr.LoadNextMeterReading());
   }
   pThis->m_Grid.FinishGrid();
   pThis->m_Grid.Redraw(true);
   pThis->m_Grid.PopRow();
   pThis->m_Grid.RedrawWindow();
}
CATCH_COM_ERROR("CMeterReadings::PopulateGridThread()")
CloseHandle(pThis->hGridMutex);
CloseHandle(pThis->hThreadHandle);
pThis->hThreadHandle = INVALID_HANDLE_VALUE;
pThis->m_DateFilter.EnableWindow(pThis->m_UseDate.GetCheck());
pThis->m_UseDate.EnableWindow(TRUE);
pThis->m_MeterFilter.EnableWindow(TRUE);
pThis->hCursor = LoadCursor(NULL, IDC_ARROW);
pThis->m_Get.SetWindowText("&Get");
return 1;

}

然后,在子窗口中,当需要更新时,我会向父窗口发送一条消息。我通过创建一个简单地发送消息的线程来做到这一点,以便对话框的其余部分继续运行......(或者在你的情况下,你可以直接向子 Windows HWND 发送消息以使其更新...... .)

void _cdecl GridUpdateThread(void *ptr)
{
   CEnterMeterReadingsDlg *pthis = (CEnterMeterReadingsDlg*)ptr;
   if(pthis->NotifyParent())
   {
      pthis->NotifyParent()->SendMessage(CMeterReadings::GRID_UPDATE_MESSAGE, 0, 0);
   }
}

然后,当用户在对话框中选择“下一步”而不是“确定”或“取消”时,所有这一切都开始了……

_beginthread(GridUpdateThread, NULL, this);

好吧,希望这会对你有所帮助,或者给你一些想法......

于 2010-10-04T22:19:41.220 回答