Winapi 子窗口如何响应其父窗口中的更改

Winapi 子窗口如何响应其父窗口中的更改,winapi,windows-messages,Winapi,Windows Messages,在Win32应用程序中,是否存在Windows消息或其他通知,当它被放置到不同的父窗口时,这些消息或通知将被发送到子窗口?这很容易在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 m

在Win32应用程序中,是否存在Windows消息或其他通知,当它被放置到不同的父窗口时,这些消息或通知将被发送到子窗口?这很容易在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。

没有专门用于此的通知。然而,一些框架,如Borland的VCL,将窗口包装在类中,从而在类对象从一个父对象移动到另一个父对象时发出它们自己的通知(例如,VCL具有
CM\u CONTROLLISTCHANGING
CM\u CONTROLLISTCHANGE
CM\u CONTROLCHANGE
通知)


通过检测父窗口中的更改,您可以提供有关您想要完成的具体操作的更多信息吗?

有点。。。在使用Windows之间的消息传递和一个线程来监听它们之前,我已经这样做了。请记住,您不希望从任何线程修改UI,而不是从创建它的线程修改UI

下面是一个父窗口的示例代码,它的一个子窗口会通知它所做的更改。同样的原则也适用于你所谈论的事情。当孩子打开时,家长的窗口并没有真正地发送信息,(是的,但我忘记了当时孩子的想法)。。。我已经10年没有做过这样的事了。。。但是下面的代码是为带有网格的父窗口和打开的子“添加/编辑”窗口设计的,当您添加或编辑项目时,它将更新模式编辑窗口后面的父网格。这是在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发送消息以使其更新…)

然后,当用户在对话框中选择“下一步”而不是“确定”或“取消”时,所有这些都会启动

_beginthread(GridUpdateThread, NULL, this);

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

我的窗口在一个插件中,该插件正在动态插入宿主程序的窗口层次结构中,我需要检测它何时在主机层次结构中的不同位置之间移动。然后我建议您记录插件窗口实际接收到的消息,然后根据您的需要选择最合适的消息。是的,这就是我现在正在做的,调用GetParent()当我收到一条WM_WINDOWPOSCHANGED消息,并将其与之前的家长有用信息进行比较时,我认为您回答的是另一个问题。在我的确切示例中,是的。但是,我要说的是,他可以用一种方法来监视事情,可能是对SetParent()进行重写,或者类似的方法。该示例的重点是演示如何使用线程和自定义消息在两个窗口之间进行对话。我想他可以用我提到的方法做他想做的事。。。没有任何内置的东西可以为他做这件事……只是想澄清一下,你是在问
SetParent(hwndChild,hwndnnewparent)
是否向hwndChild发送通知?是的,或者孩子是否有其他方法来确定它已被移动到另一个家长?我首先尝试
WM\u WINDOWPOSCHANGED
_beginthread(GridUpdateThread, NULL, this);