Fix the USER32 DLL initialization and cleanup routines to prevent memory/resource...
[reactos.git] / reactos / lib / user32 / windows / message.c
index b46f5af..3169308 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: message.c,v 1.39 2004/04/29 21:13:16 gvg Exp $
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS user32.dll
  * FILE:            lib/user32/windows/message.c
@@ -8,17 +7,13 @@
  * UPDATE HISTORY:
  *      06-06-2001  CSH  Created
  */
-#include <windows.h>
+
 #include <user32.h>
-#include <string.h>
+#define NDEBUG
 #include <debug.h>
-#include <user32/callback.h>
-#include <message.h>
-#define NTOS_MODE_USER
-#include <ntos.h>
 
 /* DDE message exchange
- * 
+ *
  * - Session initialization
  *   Client sends a WM_DDE_INITIATE message, usually a broadcast message. lParam of
  *   this message contains a pair of global atoms, the Application and Topic atoms.
@@ -94,7 +89,7 @@ DdeAddPair(HGLOBAL ClientMem, HGLOBAL ServerMem)
         }
       else
         {
-          New = HeapAlloc(GetProcessHeap(), 0, 
+          New = HeapAlloc(GetProcessHeap(), 0,
                           (DdeNumAlloc + GROWBY) * sizeof(DDEPAIR));
         }
 
@@ -192,12 +187,13 @@ MsgiUMToKMMessage(PMSG UMMsg, PMSG KMMsg, BOOL Posted)
           KMMsg->lParam = (LPARAM) DdeLparam;
         }
         break;
+
       case WM_DDE_EXECUTE:
         {
           SIZE_T Size;
           PKMDDEEXECUTEDATA KMDdeExecuteData;
           PVOID Data;
-          
+
           Size = GlobalSize((HGLOBAL) UMMsg->lParam);
           Data = GlobalLock((HGLOBAL) UMMsg->lParam);
           if (NULL == Data)
@@ -219,6 +215,31 @@ MsgiUMToKMMessage(PMSG UMMsg, PMSG KMMsg, BOOL Posted)
           GlobalUnlock((HGLOBAL) UMMsg->lParam);
         }
         break;
+
+      case WM_COPYDATA:
+        {
+          PCOPYDATASTRUCT pUMCopyData = (PCOPYDATASTRUCT)UMMsg->lParam;
+          PCOPYDATASTRUCT pKMCopyData;
+
+          pKMCopyData = HeapAlloc(GetProcessHeap(), 0,
+                                  sizeof(COPYDATASTRUCT) + pUMCopyData->cbData);
+          if (pKMCopyData == NULL)
+            {
+              SetLastError(ERROR_OUTOFMEMORY);
+              return FALSE;
+            }
+
+          pKMCopyData->dwData = pUMCopyData->dwData;
+          pKMCopyData->cbData = pUMCopyData->cbData;
+          pKMCopyData->lpData = pKMCopyData + 1;
+
+          RtlCopyMemory(pKMCopyData + 1, pUMCopyData->lpData,
+                        pUMCopyData->cbData);
+
+          KMMsg->lParam = (LPARAM)pKMCopyData;
+        }
+        break;
+
       default:
         break;
     }
@@ -233,6 +254,7 @@ MsgiUMToKMCleanup(PMSG UMMsg, PMSG KMMsg)
     {
       case WM_DDE_ACK:
       case WM_DDE_EXECUTE:
+      case WM_COPYDATA:
         HeapFree(GetProcessHeap(), 0, (LPVOID) KMMsg->lParam);
         break;
       default:
@@ -257,6 +279,27 @@ MsgiKMToUMMessage(PMSG KMMsg, PMSG UMMsg)
 
   switch (UMMsg->message)
     {
+      case WM_CREATE:
+      case WM_NCCREATE:
+        {
+          CREATESTRUCTW *Cs = (CREATESTRUCTW *) KMMsg->lParam;
+          PCHAR Class;
+          Cs->lpszName = (LPCWSTR) ((PCHAR) Cs + (DWORD_PTR) Cs->lpszName);
+          Class = (PCHAR) Cs + (DWORD_PTR) Cs->lpszClass;
+          if (L'A' == *((WCHAR *) Class))
+            {
+              Class += sizeof(WCHAR);
+              Cs->lpszClass = (LPCWSTR)(DWORD_PTR) (*((ATOM *) Class));
+            }
+          else
+            {
+              ASSERT(L'S' == *((WCHAR *) Class));
+              Class += sizeof(WCHAR);
+              Cs->lpszClass = (LPCWSTR) Class;
+            }
+        }
+        break;
+
       case WM_DDE_ACK:
         {
           PKMDDELPARAM DdeLparam = (PKMDDELPARAM) KMMsg->lParam;
@@ -270,8 +313,9 @@ MsgiKMToUMMessage(PMSG KMMsg, PMSG UMMsg)
             {
               UMMsg->lParam = DdeLparam->Value.Unpacked;
             }
-          break;
         }
+        break;
+
       case WM_DDE_EXECUTE:
         {
           PKMDDEEXECUTEDATA KMDdeExecuteData;
@@ -301,6 +345,14 @@ MsgiKMToUMMessage(PMSG KMMsg, PMSG UMMsg)
           UMMsg->lParam = (LPARAM) GlobalData;
         }
         break;
+
+      case WM_COPYDATA:
+        {
+          PCOPYDATASTRUCT pKMCopyData = (PCOPYDATASTRUCT)KMMsg->lParam;
+          pKMCopyData->lpData = pKMCopyData + 1;
+        }
+        break;
+
       default:
         break;
     }
@@ -520,15 +572,6 @@ MsgiAnsiToUnicodeReply(LPMSG UnicodeMsg, LPMSG AnsiMsg, LRESULT *Result)
           }
         break;
       }
-
-    case WM_GETTEXTLENGTH:
-    case CB_GETLBTEXTLEN:
-    case LB_GETTEXTLEN:
-      {
-        /* FIXME: There may be one DBCS char for each Unicode char */
-        *Result *= 2;
-        break;
-      }
     }
 
   MsgiAnsiToUnicodeCleanup(UnicodeMsg, AnsiMsg);
@@ -582,7 +625,18 @@ MsgiUnicodeToAnsiMessage(LPMSG AnsiMsg, LPMSG UnicodeMsg)
                 }
               CsA->lpszClass = AString.Buffer;
             }
-          UnicodeMsg->lParam = (LPARAM)CsA;
+          AnsiMsg->lParam = (LPARAM)CsA;
+          break;
+        }
+      case WM_GETTEXT:
+        {
+          /* Ansi string might contain MBCS chars so we need 2 * the number of chars */
+          AnsiMsg->wParam = UnicodeMsg->wParam * 2;
+          AnsiMsg->lParam = (LPARAM) RtlAllocateHeap(GetProcessHeap(), 0, AnsiMsg->wParam);
+          if (NULL == (PVOID) AnsiMsg->lParam)
+            {
+              return FALSE;
+            }
           break;
         }
       case WM_SETTEXT:
@@ -611,6 +665,10 @@ MsgiUnicodeToAnsiCleanup(LPMSG AnsiMsg, LPMSG UnicodeMsg)
   switch(UnicodeMsg->message)
     {
       case WM_GETTEXT:
+        {
+          RtlFreeHeap(GetProcessHeap(), 0, (PVOID) AnsiMsg->lParam);
+          break;
+        }
       case WM_SETTEXT:
         {
           ANSI_STRING AString;
@@ -654,22 +712,13 @@ MsgiUnicodeToAnsiReply(LPMSG AnsiMsg, LPMSG UnicodeMsg, LRESULT *Result)
         if (0 < AnsiMsg->wParam &&
             ! MultiByteToWideChar(CP_ACP, 0, Buffer, -1, UBuffer, UnicodeMsg->wParam))
           {
-            UBuffer[AnsiMsg->wParam - 1] = L'\0';
+            UBuffer[UnicodeMsg->wParam - 1] = L'\0';
           }
         break;
       }
-
-    case WM_GETTEXTLENGTH:
-    case CB_GETLBTEXTLEN:
-    case LB_GETTEXTLEN:
-      {
-        /* FIXME: There may be one DBCS char for each Unicode char */
-        *Result /= sizeof(WCHAR);
-        break;
-      }
     }
 
-  MsgiUnicodeToAnsiCleanup(UnicodeMsg, AnsiMsg);
+  MsgiUnicodeToAnsiCleanup(AnsiMsg, UnicodeMsg);
 
   return TRUE;
 }
@@ -708,7 +757,7 @@ MsgConversionAdd(PMSGCONVERSION Conversion)
         }
       else
         {
-          New = HeapAlloc(GetProcessHeap(), 0, 
+          New = HeapAlloc(GetProcessHeap(), 0,
                           (MsgConversionNumAlloc + GROWBY) * sizeof(MSGCONVERSION));
         }
 
@@ -830,8 +879,13 @@ BOOL
 STDCALL
 InSendMessage(VOID)
 {
+  static DWORD ShowNotImplemented = TRUE;
+  if (ShowNotImplemented)
+    {
+      DbgPrint("InSendMessage is unimplemented\n");
+      ShowNotImplemented = FALSE;
+    }
   /* return(NtUserGetThreadState(THREADSTATE_INSENDMESSAGE) != ISMEX_NOSEND); */
-  UNIMPLEMENTED;
   return FALSE;
 }
 
@@ -909,7 +963,7 @@ IntCallWindowProcW(BOOL IsAnsiProc,
     }
 }
 
-STATIC LRESULT FASTCALL
+static LRESULT FASTCALL
 IntCallWindowProcA(BOOL IsAnsiProc,
                    WNDPROC WndProc,
                    HWND hWnd,
@@ -1575,7 +1629,7 @@ SendMessageTimeoutW(
   LRESULT Result;
 
   Info.Ansi = FALSE;
-  Result = NtUserSendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout, 
+  Result = NtUserSendMessageTimeout(hWnd, Msg, wParam, lParam, fuFlags, uTimeout,
                                     lpdwResult, &Info);
   if (! Info.HandledByKernel)
     {
@@ -1723,7 +1777,7 @@ STDCALL
 RealGetQueueStatus(UINT flags)
 {
    DWORD ret;
-   WORD changed_bits, wake_bits; 
+   WORD changed_bits, wake_bits;
 
 #if 0 /* wine stuff. don't know what it does... */
 
@@ -1749,7 +1803,7 @@ BOOL STDCALL GetInputState(VOID)
    DWORD ret;
    WORD  wake_bits;
 
-#if 0 /* wine stuff. don't know what it does... */ 
+#if 0 /* wine stuff. don't know what it does... */
 
    /* check for pending X events */
    if (USER_Driver.pMsgWaitForMultipleObjectsEx)
@@ -1757,7 +1811,7 @@ BOOL STDCALL GetInputState(VOID)
 #endif
 
    ret = NtUserGetQueueStatus(FALSE /*ClearChanges*/);
-   
+
    wake_bits = HIWORD(ret);
 
    return wake_bits & (QS_KEY | QS_MOUSEBUTTON);
@@ -1866,7 +1920,9 @@ BOOL WINAPI IsInsideMessagePumpHook()
 {
        if(!gfMessagePumpHook)
                return FALSE;
-       
+
+    /* This code checks if we're inside SendMessage. */
+#if 0
        /* Since our TEB doesnt match that of real windows, testing this value is useless until we know what it does
        PUCHAR NtTeb = (PUCHAR)NtCurrentTeb();
 
@@ -1875,6 +1931,7 @@ BOOL WINAPI IsInsideMessagePumpHook()
 
        if(**(PLONG*)&NtTeb[0x708] <= 0)
                return FALSE;*/
+#endif
 
        return TRUE;
 }
@@ -1916,7 +1973,7 @@ BOOL WINAPI RegisterMessagePumpHook(MESSAGEPUMPHOOKPROC Hook)
                return FALSE;
        }
        if (!gcLoadMPH++) {
-               InterlockedExchange(&gfMessagePumpHook, 1);
+               InterlockedExchange((PLONG)&gfMessagePumpHook, 1);
        }
        LeaveCriticalSection(&gcsMPH);
        return TRUE;
@@ -1929,7 +1986,7 @@ BOOL WINAPI UnregisterMessagePumpHook(VOID)
                if(NtUserCallNoParam(NOPARAM_ROUTINE_UNINIT_MESSAGE_PUMP)) {
                        gcLoadMPH--;
                        if(!gcLoadMPH) {
-                               InterlockedExchange(&gfMessagePumpHook, 0);
+                               InterlockedExchange((PLONG)&gfMessagePumpHook, 0);
                                gpfnInitMPH(TRUE, NULL);
                                ResetMessagePumpHook(&gmph);
                                gpfnInitMPH = 0;
@@ -1947,15 +2004,173 @@ DWORD WINAPI GetQueueStatus(UINT flags)
        return IsInsideMessagePumpHook() ? gmph.RealGetQueueStatus(flags) : RealGetQueueStatus(flags);
 }
 
-DWORD WINAPI MsgWaitForMultipleObjectsEx(DWORD nCount, CONST HANDLE *lpHandles, DWORD dwMilliseconds, DWORD dwWakeMask, DWORD dwFlags)
+/**
+ * @name RealMsgWaitForMultipleObjectsEx
+ *
+ * Wait either for either message arrival or for one of the passed events
+ * to be signalled.
+ *
+ * @param nCount
+ *        Number of handles in the pHandles array.
+ * @param pHandles
+ *        Handles of events to wait for.
+ * @param dwMilliseconds
+ *        Timeout interval.
+ * @param dwWakeMask
+ *        Mask specifying on which message events we should wakeup.
+ * @param dwFlags
+ *        Wait type (see MWMO_* constants).
+ *
+ * @implemented
+ */
+
+DWORD STDCALL
+RealMsgWaitForMultipleObjectsEx(
+   DWORD nCount,
+   const HANDLE *pHandles,
+   DWORD dwMilliseconds,
+   DWORD dwWakeMask,
+   DWORD dwFlags)
+{
+   LPHANDLE RealHandles;
+   HANDLE MessageQueueHandle;
+   DWORD Result;
+
+   if (dwFlags & ~(MWMO_WAITALL | MWMO_ALERTABLE | MWMO_INPUTAVAILABLE))
+   {
+      SetLastError(ERROR_INVALID_PARAMETER);
+      return WAIT_FAILED;
+   }
+
+/*
+   if (dwFlags & MWMO_INPUTAVAILABLE)
+   {
+      RealGetQueueStatus(dwWakeMask);
+   }
+   */
+
+   MessageQueueHandle = NtUserMsqSetWakeMask(dwWakeMask);
+   if (MessageQueueHandle == NULL)
+   {
+      SetLastError(0); /* ? */
+      return WAIT_FAILED;
+   }
+
+   RealHandles = HeapAlloc(GetProcessHeap(), 0, (nCount + 1) * sizeof(HANDLE));
+   if (RealHandles == NULL)
+   {
+      NtUserMsqClearWakeMask();
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+      return WAIT_FAILED;
+   }
+
+   RtlCopyMemory(RealHandles, pHandles, nCount * sizeof(HANDLE));
+   RealHandles[nCount] = MessageQueueHandle;
+
+   Result = WaitForMultipleObjectsEx(nCount + 1, RealHandles,
+                                     dwFlags & MWMO_WAITALL,
+                                     dwMilliseconds, dwFlags & MWMO_ALERTABLE);
+
+   HeapFree(GetProcessHeap(), 0, RealHandles);
+   NtUserMsqClearWakeMask();
+
+   return Result;
+}
+
+/*
+ * @implemented
+ */
+DWORD WINAPI
+MsgWaitForMultipleObjectsEx(
+   DWORD nCount,
+   CONST HANDLE *lpHandles,
+   DWORD dwMilliseconds,
+   DWORD dwWakeMask,
+   DWORD dwFlags)
+{
+   return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
+}
+
+/*
+ * @implemented
+ */
+DWORD STDCALL
+MsgWaitForMultipleObjects(
+   DWORD nCount,
+   CONST HANDLE *lpHandles,
+   BOOL fWaitAll,
+   DWORD dwMilliseconds,
+   DWORD dwWakeMask)
 {
-       return IsInsideMessagePumpHook() ? gmph.RealMsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds, dwWakeMask, dwFlags) : RealMsgWaitForMultipleObjectsEx(nCount, lpHandles,dwMilliseconds, dwWakeMask, dwFlags);
+   return MsgWaitForMultipleObjectsEx(nCount, lpHandles, dwMilliseconds,
+                                      dwWakeMask, fWaitAll ? MWMO_WAITALL : 0);
 }
 
-BOOL FASTCALL MessageInit()
+
+BOOL FASTCALL MessageInit(VOID)
 {
   InitializeCriticalSection(&DdeCrst);
   InitializeCriticalSection(&MsgConversionCrst);
+  InitializeCriticalSection(&gcsMPH);
 
   return TRUE;
 }
+
+VOID FASTCALL MessageCleanup(VOID)
+{
+  DeleteCriticalSection(&DdeCrst);
+  DeleteCriticalSection(&MsgConversionCrst);
+  DeleteCriticalSection(&gcsMPH);
+}
+
+/***********************************************************************
+ *             map_wparam_AtoW
+ *
+ * Convert the wparam of an ASCII message to Unicode.
+ */
+static WPARAM
+map_wparam_AtoW( UINT message, WPARAM wparam )
+{
+    switch(message)
+    {
+    case WM_CHARTOITEM:
+    case EM_SETPASSWORDCHAR:
+    case WM_CHAR:
+    case WM_DEADCHAR:
+    case WM_SYSCHAR:
+    case WM_SYSDEADCHAR:
+    case WM_MENUCHAR:
+        {
+            char ch[2];
+            WCHAR wch[2];
+            ch[0] = (wparam & 0xff);
+            ch[1] = (wparam >> 8);
+            MultiByteToWideChar(CP_ACP, 0, ch, 2, wch, 2);
+            wparam = MAKEWPARAM(wch[0], wch[1]);
+        }
+        break;
+    case WM_IME_CHAR:
+        {
+            char ch[2];
+            WCHAR wch;
+            ch[0] = (wparam >> 8);
+            ch[1] = (wparam & 0xff);
+            if (ch[0]) MultiByteToWideChar(CP_ACP, 0, ch, 2, &wch, 1);
+            else MultiByteToWideChar(CP_ACP, 0, &ch[1], 1, &wch, 1);
+            wparam = MAKEWPARAM( wch, HIWORD(wparam) );
+        }
+        break;
+    }
+    return wparam;
+}
+
+/*
+ * @implemented
+ */
+BOOL WINAPI
+IsDialogMessageA( HWND hwndDlg, LPMSG pmsg )
+{
+    MSG msg = *pmsg;
+    msg.wParam = map_wparam_AtoW( msg.message, msg.wParam );
+    return IsDialogMessageW( hwndDlg, &msg );
+}