message.c

来自「一个类似windows」· C语言 代码 · 共 1,775 行 · 第 1/4 页

C
1,775
字号
   }
   return 0;
}

static 
LRESULT FASTCALL
co_IntSendMessageTimeoutSingle(HWND hWnd,
                               UINT Msg,
                               WPARAM wParam,
                               LPARAM lParam,
                               UINT uFlags,
                               UINT uTimeout,
                               ULONG_PTR *uResult)
{
   ULONG_PTR Result;
   NTSTATUS Status;
   PWINDOW_OBJECT Window = NULL;
   PMSGMEMORY MsgMemoryEntry;
   INT lParamBufferSize;
   LPARAM lParamPacked;
   PW32THREAD Win32Thread;
   DECLARE_RETURN(LRESULT);
   USER_REFERENCE_ENTRY Ref;

   /* FIXME: Call hooks. */
   if (!(Window = UserGetWindowObject(hWnd)))
   {
       RETURN( FALSE);
   }
   
   UserRefObjectCo(Window, &Ref);

   Win32Thread = PsGetWin32Thread();

   if (NULL != Win32Thread &&
         Window->MessageQueue == Win32Thread->MessageQueue)
   {
      if (Win32Thread->IsExiting)
      {
         /* Never send messages to exiting threads */
          RETURN( FALSE);
      }

      /* See if this message type is present in the table */
      MsgMemoryEntry = FindMsgMemory(Msg);
      if (NULL == MsgMemoryEntry)
      {
         lParamBufferSize = -1;
      }
      else
      {
         lParamBufferSize = MsgMemorySize(MsgMemoryEntry, wParam, lParam);
      }

      if (! NT_SUCCESS(PackParam(&lParamPacked, Msg, wParam, lParam)))
      {
         DPRINT1("Failed to pack message parameters\n");
          RETURN( FALSE);
      }

      Result = (ULONG_PTR)co_IntCallWindowProc(Window->WndProc, !Window->Unicode, hWnd, Msg, wParam,
               lParamPacked,lParamBufferSize);

      if(uResult)
      {
         *uResult = Result;
      }

      if (! NT_SUCCESS(UnpackParam(lParamPacked, Msg, wParam, lParam)))
      {
         DPRINT1("Failed to unpack message parameters\n");
          RETURN( TRUE);
      }

       RETURN( TRUE);
   }

   if(uFlags & SMTO_ABORTIFHUNG && MsqIsHung(Window->MessageQueue))
   {
      /* FIXME - Set a LastError? */
       RETURN( FALSE);
   }

   if(Window->Status & WINDOWSTATUS_DESTROYING)
   {
      /* FIXME - last error? */
      DPRINT1("Attempted to send message to window 0x%x that is being destroyed!\n", hWnd);
       RETURN( FALSE);
   }

   Status = co_MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam,
                              uTimeout, (uFlags & SMTO_BLOCK), FALSE, uResult);


   if (STATUS_TIMEOUT == Status)
   {
      /* MSDN says GetLastError() should return 0 after timeout */
      SetLastWin32Error(0);
       RETURN( FALSE);
   }
   else if (! NT_SUCCESS(Status))
   {
      SetLastNtError(Status);
       RETURN( FALSE);
   }

   RETURN( TRUE);
   
CLEANUP:
   if (Window) UserDerefObjectCo(Window);
   END_CLEANUP;
}

LRESULT FASTCALL
co_IntSendMessageTimeout(HWND hWnd,
                         UINT Msg,
                         WPARAM wParam,
                         LPARAM lParam,
                         UINT uFlags,
                         UINT uTimeout,
                         ULONG_PTR *uResult)
{
   PWINDOW_OBJECT DesktopWindow;
   HWND *Children;
   HWND *Child;

   if (HWND_BROADCAST != hWnd)
   {
      return co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, uFlags, uTimeout, uResult);
   }

   DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
   if (NULL == DesktopWindow)
   {
      SetLastWin32Error(ERROR_INTERNAL_ERROR);
      return 0;
   }

   Children = IntWinListChildren(DesktopWindow);
   if (NULL == Children)
   {
      return 0;
   }

   for (Child = Children; NULL != *Child; Child++)
   {
      co_IntSendMessageTimeoutSingle(*Child, Msg, wParam, lParam, uFlags, uTimeout, uResult);
   }

   ExFreePool(Children);

   return (LRESULT) TRUE;
}


/* This function posts a message if the destination's message queue belongs to
   another thread, otherwise it sends the message. It does not support broadcast
   messages! */
LRESULT FASTCALL
co_IntPostOrSendMessage(HWND hWnd,
                        UINT Msg,
                        WPARAM wParam,
                        LPARAM lParam)
{
   ULONG_PTR Result;
   PWINDOW_OBJECT Window;

   if(hWnd == HWND_BROADCAST)
   {
      return 0;
   }

   if(!(Window = UserGetWindowObject(hWnd)))
   {
      return 0;
   }

   if(Window->MessageQueue != PsGetWin32Thread()->MessageQueue)
   {
      Result = UserPostMessage(hWnd, Msg, wParam, lParam);
   }
   else
   {
      if(!co_IntSendMessageTimeoutSingle(hWnd, Msg, wParam, lParam, SMTO_NORMAL, 0, &Result))
      {
         Result = 0;
      }
   }

   return (LRESULT)Result;
}

LRESULT FASTCALL
co_IntDoSendMessage(HWND hWnd,
                    UINT Msg,
                    WPARAM wParam,
                    LPARAM lParam,
                    PDOSENDMESSAGE dsm,
                    PNTUSERSENDMESSAGEINFO UnsafeInfo)
{
   LRESULT Result = TRUE;
   NTSTATUS Status;
   PWINDOW_OBJECT Window;
   NTUSERSENDMESSAGEINFO Info;
   MSG UserModeMsg;
   MSG KernelModeMsg;
   PMSGMEMORY MsgMemoryEntry;

   RtlZeroMemory(&Info, sizeof(NTUSERSENDMESSAGEINFO));

   /* FIXME: Call hooks. */
   if (HWND_BROADCAST != hWnd)
   {
      Window = UserGetWindowObject(hWnd);
      if (NULL == Window)
      {
         /* Tell usermode to not touch this one */
         Info.HandledByKernel = TRUE;
         MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
         return 0;
      }
   }

   /* FIXME: Check for an exiting window. */

   /* See if the current thread can handle the message */
   if (HWND_BROADCAST != hWnd && NULL != PsGetWin32Thread() &&
         Window->MessageQueue == PsGetWin32Thread()->MessageQueue)
   {
      /* Gather the information usermode needs to call the window proc directly */
      Info.HandledByKernel = FALSE;

      Status = MmCopyFromCaller(&(Info.Ansi), &(UnsafeInfo->Ansi),
                                sizeof(BOOL));
      if (! NT_SUCCESS(Status))
      {
         Info.Ansi = ! Window->Unicode;
      }

      if (Window->IsSystem)
      {
          Info.Proc = (!Info.Ansi ? Window->WndProc : Window->WndProcExtra);
      }
      else
      {
          Info.Ansi = !Window->Unicode;
          Info.Proc = Window->WndProc;
      }
   }
   else
   {
      /* Must be handled by other thread */
//      if (HWND_BROADCAST != hWnd)
//      {
//         UserDerefObject(Window);
//      }
      Info.HandledByKernel = TRUE;
      UserModeMsg.hwnd = hWnd;
      UserModeMsg.message = Msg;
      UserModeMsg.wParam = wParam;
      UserModeMsg.lParam = lParam;
      MsgMemoryEntry = FindMsgMemory(UserModeMsg.message);
      Status = CopyMsgToKernelMem(&KernelModeMsg, &UserModeMsg, MsgMemoryEntry);
      if (! NT_SUCCESS(Status))
      {
         MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
         SetLastWin32Error(ERROR_INVALID_PARAMETER);
         return (dsm ? 0 : -1);
      }
      if(!dsm)
      {
         Result = co_IntSendMessage(KernelModeMsg.hwnd, KernelModeMsg.message,
                                    KernelModeMsg.wParam, KernelModeMsg.lParam);
      }
      else
      {
         Result = co_IntSendMessageTimeout(KernelModeMsg.hwnd, KernelModeMsg.message,
                                           KernelModeMsg.wParam, KernelModeMsg.lParam,
                                           dsm->uFlags, dsm->uTimeout, &dsm->Result);
      }
      Status = CopyMsgToUserMem(&UserModeMsg, &KernelModeMsg);
      if (! NT_SUCCESS(Status))
      {
         MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
         SetLastWin32Error(ERROR_INVALID_PARAMETER);
         return(dsm ? 0 : -1);
      }
   }

   Status = MmCopyToCaller(UnsafeInfo, &Info, sizeof(NTUSERSENDMESSAGEINFO));
   if (! NT_SUCCESS(Status))
   {
      SetLastWin32Error(ERROR_INVALID_PARAMETER);
   }

   return (LRESULT)Result;
}

LRESULT STDCALL
NtUserSendMessageTimeout(HWND hWnd,
                         UINT Msg,
                         WPARAM wParam,
                         LPARAM lParam,
                         UINT uFlags,
                         UINT uTimeout,
                         ULONG_PTR *uResult,
                         PNTUSERSENDMESSAGEINFO UnsafeInfo)
{
   DOSENDMESSAGE dsm;
   LRESULT Result;
   DECLARE_RETURN(BOOL);

   DPRINT("Enter NtUserSendMessageTimeout\n");
   UserEnterExclusive();

   dsm.uFlags = uFlags;
   dsm.uTimeout = uTimeout;
   Result = co_IntDoSendMessage(hWnd, Msg, wParam, lParam, &dsm, UnsafeInfo);
   if(uResult != NULL && Result != 0)
   {
      NTSTATUS Status;

      Status = MmCopyToCaller(uResult, &dsm.Result, sizeof(ULONG_PTR));
      if(!NT_SUCCESS(Status))
      {
         SetLastWin32Error(ERROR_INVALID_PARAMETER);
         RETURN( FALSE);
      }
   }
   RETURN( Result);

CLEANUP:
   DPRINT("Leave NtUserSendMessageTimeout, ret=%i\n",_ret_);
   UserLeave();
   END_CLEANUP;
}

LRESULT STDCALL
NtUserSendMessage(HWND Wnd,
                  UINT Msg,
                  WPARAM wParam,
                  LPARAM lParam,
                  PNTUSERSENDMESSAGEINFO UnsafeInfo)
{
   DECLARE_RETURN(BOOL);

   DPRINT("Enter NtUserSendMessage\n");
   UserEnterExclusive();

   RETURN(co_IntDoSendMessage(Wnd, Msg, wParam, lParam, NULL, UnsafeInfo));

CLEANUP:
   DPRINT("Leave NtUserSendMessage, ret=%i\n",_ret_);
   UserLeave();
   END_CLEANUP;
}

BOOL STDCALL
NtUserSendMessageCallback(HWND hWnd,
                          UINT Msg,
                          WPARAM wParam,
                          LPARAM lParam,
                          SENDASYNCPROC lpCallBack,
                          ULONG_PTR dwData)
{
   UNIMPLEMENTED;

   return 0;
}

BOOL STDCALL
NtUserSendNotifyMessage(HWND hWnd,
                        UINT Msg,
                        WPARAM wParam,
                        LPARAM lParam)
{
   UNIMPLEMENTED;

   return 0;
}

BOOL STDCALL
NtUserWaitMessage(VOID)
{
   DECLARE_RETURN(BOOL);

   DPRINT("EnterNtUserWaitMessage\n");
   UserEnterExclusive();

   RETURN(co_IntWaitMessage(NULL, 0, 0));

CLEANUP:
   DPRINT("Leave NtUserWaitMessage, ret=%i\n",_ret_);
   UserLeave();
   END_CLEANUP;
}

DWORD STDCALL
NtUserGetQueueStatus(BOOL ClearChanges)
{
   PUSER_MESSAGE_QUEUE Queue;
   DWORD Result;
   DECLARE_RETURN(DWORD);

   DPRINT("Enter NtUserGetQueueStatus\n");
   UserEnterExclusive();

   Queue = PsGetWin32Thread()->MessageQueue;

   Result = MAKELONG(Queue->QueueBits, Queue->ChangedBits);
   if (ClearChanges)
   {
      Queue->ChangedBits = 0;
   }

   RETURN( Result);

CLEANUP:
   DPRINT("Leave NtUserGetQueueStatus, ret=%i\n",_ret_);
   UserLeave();
   END_CLEANUP;
}

BOOL STDCALL
IntInitMessagePumpHook()
{
   ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->MessagePumpHookValue++;
   return TRUE;
}

BOOL STDCALL
IntUninitMessagePumpHook()
{
   if (((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->MessagePumpHookValue <= 0)
   {
      return FALSE;
   }
   ((PW32THREAD)PsGetCurrentThread()->Tcb.Win32Thread)->MessagePumpHookValue--;
   return TRUE;
}

/* EOF */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?