Part 1 of the comctl32 sync. I'll do it in 2 stages for testing purposes as it's...
authorGed Murphy <gedmurphy@reactos.org>
Tue, 8 Jun 2010 10:21:26 +0000 (10:21 +0000)
committerGed Murphy <gedmurphy@reactos.org>
Tue, 8 Jun 2010 10:21:26 +0000 (10:21 +0000)
This part includes alpha support for imagelists and tango icons for the common toolbars
I'll do the second part later today. It has a propsheet bug and I'm a bit busy at the mo.

svn path=/trunk/; revision=47695

47 files changed:
reactos/dll/win32/comctl32/animate.c
reactos/dll/win32/comctl32/comboex.c
reactos/dll/win32/comctl32/comctl32.h
reactos/dll/win32/comctl32/comctl32.rbuild
reactos/dll/win32/comctl32/comctl32undoc.c
reactos/dll/win32/comctl32/comctl_Bg.rc
reactos/dll/win32/comctl32/comctl_Cs.rc
reactos/dll/win32/comctl32/comctl_De.rc
reactos/dll/win32/comctl32/comctl_El.rc
reactos/dll/win32/comctl32/comctl_En.rc
reactos/dll/win32/comctl32/comctl_Eo.rc
reactos/dll/win32/comctl32/comctl_Es.rc
reactos/dll/win32/comctl32/comctl_Fr.rc
reactos/dll/win32/comctl32/comctl_Hu.rc
reactos/dll/win32/comctl32/comctl_It.rc
reactos/dll/win32/comctl32/comctl_Ja.rc
reactos/dll/win32/comctl32/comctl_Ko.rc
reactos/dll/win32/comctl32/comctl_Lt.rc
reactos/dll/win32/comctl32/comctl_Nl.rc
reactos/dll/win32/comctl32/comctl_No.rc
reactos/dll/win32/comctl32/comctl_Pl.rc
reactos/dll/win32/comctl32/comctl_Pt.rc
reactos/dll/win32/comctl32/comctl_Ro.rc
reactos/dll/win32/comctl32/comctl_Ru.rc
reactos/dll/win32/comctl32/comctl_Si.rc
reactos/dll/win32/comctl32/comctl_Sk.rc
reactos/dll/win32/comctl32/comctl_Sv.rc
reactos/dll/win32/comctl32/comctl_Th.rc
reactos/dll/win32/comctl32/comctl_Tr.rc
reactos/dll/win32/comctl32/comctl_Uk.rc
reactos/dll/win32/comctl32/comctl_Zh.rc
reactos/dll/win32/comctl32/commctrl.c
reactos/dll/win32/comctl32/datetime.c
reactos/dll/win32/comctl32/dpa.c
reactos/dll/win32/comctl32/draglist.c
reactos/dll/win32/comctl32/header.c
reactos/dll/win32/comctl32/idb_hist_large.bmp
reactos/dll/win32/comctl32/idb_hist_small.bmp
reactos/dll/win32/comctl32/idb_std_large.bmp
reactos/dll/win32/comctl32/idb_std_small.bmp
reactos/dll/win32/comctl32/idb_view_large.bmp
reactos/dll/win32/comctl32/idb_view_small.bmp
reactos/dll/win32/comctl32/imagelist.c
reactos/dll/win32/comctl32/imagelist.h
reactos/dll/win32/comctl32/ipaddress.c
reactos/dll/win32/comctl32/listview.c
reactos/dll/win32/comctl32/monthcal.c

index 3aad68b..a86ff85 100644 (file)
@@ -717,7 +717,7 @@ static BOOL ANIMATE_OpenW(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPWSTR lps
 
     TRACE("(%s)\n", debugstr_w(lpszName));
 
-    if (HIWORD(lpszName))
+    if (!IS_INTRESOURCE(lpszName))
     {
        if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName)) 
         {
@@ -775,7 +775,7 @@ static BOOL ANIMATE_OpenA(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPSTR lpsz
     LRESULT result;
     INT len;
 
-    if (!HIWORD(lpszName))
+    if (IS_INTRESOURCE(lpszName))
         return ANIMATE_OpenW(infoPtr, hInstance, (LPWSTR)lpszName);
 
     len = MultiByteToWideChar(CP_ACP, 0, lpszName, -1, NULL, 0);
index 1484ba8..4b5e079 100644 (file)
@@ -67,8 +67,6 @@ typedef struct
     HWND         hwndNotify;       /* my parent hwnd */
     HWND         hwndCombo;
     HWND         hwndEdit;
-    WNDPROC      prevEditWndProc;  /* previous Edit WNDPROC value */
-    WNDPROC      prevComboWndProc; /* previous Combo WNDPROC value */
     DWORD        dwExtStyle;
     INT          selected;         /* index of selected item */
     DWORD        flags;            /* WINE internal flags */
@@ -121,17 +119,15 @@ typedef struct
 /* Offset between image and text */
 #define CBE_SEP                        4
 
-static const WCHAR COMBOEX_SUBCLASS_PROP[] = {
-    'C','C','C','o','m','b','o','E','x','3','2',
-    'S','u','b','c','l','a','s','s','I','n','f','o',0
-};
+#define COMBO_SUBCLASSID  1
+#define EDIT_SUBCLASSID   2
 
 #define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongPtrW (hwnd, 0))
 
-
-/* Things common to the entire DLL */
-static LRESULT WINAPI COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-static LRESULT WINAPI COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+static LRESULT CALLBACK COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+                                             UINT_PTR uId, DWORD_PTR ref_data);
+static LRESULT CALLBACK COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+                                              UINT_PTR uId, DWORD_PTR ref_data);
 static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr);
 typedef INT (WINAPI *cmp_func_t)(LPCWSTR, LPCWSTR);
 
@@ -177,7 +173,7 @@ static void COMBOEX_DumpInput (COMBOBOXEXITEMW const *input)
 static inline CBE_ITEMDATA *get_item_data(const COMBOEX_INFO *infoPtr, INT index)
 {
     return (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, CB_GETITEMDATA,
-                                        (WPARAM)index, 0);
+                                         index, 0);
 }
 
 static inline cmp_func_t get_cmp_func(COMBOEX_INFO const *infoPtr)
@@ -455,10 +451,7 @@ static void COMBOEX_ReSize (const COMBOEX_INFO *infoPtr)
 static void COMBOEX_SetEditText (const COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item)
 {
     if (!infoPtr->hwndEdit) return;
-    /* native issues the following messages to the {Edit} control */
-    /*      WM_SETTEXT (0,addr)     */
-    /*      EM_SETSEL32 (0,0)       */
-    /*      EM_SETSEL32 (0,-1)      */
+
     if (item->mask & CBEIF_TEXT) {
        SendMessageW (infoPtr->hwndEdit, WM_SETTEXT, 0, (LPARAM)COMBOEX_GetText(infoPtr, item));
        SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0);
@@ -491,13 +484,6 @@ static CBE_ITEMDATA * COMBOEX_FindItem(const COMBOEX_INFO *infoPtr, INT_PTR inde
     return item;
 }
 
-
-static inline BOOL COMBOEX_HasEdit(COMBOEX_INFO const *infoPtr)
-{
-    return infoPtr->hwndEdit ? TRUE : FALSE;
-}
-
-
 /* ***  CBEM_xxx message support  *** */
 
 static UINT COMBOEX_GetListboxText(const COMBOEX_INFO *infoPtr, INT_PTR n, LPWSTR buf)
@@ -510,6 +496,17 @@ static UINT COMBOEX_GetListboxText(const COMBOEX_INFO *infoPtr, INT_PTR n, LPWST
         return 0;
 
     str = COMBOEX_GetText(infoPtr, item);
+    if (!str)
+    {
+        if (buf)
+        {
+            if (infoPtr->unicode)
+                buf[0] = 0;
+            else
+                *((LPSTR)buf) = 0;
+        }
+        return 0;
+    }
 
     if (infoPtr->unicode)
     {
@@ -536,7 +533,7 @@ static INT COMBOEX_DeleteItem (const COMBOEX_INFO *infoPtr, INT_PTR index)
     if (!COMBOEX_FindItem(infoPtr, index)) return CB_ERR;
 
     /* doing this will result in WM_DELETEITEM being issued */
-    SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, (WPARAM)index, 0);
+    SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, index, 0);
 
     return infoPtr->nb_items;
 }
@@ -547,13 +544,13 @@ static BOOL COMBOEX_GetItemW (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
     INT_PTR index = cit->iItem;
     CBE_ITEMDATA *item;
 
-    TRACE("(...)\n");
+    TRACE("\n");
 
     /* if item number requested does not exist then return failure */
     if ((index >= infoPtr->nb_items) || (index < -1)) return FALSE;
 
     /* if the item is the edit control and there is no edit control, skip */
-    if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE;
+    if ((index == -1) && !infoPtr->hwndEdit) return FALSE;
 
     if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE;
 
@@ -567,7 +564,7 @@ static BOOL COMBOEX_GetItemA (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit)
 {
     COMBOBOXEXITEMW tmpcit;
 
-    TRACE("(...)\n");
+    TRACE("\n");
 
     tmpcit.mask = cit->mask;
     tmpcit.iItem = cit->iItem;
@@ -600,8 +597,7 @@ static BOOL COMBOEX_GetItemA (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit)
 
 static inline BOOL COMBOEX_HasEditChanged (COMBOEX_INFO const *infoPtr)
 {
-    return COMBOEX_HasEdit(infoPtr) &&
-          (infoPtr->flags & WCBE_EDITHASCHANGED) == WCBE_EDITHASCHANGED;
+    return infoPtr->hwndEdit && (infoPtr->flags & WCBE_EDITHASCHANGED) == WCBE_EDITHASCHANGED;
 }
 
 
@@ -678,8 +674,7 @@ static INT COMBOEX_InsertItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW const *ci
 
     if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
 
-    SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING,
-                 (WPARAM)cit->iItem, (LPARAM)item);
+    SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING, cit->iItem, (LPARAM)item);
 
     memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem));
     COMBOEX_CopyItem (item, &nmcit.ceItem);
@@ -751,7 +746,7 @@ static HIMAGELIST COMBOEX_SetImageList (COMBOEX_INFO *infoPtr, HIMAGELIST himl)
 {
     HIMAGELIST himlTemp = infoPtr->himl;
 
-    TRACE("(...)\n");
+    TRACE("\n");
 
     infoPtr->himl = himl;
 
@@ -774,7 +769,7 @@ static BOOL COMBOEX_SetItemW (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
     if ((index >= infoPtr->nb_items) || (index < -1)) return FALSE;
 
     /* if the item is the edit control and there is no edit control, skip */
-    if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE;
+    if ((index == -1) && !infoPtr->hwndEdit) return FALSE;
 
     if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE;
 
@@ -802,7 +797,7 @@ static BOOL COMBOEX_SetItemW (const COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit)
     if (cit->mask & CBEIF_INDENT)
         item->iIndent = cit->iIndent;
     if (cit->mask & CBEIF_LPARAM)
-        cit->lParam = cit->lParam;
+        item->lParam = cit->lParam;
 
     if (TRACE_ON(comboex)) COMBOEX_DumpItem (item);
 
@@ -968,12 +963,10 @@ static INT COMBOEX_SetItemHeight (COMBOEX_INFO const *infoPtr, INT index, UINT h
 
 static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
 {
-    static const WCHAR COMBOBOX[] = { 'C', 'o', 'm', 'b', 'o', 'B', 'o', 'x', 0 };
-    static const WCHAR EDIT[] = { 'E', 'D', 'I', 'T', 0 };
     static const WCHAR NIL[] = { 0 };
     COMBOEX_INFO *infoPtr;
     LOGFONTW mylogfont;
-    RECT wnrc1, clrc1, cmbwrc;
+    RECT win_rect;
     INT i;
 
     /* allocate memory for info structure */
@@ -998,11 +991,13 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
 
     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
 
-    /* create combo box */
-    GetWindowRect(hwnd, &wnrc1);
-    GetClientRect(hwnd, &clrc1);
-    TRACE("EX window=(%s), client=(%s)\n",
-          wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1));
+    if (TRACE_ON(comboex)) {
+       RECT client, rect;
+       GetWindowRect(hwnd, &rect);
+       GetClientRect(hwnd, &client);
+       TRACE("EX window=(%s), client=(%s)\n",
+               wine_dbgstr_rect(&rect), wine_dbgstr_rect(&client));
+    }
 
     /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */
     /* specified. It then creates it's own version of the EDIT control  */
@@ -1011,7 +1006,7 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
     /* We also need to place the edit control at the proper location    */
     /* (allow space for the icons).                                     */
 
-    infoPtr->hwndCombo = CreateWindowW (COMBOBOX, NIL,
+    infoPtr->hwndCombo = CreateWindowW (WC_COMBOBOXW, NIL,
                         /* following line added to match native */
                          WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL |
                          CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST |
@@ -1030,22 +1025,16 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
      *  GetCurrentProcessId()
      */
 
-    /*
-     * Setup a property to hold the pointer to the COMBOBOXEX
-     * data structure.
-     */
-    SetPropW(infoPtr->hwndCombo, COMBOEX_SUBCLASS_PROP, hwnd);
-    infoPtr->prevComboWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndCombo,
-                               GWLP_WNDPROC, (DWORD_PTR)COMBOEX_ComboWndProc);
+    SetWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID,
+                      (DWORD_PTR)hwnd);
     infoPtr->font = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0);
 
-
     /*
      * Now create our own EDIT control so we can position it.
      * It is created only for CBS_DROPDOWN style
      */
     if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) {
-       infoPtr->hwndEdit = CreateWindowExW (0, EDIT, NIL,
+       infoPtr->hwndEdit = CreateWindowExW (0, WC_EDITW, NIL,
                    WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL,
                    0, 0, 0, 0,  /* will set later */
                    infoPtr->hwndCombo,
@@ -1058,14 +1047,9 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
         *  GetWindowThreadProcessId(hwndEdit, &???)
         *  GetCurrentProcessId()
         */
+       SetWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID,
+                         (DWORD_PTR)hwnd);
 
-       /*
-        * Setup a property to hold the pointer to the COMBOBOXEX
-        * data structure.
-        */
-        SetPropW(infoPtr->hwndEdit, COMBOEX_SUBCLASS_PROP, hwnd);
-       infoPtr->prevEditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndEdit,
-                                GWLP_WNDPROC, (DWORD_PTR)COMBOEX_EditWndProc);
        infoPtr->font = (HFONT)SendMessageW(infoPtr->hwndCombo, WM_GETFONT, 0, 0);
     }
 
@@ -1081,27 +1065,31 @@ static LRESULT COMBOEX_Create (HWND hwnd, CREATESTRUCTA const *cs)
     SendMessageW (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0);
     if (infoPtr->hwndEdit) {
        SendMessageW (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0);
-       SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, (WPARAM)EC_USEFONTINFO, 0);
+       SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, EC_USEFONTINFO, 0);
     }
 
     COMBOEX_ReSize (infoPtr);
 
     /* Above is fairly certain, below is much less certain. */
 
-    GetWindowRect(hwnd, &wnrc1);
-    GetClientRect(hwnd, &clrc1);
-    GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
-    TRACE("EX window=(%s) client=(%s) CB wnd=(%s)\n",
-          wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1),
-          wine_dbgstr_rect(&cmbwrc));
-    SetWindowPos(infoPtr->hwndCombo, HWND_TOP,
-                0, 0, wnrc1.right-wnrc1.left, wnrc1.bottom-wnrc1.top,
+    GetWindowRect(hwnd, &win_rect);
+
+    if (TRACE_ON(comboex)) {
+       RECT client, rect;
+       GetClientRect(hwnd, &client);
+       GetWindowRect(infoPtr->hwndCombo, &rect);
+       TRACE("EX window=(%s) client=(%s) CB wnd=(%s)\n",
+               wine_dbgstr_rect(&win_rect), wine_dbgstr_rect(&client),
+               wine_dbgstr_rect(&rect));
+    }
+    SetWindowPos(infoPtr->hwndCombo, HWND_TOP, 0, 0,
+                win_rect.right - win_rect.left, win_rect.bottom - win_rect.top,
                 SWP_NOACTIVATE | SWP_NOREDRAW);
 
-    GetWindowRect(infoPtr->hwndCombo, &cmbwrc);
-    TRACE("CB window=(%s)\n", wine_dbgstr_rect(&cmbwrc));
-    SetWindowPos(hwnd, HWND_TOP,
-                0, 0, cmbwrc.right-cmbwrc.left, cmbwrc.bottom-cmbwrc.top,
+    GetWindowRect(infoPtr->hwndCombo, &win_rect);
+    TRACE("CB window=(%s)\n", wine_dbgstr_rect(&win_rect));
+    SetWindowPos(hwnd, HWND_TOP, 0, 0,
+                win_rect.right - win_rect.left, win_rect.bottom - win_rect.top,
                 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
 
     COMBOEX_AdjustEditPos (infoPtr);
@@ -1158,7 +1146,7 @@ static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam)
         */
        ShowWindow (infoPtr->hwndEdit, SW_SHOW);
        InvalidateRect (infoPtr->hwndCombo, 0, TRUE);
-       InvalidateRect (infoPtr->hwndEdit, 0, TRUE);
+       if (infoPtr->hwndEdit) InvalidateRect (infoPtr->hwndEdit, 0, TRUE);
        cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0);
        if (cursel == -1) {
             cmp_func_t cmptext = get_cmp_func(infoPtr);
@@ -1173,8 +1161,7 @@ static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam)
            if ((cursel == n) || ((INT_PTR)item == CB_ERR)) {
                TRACE("failed to find match??? item=%p cursel=%d\n",
                      item, cursel);
-               if (infoPtr->hwndEdit)
-                   SetFocus(infoPtr->hwndEdit);
+               if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit);
                return 0;
            }
        }
@@ -1183,8 +1170,7 @@ static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam)
            if ((INT_PTR)item == CB_ERR) {
                TRACE("failed to find match??? item=%p cursel=%d\n",
                      item, cursel);
-               if (infoPtr->hwndEdit)
-                   SetFocus(infoPtr->hwndEdit);
+               if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit);
                return 0;
            }
        }
@@ -1280,8 +1266,7 @@ static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam)
         * after passing the command to the parent of the ComboEx.
         */
        lret = SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf);
-       if (infoPtr->hwndEdit)
-           SetFocus(infoPtr->hwndEdit);
+       if (infoPtr->hwndEdit) SetFocus(infoPtr->hwndEdit);
        return lret;
     }
     return 0;
@@ -1377,14 +1362,12 @@ static LRESULT COMBOEX_DrawItem (const COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT con
                 (dis->itemAction == ODA_DRAWENTIRE)) {
            /* draw of edit control data */
 
-           /* testing */
-           {
+           if (TRACE_ON(comboex)) {
                RECT exrc, cbrc, edrc;
                GetWindowRect (infoPtr->hwndSelf, &exrc);
                GetWindowRect (infoPtr->hwndCombo, &cbrc);
-               edrc.left=edrc.top=edrc.right=edrc.bottom=-1;
-               if (infoPtr->hwndEdit)
-                   GetWindowRect (infoPtr->hwndEdit, &edrc);
+               edrc.left = edrc.top = edrc.right = edrc.bottom = -1;
+               if (infoPtr->hwndEdit) GetWindowRect (infoPtr->hwndEdit, &edrc);
                 TRACE("window rects ex=(%s), cb=(%s), ed=(%s)\n",
                       wine_dbgstr_rect(&exrc), wine_dbgstr_rect(&cbrc),
                       wine_dbgstr_rect(&edrc));
@@ -1595,8 +1578,12 @@ static void COMBOEX_ResetContent (COMBOEX_INFO *infoPtr)
 static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr)
 {
     if (infoPtr->hwndCombo)
-       DestroyWindow (infoPtr->hwndCombo);
+        RemoveWindowSubclass(infoPtr->hwndCombo, COMBOEX_ComboWndProc, COMBO_SUBCLASSID);
+
+    if (infoPtr->hwndEdit)
+        RemoveWindowSubclass(infoPtr->hwndEdit, COMBOEX_EditWndProc, EDIT_SUBCLASSID);
 
+    COMBOEX_FreeText (infoPtr->edit);
     Free (infoPtr->edit);
     infoPtr->edit = 0;
 
@@ -1720,11 +1707,11 @@ static LRESULT COMBOEX_WindowPosChanging (const COMBOEX_INFO *infoPtr, WINDOWPOS
     return 0;
 }
 
-static LRESULT WINAPI
-COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK
+COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+                     UINT_PTR uId, DWORD_PTR ref_data)
 {
-    HWND hwndComboex = GetPropW(hwnd, COMBOEX_SUBCLASS_PROP);
-    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
+    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data);
     NMCBEENDEDITW cbeend;
     WCHAR edit_text[260];
     COLORREF obkc;
@@ -1744,8 +1731,7 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
            /* handle (ignore) the return character */
            if (wParam == VK_RETURN) return 0;
            /* all other characters pass into the real Edit */
-           return CallWindowProcW (infoPtr->prevEditWndProc,
-                                  hwnd, uMsg, wParam, lParam);
+           return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
        case WM_ERASEBKGND:
            /*
@@ -1757,8 +1743,7 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect));
            ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
             SetBkColor (hDC, obkc);
-           return CallWindowProcW (infoPtr->prevEditWndProc,
-                                  hwnd, uMsg, wParam, lParam);
+           return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
        case WM_KEYDOWN: {
            INT_PTR oldItem, selected, step = 1;
@@ -1864,8 +1849,7 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
                oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0);
                if (oldItem != -1) {
                    /* if something is selected, then deselect it */
-                   SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL,
-                                 (WPARAM)-1, 0);
+                    SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, -1, 0);
                }
                InvalidateRect (infoPtr->hwndCombo, 0, 0);
                SetFocus(infoPtr->hwndEdit);
@@ -1880,16 +1864,14 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
                    SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, oldItem + step, 0);
                return 0;
            default:
-               return CallWindowProcW (infoPtr->prevEditWndProc,
-                                      hwnd, uMsg, wParam, lParam);
+               return DefSubclassProc(hwnd, uMsg, wParam, lParam);
            }
            return 0;
             }
 
        case WM_SETFOCUS:
            /* remember the focus to set state of icon */
-           lret = CallWindowProcW (infoPtr->prevEditWndProc,
-                                  hwnd, uMsg, wParam, lParam);
+           lret = DefSubclassProc(hwnd, uMsg, wParam, lParam);
            infoPtr->flags |= WCBE_EDITFOCUSED;
            return lret;
 
@@ -1912,17 +1894,16 @@ COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
            /* fall through */
 
        default:
-           return CallWindowProcW (infoPtr->prevEditWndProc,
-                                  hwnd, uMsg, wParam, lParam);
+           return DefSubclassProc(hwnd, uMsg, wParam, lParam);
     }
 }
 
 
-static LRESULT WINAPI
-COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK
+COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
+                      UINT_PTR uId, DWORD_PTR ref_data)
 {
-    HWND hwndComboex = GetPropW(hwnd, COMBOEX_SUBCLASS_PROP);
-    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex);
+    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr ((HWND)ref_data);
     NMCBEENDEDITW cbeend;
     NMMOUSE nmmse;
     COLORREF obkc;
@@ -1947,8 +1928,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             * that ComboEx knows this is listbox.
             */
            ((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX;
-           return CallWindowProcW (infoPtr->prevComboWndProc,
-                                  hwnd, uMsg, wParam, lParam);
+           return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
     case WM_ERASEBKGND:
            /*
@@ -1960,8 +1940,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
             TRACE("erasing (%s)\n", wine_dbgstr_rect(&rect));
            ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0);
             SetBkColor (hDC, obkc);
-           return CallWindowProcW (infoPtr->prevComboWndProc,
-                                  hwnd, uMsg, wParam, lParam);
+           return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
     case WM_SETCURSOR:
            /*
@@ -1975,8 +1954,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
            nmmse.pt.y = 0;
            nmmse.dwHitInfo = lParam;
            COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse);
-           return CallWindowProcW (infoPtr->prevComboWndProc,
-                                  hwnd, uMsg, wParam, lParam);
+           return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
     case WM_LBUTTONDOWN:
            GetClientRect (hwnd, &rect);
@@ -1986,16 +1964,16 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
            pt.x = (short)LOWORD(lParam);
            pt.y = (short)HIWORD(lParam);
            if (PtInRect(&rect, pt))
-               return CallWindowProcW (infoPtr->prevComboWndProc,
-                                       hwnd, uMsg, wParam, lParam);
+               return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+
            infoPtr->flags |= WCBE_MOUSECAPTURED;
            SetCapture(hwnd);
            break;
 
     case WM_LBUTTONUP:
            if (!(infoPtr->flags & WCBE_MOUSECAPTURED))
-               return CallWindowProcW (infoPtr->prevComboWndProc,
-                                       hwnd, uMsg, wParam, lParam);
+               return DefSubclassProc(hwnd, uMsg, wParam, lParam);
+
            ReleaseCapture();
            infoPtr->flags &= ~WCBE_MOUSECAPTURED;
            if (infoPtr->flags & WCBE_MOUSEDRAGGED) {
@@ -2012,8 +1990,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
                COMBOEX_NotifyDragBegin(infoPtr, edit_text);
                infoPtr->flags |= WCBE_MOUSEDRAGGED;
            }
-           return CallWindowProcW (infoPtr->prevComboWndProc,
-                                   hwnd, uMsg, wParam, lParam);
+           return DefSubclassProc(hwnd, uMsg, wParam, lParam);
 
     case WM_COMMAND:
            switch (HIWORD(wParam)) {
@@ -2157,8 +2134,7 @@ COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
                break;
            }/* fall through */
     default:
-           return CallWindowProcW (infoPtr->prevComboWndProc,
-                                  hwnd, uMsg, wParam, lParam);
+           return DefSubclassProc(hwnd, uMsg, wParam, lParam);
     }
     return 0;
 }
index 3008314..3d172ae 100644 (file)
@@ -231,18 +231,7 @@ extern void UPDOWN_Unregister(void);
 
 
 int MONTHCAL_MonthLength(int month, int year);
-
-static inline void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to)
-{
-  to->wYear = from->wYear;
-  to->wMonth = from->wMonth;
-  to->wDayOfWeek = from->wDayOfWeek;
-  to->wDay = from->wDay;
-  to->wHour = from->wHour;
-  to->wMinute = from->wMinute;
-  to->wSecond = from->wSecond;
-  to->wMilliseconds = from->wMilliseconds;
-}
+int MONTHCAL_CalculateDayOfWeek(SYSTEMTIME *date, BOOL inplace);
 
 extern void THEMING_Initialize(void);
 extern void THEMING_Uninitialize(void);
index 150241f..958edb0 100644 (file)
@@ -47,6 +47,7 @@
        <file>treeview.c</file>
        <file>updown.c</file>
        <file>rsrc.rc</file>
+       <library>uuid</library>
        <library>wine</library>
        <library>user32</library>
        <library>gdi32</library>
index ee684c6..ff94051 100644 (file)
@@ -885,9 +885,11 @@ INT WINAPI EnumMRUListA (HANDLE hList, INT nItemPos, LPVOID lpBuffer,
     } else {
         lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
                                   NULL, 0, NULL, NULL);
-       datasize = min( witem->size, nBufferSize );
+       datasize = min( lenA, nBufferSize );
        WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1,
                            lpBuffer, datasize, NULL, NULL);
+        ((char *)lpBuffer)[ datasize - 1 ] = '\0';
+        datasize = lenA - 1;
     }
     TRACE("(%p, %d, %p, %d): returning len=%d\n",
          hList, nItemPos, lpBuffer, nBufferSize, datasize);
index 94dd870..6c64f9a 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index 63cc0bb..e770e33 100644 (file)
@@ -20,6 +20,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
 
 /* Czech strings in CP1250 */
index 831e2ee..87730c8 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
+#pragma code_page(65001)
+
 LANGUAGE LANG_GERMAN, SUBLANG_NEUTRAL
 
 STRINGTABLE DISCARDABLE
 {
-     IDS_CLOSE    "Schließen"
+     IDS_CLOSE    "Schließen"
 }
 
 STRINGTABLE DISCARDABLE
@@ -41,7 +45,7 @@ STRINGTABLE DISCARDABLE
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
 STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Eigenschaften für %s"
+CAPTION "Eigenschaften für %s"
 FONT 8, "MS Shell Dlg"
 BEGIN
   DEFPUSHBUTTON "&OK",        IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
@@ -57,9 +61,9 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
 CAPTION "Wizard"
 FONT 8, "MS Shell Dlg"
 BEGIN
-  PUSHBUTTON    "< &Zurück", IDC_BACK_BUTTON,71,138,50,14
+  PUSHBUTTON    "< &Zurück", IDC_BACK_BUTTON,71,138,50,14
   DEFPUSHBUTTON "&Weiter >", IDC_NEXT_BUTTON,121,138,50,14
-  DEFPUSHBUTTON "&Beenden",   IDC_FINISH_BUTTON,121,138,50,14
+  DEFPUSHBUTTON "&Fertig",   IDC_FINISH_BUTTON,121,138,50,14
   PUSHBUTTON    "Abbrechen", IDCANCEL,178,138,50,14
   PUSHBUTTON    "&Hilfe",     IDHELP,235,138,50,14,WS_GROUP
   LTEXT         "",          IDC_SUNKEN_LINE,7,129,278,1,SS_SUNKEN
@@ -73,15 +77,15 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
 CAPTION "Toolbar einrichten"
 FONT 8, "MS Shell Dlg"
 BEGIN
-  DEFPUSHBUTTON "&Schließen",               IDCANCEL,308,6,44,14
-  PUSHBUTTON    "&Zurücksetzen",            IDC_RESET_BTN,308,23,44,14
+  DEFPUSHBUTTON "&Schließen",               IDCANCEL,308,6,44,14
+  PUSHBUTTON    "&Zurücksetzen",            IDC_RESET_BTN,308,23,44,14
   PUSHBUTTON    "&Hilfe",                   IDC_HELP_BTN,308,40,44,14
   PUSHBUTTON    "Nach &Oben verschieben",   IDC_MOVEUP_BTN,308,74,44,14
   PUSHBUTTON    "Nach &Unten verschieben",  IDC_MOVEDN_BTN,308,91,44,14
-  LTEXT         "&Vorhandene Knöpfe:", -1,4,5,84,10
+  LTEXT         "&Vorhandene Knöpfe:", -1,4,5,84,10
   LISTBOX       IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
-  PUSHBUTTON    "H&inzufügen ->",           IDOK, 131, 42, 44, 14
-  PUSHBUTTON    "<- &Löschen",              IDC_REMOVE_BTN,131,62,44,14
-  LTEXT         "&Toolbarknöpfe:", -1,182,5,78,10
+  PUSHBUTTON    "H&inzufügen ->",           IDOK, 131, 42, 44, 14
+  PUSHBUTTON    "<- &Löschen",              IDC_REMOVE_BTN,131,62,44,14
+  LTEXT         "&Toolbarknöpfe:", -1,182,5,78,10
   LISTBOX       IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
 END
index a505620..de08357 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_GREEK, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index 369eecd..d8055e9 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index bda1817..59fe39e 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_ESPERANTO, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index ea2968e..ce46217 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index df56339..2fd2f89 100644 (file)
@@ -3,7 +3,7 @@
  * French language support
  *
  * Copyright 1999 Eric Kohl
- * Copyright 2003 Vincent Béron
+ * Copyright 2003 Vincent Béron
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
+/* UTF-8 */
+#pragma code_page(65001)
+
 LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
 STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Propriétés pour %s"
+CAPTION "Propriétés pour %s"
 FONT 8, "MS Shell Dlg"
 BEGIN
   DEFPUSHBUTTON "OK",     IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
@@ -40,9 +45,9 @@ STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
 CAPTION "Assistant"
 FONT 8, "MS Shell Dlg"
 BEGIN
-  PUSHBUTTON    "< &Précédent", IDC_BACK_BUTTON,71,138,50,14
-  DEFPUSHBUTTON "&Suivant >", IDC_NEXT_BUTTON,121,138,50,14
-  DEFPUSHBUTTON "Terminer", IDC_FINISH_BUTTON,121,138,50,14
+  PUSHBUTTON    "< &Précédent", IDC_BACK_BUTTON,71,138,50,14
+  DEFPUSHBUTTON "&Suivant >", IDC_NEXT_BUTTON,123,138,50,14
+  DEFPUSHBUTTON "Terminer", IDC_FINISH_BUTTON,123,138,50,14
   PUSHBUTTON    "Annuler", IDCANCEL,178,138,50,14
   PUSHBUTTON    "Aide",    IDHELP,235,138,50,14,WS_GROUP
   LTEXT         "",        IDC_SUNKEN_LINE,7,129,278,1,SS_SUNKEN
@@ -57,15 +62,15 @@ CAPTION "Personnaliser la barre d'outils"
 FONT 8, "MS Shell Dlg"
 BEGIN
   DEFPUSHBUTTON "&Fermer",  IDCANCEL,308,6,44,14
-  PUSHBUTTON    "&Réinitialiser", IDC_RESET_BTN,308,23,44,14
+  PUSHBUTTON    "&Réinitialiser", IDC_RESET_BTN,308,23,44,14
   PUSHBUTTON    "Aid&e",    IDC_HELP_BTN,308,40,44,14
   PUSHBUTTON    "&Monter",  IDC_MOVEUP_BTN,308,74,44,14
   PUSHBUTTON    "&Descendre", IDC_MOVEDN_BTN,308,91,44,14
-  LTEXT         "Boutons disponibles :", -1,4,5,84,10
+  LTEXT         "Boutons &disponibles :", -1,4,5,84,10
   LISTBOX       IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
   PUSHBUTTON    "A&jouter ->",    IDOK, 131, 42, 44, 14
   PUSHBUTTON    "<- E&nlever", IDC_REMOVE_BTN,131,62,44,14
-  LTEXT         "&Boutons de la barre d'outils :", -1,182,5,78,10
+  LTEXT         "&Boutons de la barre d'outils :", -1,182,5,93,10
   LISTBOX       IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
 END
 
@@ -77,12 +82,12 @@ STRINGTABLE DISCARDABLE
 STRINGTABLE DISCARDABLE
 {
     IDM_TODAY    "Aujourd'hui:"
-    IDM_GOTODAY  "Aller à aujourd'hui"
+    IDM_GOTODAY  "Aller à aujourd'hui"
 }
 
 STRINGTABLE DISCARDABLE
 {
-    IDS_SEPARATOR "Séparateur"
+    IDS_SEPARATOR "Séparateur"
 }
 
 STRINGTABLE DISCARDABLE
index 6019777..2ba1160 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index 2b2f315..75bd9c1 100644 (file)
@@ -17,6 +17,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_ITALIAN, SUBLANG_NEUTRAL
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index e3c1272..ce16f5a 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 /* UTF-8 */
 #pragma code_page(65001)
 
@@ -23,7 +25,7 @@ LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
 STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Properties for %s"
+CAPTION "%sのプロパティ"
 FONT 9, "MS Shell Dlg"
 BEGIN
   DEFPUSHBUTTON "OK",     IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
@@ -36,11 +38,11 @@ END
 
 IDD_WIZARD DIALOG DISCARDABLE 0, 0, 290, 159
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Wizard"
+CAPTION "ウィザード"
 FONT 9, "MS Shell Dlg"
 BEGIN
   PUSHBUTTON    "< 戻る(&B)", IDC_BACK_BUTTON,71,138,50,14
-  DEFPUSHBUTTON "進む(&N) >", IDC_NEXT_BUTTON,121,138,50,14
+  DEFPUSHBUTTON "次へ(&N) >", IDC_NEXT_BUTTON,121,138,50,14
   DEFPUSHBUTTON "完了",  IDC_FINISH_BUTTON,121,138,50,14
   PUSHBUTTON    "キャンセル",  IDCANCEL,178,138,50,14
   PUSHBUTTON    "ヘルプ",    IDHELP,235,138,50,14,WS_GROUP
@@ -52,7 +54,7 @@ END
 
 IDD_TBCUSTOMIZE DIALOG DISCARDABLE 10, 20, 357, 125
 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-CAPTION "Customize Toolbar"
+CAPTION "ツールバーのカスタマイズ"
 FONT 9, "MS Shell Dlg"
 BEGIN
   DEFPUSHBUTTON "閉じる(&C)",     IDCANCEL,308,6,44,14
@@ -60,33 +62,31 @@ BEGIN
   PUSHBUTTON    "ヘルプ(&H)",      IDC_HELP_BTN,308,40,44,14
   PUSHBUTTON    "上へ (&U)",   IDC_MOVEUP_BTN,308,74,44,14
   PUSHBUTTON    "下へ (&D)", IDC_MOVEDN_BTN,308,91,44,14
-  LTEXT         "A&vailable buttons:", -1,4,5,84,10
+  LTEXT         "利用可能なボタン(&V):", -1,4,5,84,10
   LISTBOX       IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
   PUSHBUTTON    "追加(&A) ->",    IDOK, 131, 42, 44, 14
   PUSHBUTTON    "<- 削除(&R)", IDC_REMOVE_BTN,131,62,44,14
-  LTEXT         "&Toolbar buttons:", -1,182,5,78,10
+  LTEXT         "ツールバーのボタン(&T):", -1,182,5,78,10
   LISTBOX       IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
 END
 
 STRINGTABLE DISCARDABLE
 {
-    IDS_CLOSE    "Close"
+    IDS_CLOSE    "閉じる"
 }
 
 STRINGTABLE DISCARDABLE
 {
-    IDM_TODAY    "Today:"
-    IDM_GOTODAY  "Go to today"
+    IDM_TODAY    "今日:"
+    IDM_GOTODAY  "今日へ移動"
 }
 
 STRINGTABLE DISCARDABLE
 {
-    IDS_SEPARATOR "Separator"
+    IDS_SEPARATOR "区切り"
 }
 
 STRINGTABLE DISCARDABLE
 {
-    HKY_NONE "None"
+    HKY_NONE "なし"
 }
-
-#pragma code_page(default)
index 6574b66..daf9917 100644 (file)
@@ -17,6 +17,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index bfe0986..f5f3294 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 /* UTF-8 */
 #pragma code_page(65001)
 
@@ -88,5 +90,3 @@ STRINGTABLE DISCARDABLE
 {
     HKY_NONE "Joks"
 }
-
-#pragma code_page(default)
index a277b0f..fe2bf7a 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_DUTCH, SUBLANG_NEUTRAL
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
@@ -75,7 +77,7 @@ STRINGTABLE DISCARDABLE
 STRINGTABLE DISCARDABLE
 {
     IDM_TODAY    "Vandaag:"
-    IDM_GOTODAY  "Ga vandaag naar"
+    IDM_GOTODAY  "Ga naar vandaag"
 }
 
 STRINGTABLE DISCARDABLE
index 77b9ec8..6361f04 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index 9144134..12f13a6 100644 (file)
@@ -17,6 +17,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index 3ab75fd..914c4c2 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright 2003 Marcelo Duarte
- * Copyright 2006-2007 Américo José Melo
+ * Copyright 2006-2007 Américo José Melo
+ * Copyright 2009 Ricardo Filipe
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
+#include "comctl32.h"
 
-IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
-STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Propriedades para %s"
-FONT 8, "MS Shell Dlg"
-BEGIN
-  DEFPUSHBUTTON "OK",     IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
-  PUSHBUTTON    "Cancelar", IDCANCEL,58,122,50,14
-  PUSHBUTTON    "&Aplicar", IDC_APPLY_BUTTON,112,122,50,14,WS_DISABLED
-  PUSHBUTTON    "Ajuda",   IDHELP,166,122,50,14,WS_TABSTOP|WS_GROUP
-  CONTROL       "Tab",    IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS|WS_GROUP|WS_TABSTOP|TCS_MULTILINE,4,4,212,114
-END
+#pragma code_page(65001)
 
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE
+LANGUAGE LANG_PORTUGUESE, SUBLANG_NEUTRAL
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
 STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
@@ -45,27 +36,21 @@ BEGIN
   CONTROL       "Separador",    IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS|WS_GROUP|WS_TABSTOP|TCS_MULTILINE,4,4,212,114
 END
 
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
 IDD_WIZARD DIALOG DISCARDABLE 0, 0, 290, 159
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
 CAPTION "Assistente"
 FONT 8, "MS Shell Dlg"
 BEGIN
   PUSHBUTTON    "< &Voltar", IDC_BACK_BUTTON,71,138,50,14
-  DEFPUSHBUTTON "&Avançar >", IDC_NEXT_BUTTON,121,138,50,14
+  DEFPUSHBUTTON "&Avançar >", IDC_NEXT_BUTTON,121,138,50,14
   DEFPUSHBUTTON "Finalizar",  IDC_FINISH_BUTTON,121,138,50,14
   PUSHBUTTON    "Cancelar",  IDCANCEL,178,138,50,14
   PUSHBUTTON    "Ajuda",    IDHELP,235,138,50,14,WS_GROUP
   LTEXT         "",        IDC_SUNKEN_LINE,7,129,278,1,SS_SUNKEN
-  CONTROL       "Tab",     IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS | WS_DISABLED,7,7,258,5
+  CONTROL       "Separador",     IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS | WS_DISABLED,7,7,258,5
   LTEXT                "",        IDC_SUNKEN_LINEHEADER,0,35,290,1,SS_LEFT | SS_SUNKEN | WS_CHILD | WS_VISIBLE
 END
 
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
 IDD_TBCUSTOMIZE DIALOG DISCARDABLE 10, 20, 357, 125
 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
 CAPTION "Personalizar barra de ferramentas"
@@ -76,42 +61,30 @@ BEGIN
   PUSHBUTTON    "&Ajuda",      IDC_HELP_BTN,308,40,44,14
   PUSHBUTTON    "A&cima",   IDC_MOVEUP_BTN,308,74,44,14
   PUSHBUTTON    "A&baixo", IDC_MOVEDN_BTN,308,91,44,14
-  LTEXT         "Botões &disponíveis:", -1,4,5,84,10
+  LTEXT         "Botões &disponíveis:", -1,4,5,84,10
   LISTBOX       IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
   PUSHBUTTON    "&Adicionar ->",    IDOK, 131, 42, 44, 14
   PUSHBUTTON    "<- &Remover", IDC_REMOVE_BTN,131,62,44,14
-  LTEXT         "&Botões da barra de ferramentas:", -1,182,5,78,10
+  LTEXT         "&Botões da barra de ferramentas:", -1,182,5,78,10
   LISTBOX       IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
 END
 
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
 STRINGTABLE DISCARDABLE
 {
     IDS_CLOSE    "Fechar"
 }
 
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
 STRINGTABLE DISCARDABLE
 {
     IDM_TODAY    "Hoje:"
     IDM_GOTODAY  "Ir para hoje"
 }
 
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
 STRINGTABLE DISCARDABLE
 {
     IDS_SEPARATOR "Separador"
 }
 
-
-LANGUAGE LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN
-
 STRINGTABLE DISCARDABLE
 {
     HKY_NONE "Nenhum"
index 0581d0d..497f626 100644 (file)
@@ -17,6 +17,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
 
 #pragma code_page(65001)
@@ -88,5 +90,3 @@ STRINGTABLE DISCARDABLE
 {
     HKY_NONE "Nimic"
 }
-
-#pragma code_page(default)
index 2bbb513..9cba44d 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
+/* UTF-8 */
+#pragma code_page(65001)
+
 LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
 STYLE DS_CONTEXTHELP | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Ñâîéñòâà äëÿ %s"
+CAPTION "Свойства для %s"
 FONT 8, "MS Shell Dlg"
 BEGIN
   DEFPUSHBUTTON "OK",     IDOK,4,122,50,14, WS_TABSTOP | WS_GROUP
-  PUSHBUTTON    "Îòìåíà", IDCANCEL,58,122,50,14
-  PUSHBUTTON    "Ïðè&ìåíèòü", IDC_APPLY_BUTTON,112,122,50,14,WS_DISABLED
-  PUSHBUTTON    "&Ñïðàâêà",   IDHELP,166,122,50,14,WS_TABSTOP|WS_GROUP
+  PUSHBUTTON    "Отмена", IDCANCEL,58,122,50,14
+  PUSHBUTTON    "При&менить", IDC_APPLY_BUTTON,112,122,50,14,WS_DISABLED
+  PUSHBUTTON    "&Справка",   IDHELP,166,122,50,14,WS_TABSTOP|WS_GROUP
   CONTROL       "Tab",    IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS|WS_GROUP|WS_TABSTOP|TCS_MULTILINE,4,4,212,114
 END
 
 
 IDD_WIZARD DIALOG DISCARDABLE 0, 0, 290, 159
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
-CAPTION "Ìàñòåð"
+CAPTION "Мастер"
 FONT 8, "MS Shell Dlg"
 BEGIN
-  PUSHBUTTON    "< &Íàçàä", IDC_BACK_BUTTON,71,138,50,14
-  DEFPUSHBUTTON "&Äàëåå >", IDC_NEXT_BUTTON,121,138,50,14
-  DEFPUSHBUTTON "Ãîòîâî",  IDC_FINISH_BUTTON,121,138,50,14
-  PUSHBUTTON    "Îòìåíà",  IDCANCEL,178,138,50,14
-  PUSHBUTTON    "&Ñïðàâêà",    IDHELP,235,138,50,14,WS_GROUP
+  PUSHBUTTON    "< &Назад", IDC_BACK_BUTTON,71,138,50,14
+  DEFPUSHBUTTON "&Далее >", IDC_NEXT_BUTTON,121,138,50,14
+  DEFPUSHBUTTON "Готово",  IDC_FINISH_BUTTON,121,138,50,14
+  PUSHBUTTON    "Отмена",  IDCANCEL,178,138,50,14
+  PUSHBUTTON    "&Справка",    IDHELP,235,138,50,14,WS_GROUP
   LTEXT         "",        IDC_SUNKEN_LINE,7,129,278,1,SS_SUNKEN
   CONTROL       "Tab",     IDC_TABCONTROL,"SysTabControl32",WS_CLIPSIBLINGS | WS_DISABLED,7,7,258,5
   LTEXT                "",        IDC_SUNKEN_LINEHEADER,0,35,290,1,SS_LEFT | SS_SUNKEN | WS_CHILD | WS_VISIBLE
@@ -51,39 +56,39 @@ END
 
 IDD_TBCUSTOMIZE DIALOG DISCARDABLE 10, 20, 357, 125
 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
-CAPTION "Íàñòðîéêà ïàíåëè èíñòðóìåíòîâ"
+CAPTION "Настройка панели инструментов"
 FONT 8, "MS Shell Dlg"
 BEGIN
-  DEFPUSHBUTTON "&Çàêðûòü",     IDCANCEL,308,6,44,14
-  PUSHBUTTON    "Ñ&áðîñèòü",     IDC_RESET_BTN,308,23,44,14
-  PUSHBUTTON    "&Ñïðàâêà",      IDC_HELP_BTN,308,40,44,14
-  PUSHBUTTON    "Ïåðåìåñòèòü &ââåðõ",   IDC_MOVEUP_BTN,308,74,44,14
-  PUSHBUTTON    "Ïåðåìåñòèòü &âíèç", IDC_MOVEDN_BTN,308,91,44,14
-  LTEXT         "&Äîñòóïíûå êíîïêè:", -1,4,5,84,10
+  DEFPUSHBUTTON "&Закрыть",     IDCANCEL,308,6,44,14
+  PUSHBUTTON    "С&бросить",     IDC_RESET_BTN,308,23,44,14
+  PUSHBUTTON    "&Справка",      IDC_HELP_BTN,308,40,44,14
+  PUSHBUTTON    "Переместить &вверх",   IDC_MOVEUP_BTN,308,74,44,14
+  PUSHBUTTON    "Переместить &вниз", IDC_MOVEDN_BTN,308,91,44,14
+  LTEXT         "&Доступные кнопки:", -1,4,5,84,10
   LISTBOX       IDC_AVAILBTN_LBOX,4,17,120,100, LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
-  PUSHBUTTON    "&Äîáàâèòü ->",    IDOK, 131, 42, 44, 14
-  PUSHBUTTON    "<- &Óäàëèòü", IDC_REMOVE_BTN,131,62,44,14
-  LTEXT         "&Êíîïêè ïàíåëè èíñòðóìåíòîâ:", -1,182,5,78,10
+  PUSHBUTTON    "&Добавить ->",    IDOK, 131, 42, 44, 14
+  PUSHBUTTON    "<- &Удалить", IDC_REMOVE_BTN,131,62,44,14
+  LTEXT         "&Кнопки панели инструментов:", -1,182,5,78,10
   LISTBOX       IDC_TOOLBARBTN_LBOX, 182,17,120,100,LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
 END
 
 STRINGTABLE DISCARDABLE
 {
-    IDS_CLOSE    "Çàêðûòü"
+    IDS_CLOSE    "Закрыть"
 }
 
 STRINGTABLE DISCARDABLE
 {
-    IDM_TODAY    "Ñåãîäíÿ:"
-    IDM_GOTODAY  "Òåêóùàÿ äàòà"
+    IDM_TODAY    "Сегодня:"
+    IDM_GOTODAY  "Текущая дата"
 }
 
 STRINGTABLE DISCARDABLE
 {
-    IDS_SEPARATOR "Ðàçäåëèòåëü"
+    IDS_SEPARATOR "РазделиÑ\82елÑ\8c"
 }
 
 STRINGTABLE DISCARDABLE
 {
-    HKY_NONE "Íåò"
+    HKY_NONE "Нет"
 }
index aa9a7b6..cc1053f 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 #pragma code_page(65001)
 
 LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT
@@ -87,5 +89,3 @@ STRINGTABLE DISCARDABLE
 {
     HKY_NONE "Brez"
 }
-
-#pragma code_page(default)
index fb5f65d..c543e37 100644 (file)
@@ -17,6 +17,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 /* Slovak strings in CP1250 */
 
 LANGUAGE LANG_SLOVAK, SUBLANG_DEFAULT
index 2037d79..18bfefc 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_SWEDISH, SUBLANG_NEUTRAL
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index 3195e1b..ff1e1fa 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_THAI, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index c0f6512..cdc89ca 100644 (file)
@@ -16,6 +16,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index 95e502d..608697d 100644 (file)
@@ -18,6 +18,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 LANGUAGE LANG_UKRAINIAN, SUBLANG_DEFAULT
 
 IDD_PROPSHEET DIALOG DISCARDABLE 0, 0, 220, 140
index b6c5692..8919119 100644 (file)
@@ -19,6 +19,8 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "comctl32.h"
+
 /* Chinese text is encoded in UTF-8 */
 #pragma code_page(65001)
 
@@ -161,5 +163,3 @@ STRINGTABLE DISCARDABLE
 {
     HKY_NONE "無"
 }
-
-#pragma code_page(default)
index db0eade..eb0f6b5 100644 (file)
@@ -784,7 +784,7 @@ CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
     if(hwndTB) {
        TBADDBITMAP tbab;
 
-        SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)uStructSize, 0);
+        SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, uStructSize, 0);
 
        /* set bitmap and button size */
        /*If CreateToolbarEx receives 0, windows sets default values*/
@@ -811,12 +811,11 @@ CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps,
            tbab.hInst = hBMInst;
            tbab.nID   = wBMID;
 
-           SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab);
+            SendMessageW (hwndTB, TB_ADDBITMAP, nBitmaps, (LPARAM)&tbab);
        }
        /* add buttons */
        if(iNumButtons > 0)
-       SendMessageW (hwndTB, TB_ADDBUTTONSW,
-                       (WPARAM)iNumButtons, (LPARAM)lpButtons);
+        SendMessageW (hwndTB, TB_ADDBUTTONSW, iNumButtons, (LPARAM)lpButtons);
     }
 
     return hwndTB;
@@ -923,8 +922,7 @@ CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
     if (hbm) {
        HDC hdcDst = CreateCompatibleDC (hdcScreen);
        HBITMAP hbmOld = SelectObject (hdcDst, hbm);
-       const BYTE *lpBits = (const BYTE *)(lpBitmap + 1);
-       lpBits += nColorTableSize * sizeof(RGBQUAD);
+       const BYTE *lpBits = (const BYTE *)lpBitmap + nSize;
        StretchDIBits (hdcDst, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
                         lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS,
                         SRCCOPY);
@@ -1403,9 +1401,8 @@ COMCTL32_CreateToolTip(HWND hwndOwner)
        nmttc.hdr.code = NM_TOOLTIPSCREATED;
        nmttc.hwndToolTips = hwndToolTip;
 
-       SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
-                    (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID),
-                   (LPARAM)&nmttc);
+        SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY,
+                     GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), (LPARAM)&nmttc);
     }
 
     return hwndToolTip;
index ae538a5..2418950 100644 (file)
@@ -31,7 +31,6 @@
  * TODO:
  *    -- DTS_APPCANPARSE
  *    -- DTS_SHORTDATECENTURYFORMAT
- *    -- DTN_CLOSEUP
  *    -- DTN_FORMAT
  *    -- DTN_FORMATQUERY
  *    -- DTN_USERSTRING
@@ -88,6 +87,7 @@ typedef struct
 
 /* in monthcal.c */
 extern int MONTHCAL_MonthLength(int month, int year);
+extern int MONTHCAL_CalculateDayOfWeek(SYSTEMTIME *date, BOOL inplace);
 
 /* this list of defines is closely related to `allowedformatchars' defined
  * in datetime.c; the high nibble indicates the `base type' of the format
@@ -125,10 +125,11 @@ extern int MONTHCAL_MonthLength(int month, int year);
 
 #define DTHT_DATEFIELD  0xff      /* for hit-testing */
 
-#define DTHT_NONE     0
-#define DTHT_CHECKBOX 0x200    /* these should end at '00' , to make */
-#define DTHT_MCPOPUP  0x300     /* & DTHT_DATEFIELD 0 when DATETIME_KeyDown */
-#define DTHT_GOTFOCUS 0x400     /* tests for date-fields */
+#define DTHT_NONE       0x1000
+#define DTHT_CHECKBOX   0x2000  /* these should end at '00' , to make */
+#define DTHT_MCPOPUP    0x3000  /* & DTHT_DATEFIELD 0 when DATETIME_KeyDown */
+#define DTHT_GOTFOCUS   0x4000  /* tests for date-fields */
+#define DTHT_NODATEMASK 0xf000  /* to mask check and drop down from others */
 
 static BOOL DATETIME_SendSimpleNotify (const DATETIME_INFO *infoPtr, UINT code);
 static BOOL DATETIME_SendDateTimeChangeNotify (const DATETIME_INFO *infoPtr);
@@ -138,43 +139,45 @@ static const int maxrepetition [] = {4,2,2,2,4,2,2,4,-1};
 
 
 static DWORD
-DATETIME_GetSystemTime (const DATETIME_INFO *infoPtr, SYSTEMTIME *lprgSysTimeArray)
+DATETIME_GetSystemTime (const DATETIME_INFO *infoPtr, SYSTEMTIME *systime)
 {
-    if (!lprgSysTimeArray) return GDT_NONE;
+    if (!systime) return GDT_NONE;
 
     if ((infoPtr->dwStyle & DTS_SHOWNONE) &&
         (SendMessageW (infoPtr->hwndCheckbut, BM_GETCHECK, 0, 0) == BST_UNCHECKED))
         return GDT_NONE;
 
-    MONTHCAL_CopyTime (&infoPtr->date, lprgSysTimeArray);
+    *systime = infoPtr->date;
 
     return GDT_VALID;
 }
 
 
 static BOOL
-DATETIME_SetSystemTime (DATETIME_INFO *infoPtr, DWORD flag, const SYSTEMTIME *lprgSysTimeArray)
+DATETIME_SetSystemTime (DATETIME_INFO *infoPtr, DWORD flag, const SYSTEMTIME *systime)
 {
-    if (!lprgSysTimeArray) return 0;
+    if (!systime) return 0;
 
     TRACE("%04d/%02d/%02d %02d:%02d:%02d\n",
-          lprgSysTimeArray->wYear, lprgSysTimeArray->wMonth, lprgSysTimeArray->wDay,
-          lprgSysTimeArray->wHour, lprgSysTimeArray->wMinute, lprgSysTimeArray->wSecond);
+          systime->wYear, systime->wMonth, systime->wDay,
+          systime->wHour, systime->wMinute, systime->wSecond);
 
     if (flag == GDT_VALID) {
-      if (lprgSysTimeArray->wYear < 1601 || lprgSysTimeArray->wYear > 30827 ||
-          lprgSysTimeArray->wMonth < 1 || lprgSysTimeArray->wMonth > 12 ||
-          lprgSysTimeArray->wDayOfWeek > 6 ||
-          lprgSysTimeArray->wDay < 1 || lprgSysTimeArray->wDay > 31 ||
-          lprgSysTimeArray->wHour > 23 ||
-          lprgSysTimeArray->wMinute > 59 ||
-          lprgSysTimeArray->wSecond > 59 ||
-          lprgSysTimeArray->wMilliseconds > 999
+      if (systime->wYear < 1601 || systime->wYear > 30827 ||
+          systime->wMonth < 1 || systime->wMonth > 12 ||
+          systime->wDay < 1 || systime->wDay > 31 ||
+          systime->wHour > 23 ||
+          systime->wMinute > 59 ||
+          systime->wSecond > 59 ||
+          systime->wMilliseconds > 999
           )
-        return 0;
+        return FALSE;
 
         infoPtr->dateValid = TRUE;
-        MONTHCAL_CopyTime (lprgSysTimeArray, &infoPtr->date);
+        infoPtr->date = *systime;
+        /* always store a valid day of week */
+        MONTHCAL_CalculateDayOfWeek(&infoPtr->date, TRUE);
+
         SendMessageW (infoPtr->hMonthCal, MCM_SETCURSEL, 0, (LPARAM)(&infoPtr->date));
         SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_CHECKED, 0);
     } else if ((infoPtr->dwStyle & DTS_SHOWNONE) && (flag == GDT_NONE)) {
@@ -182,7 +185,7 @@ DATETIME_SetSystemTime (DATETIME_INFO *infoPtr, DWORD flag, const SYSTEMTIME *lp
         SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_UNCHECKED, 0);
     }
     else
-        return 0;
+        return FALSE;
 
     InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
     return TRUE;
@@ -286,7 +289,7 @@ DATETIME_SetFormatW (DATETIME_INFO *infoPtr, LPCWSTR lpszFormat)
            format_item = LOCALE_STIMEFORMAT;
         else /* DTS_SHORTDATEFORMAT */
            format_item = LOCALE_SSHORTDATE;
-       GetLocaleInfoW( GetSystemDefaultLCID(), format_item, format_buf, sizeof(format_buf)/sizeof(format_buf[0]));
+       GetLocaleInfoW(LOCALE_USER_DEFAULT, format_item, format_buf, sizeof(format_buf)/sizeof(format_buf[0]));
        lpszFormat = format_buf;
     }
 
@@ -407,12 +410,12 @@ DATETIME_ReturnTxt (const DATETIME_INFO *infoPtr, int count, LPWSTR result, int
            wsprintfW (result, fmt__2dW, date.wMonth);
            break;
        case THREECHARMONTH:
-           GetLocaleInfoW(GetSystemDefaultLCID(), LOCALE_SMONTHNAME1+date.wMonth -1, 
+           GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+date.wMonth -1,
                           buffer, sizeof(buffer)/sizeof(buffer[0]));
            wsprintfW (result, fmt__3sW, buffer);
            break;
        case FULLMONTH:
-           GetLocaleInfoW(GetSystemDefaultLCID(),LOCALE_SMONTHNAME1+date.wMonth -1,
+           GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+date.wMonth -1,
                            result, resultSize);
            break;
        case ONELETTERAMPM:
@@ -444,19 +447,6 @@ DATETIME_ReturnTxt (const DATETIME_INFO *infoPtr, int count, LPWSTR result, int
     TRACE ("arg%d=%x->[%s]\n", count, infoPtr->fieldspec[count], debugstr_w(result));
 }
 
-/* Offsets of days in the week to the weekday of january 1 in a leap year. */
-static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
-
-/* returns the day in the week(0 == sunday, 6 == saturday) */
-/* day(1 == 1st, 2 == 2nd... etc), year is the  year value */
-static int DATETIME_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year)
-{
-    year-=(month < 3);
-    
-    return((year + year/4 - year/100 + year/400 +
-         DayOfWeekTable[month-1] + day ) % 7);
-}
-
 static int wrap(int val, int delta, int minVal, int maxVal)
 {
     val += delta;
@@ -480,14 +470,14 @@ DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta)
        case TWODIGITYEAR:
        case FULLYEAR:
            date->wYear = wrap(date->wYear, delta, 1752, 9999);
-           date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear);
+           MONTHCAL_CalculateDayOfWeek(date, TRUE);
            break;
        case ONEDIGITMONTH:
        case TWODIGITMONTH:
        case THREECHARMONTH:
        case FULLMONTH:
            date->wMonth = wrap(date->wMonth, delta, 1, 12);
-           date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear);
+           MONTHCAL_CalculateDayOfWeek(date, TRUE);
            delta = 0;
            /* fall through */
        case ONEDIGITDAY:
@@ -495,7 +485,7 @@ DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta)
        case THREECHARDAY:
        case FULLDAY:
            date->wDay = wrap(date->wDay, delta, 1, MONTHCAL_MonthLength(date->wMonth, date->wYear));
-           date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear);
+           MONTHCAL_CalculateDayOfWeek(date, TRUE);
            break;
        case ONELETTERAMPM:
        case TWOLETTERAMPM:
@@ -537,7 +527,7 @@ DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta)
 
 
 static void
-DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHORT *fieldWidthPtr)
+DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHORT *width)
 {
     /* fields are a fixed width, determined by the largest possible string */
     /* presumably, these widths should be language dependent */
@@ -546,10 +536,6 @@ DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHO
     static const WCHAR fld_d4W[] = { '2', '2', '2', '2', 0 };
     static const WCHAR fld_am1[] = { 'A', 0 };
     static const WCHAR fld_am2[] = { 'A', 'M', 0 };
-    static const WCHAR fld_day[] = { 'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', 0 };
-    static const WCHAR fld_day3[] = { 'W', 'e', 'd', 0 };
-    static const WCHAR fld_mon[] = { 'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', 0 };
-    static const WCHAR fld_mon3[] = { 'D', 'e', 'c', 0 };
     int spec;
     WCHAR buffer[80];
     LPCWSTR bufptr;
@@ -596,18 +582,64 @@ DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHO
            case FULLYEAR:
                bufptr = fld_d4W;
                break;
-           case THREECHARDAY:
-               bufptr = fld_day3;
-               break;
-           case FULLDAY:
-               bufptr = fld_day;
-               break;
            case THREECHARMONTH:
-               bufptr = fld_mon3;
-               break;
            case FULLMONTH:
-               bufptr = fld_mon;
-               break;
+           case THREECHARDAY:
+           case FULLDAY:
+           {
+               static const WCHAR fld_day[] = {'W','e','d','n','e','s','d','a','y',0};
+               static const WCHAR fld_abbrday[] = {'W','e','d',0};
+               static const WCHAR fld_mon[] = {'S','e','p','t','e','m','b','e','r',0};
+               static const WCHAR fld_abbrmon[] = {'D','e','c',0};
+
+               const WCHAR *fall;
+               LCTYPE lctype;
+               INT i, max_count;
+               LONG cx;
+
+               /* choose locale data type and fallback string */
+               switch (spec) {
+               case THREECHARDAY:
+                   fall   = fld_abbrday;
+                   lctype = LOCALE_SABBREVDAYNAME1;
+                   max_count = 7;
+                   break;
+               case FULLDAY:
+                   fall   = fld_day;
+                   lctype = LOCALE_SDAYNAME1;
+                   max_count = 7;
+                   break;
+               case THREECHARMONTH:
+                   fall   = fld_abbrmon;
+                   lctype = LOCALE_SABBREVMONTHNAME1;
+                   max_count = 12;
+                   break;
+               default: /* FULLMONTH */
+                   fall   = fld_mon;
+                   lctype = LOCALE_SMONTHNAME1;
+                   max_count = 12;
+                   break;
+               }
+
+               cx = 0;
+               for (i = 0; i < max_count; i++)
+               {
+                   if(GetLocaleInfoW(LOCALE_USER_DEFAULT, lctype + i,
+                       buffer, lstrlenW(buffer)))
+                   {
+                       GetTextExtentPoint32W(hdc, buffer, lstrlenW(buffer), &size);
+                       if (size.cx > cx) cx = size.cx;
+                   }
+                   else /* locale independent fallback on failure */
+                   {
+                       GetTextExtentPoint32W(hdc, fall, lstrlenW(fall), &size);
+                       cx = size.cx;
+                       break;
+                   }
+               }
+               *width = cx;
+               return;
+           }
            case ONELETTERAMPM:
                bufptr = fld_am1;
                break;
@@ -620,25 +652,21 @@ DATETIME_ReturnFieldWidth (const DATETIME_INFO *infoPtr, HDC hdc, int count, SHO
         }
     }
     GetTextExtentPoint32W (hdc, bufptr, strlenW(bufptr), &size);
-    *fieldWidthPtr = size.cx;
+    *width = size.cx;
 }
 
 static void 
 DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
 {
-    int i,prevright;
-    RECT *field;
-    RECT *rcDraw = &infoPtr->rcDraw;
-    RECT *calbutton = &infoPtr->calbutton;
-    RECT *checkbox = &infoPtr->checkbox;
-    SIZE size;
-    COLORREF oldTextColor;
-    SHORT fieldWidth = 0;
-
-    /* draw control edge */
     TRACE("\n");
 
     if (infoPtr->dateValid) {
+        int i, prevright;
+        RECT *field;
+        RECT *rcDraw = &infoPtr->rcDraw;
+        SIZE size;
+        COLORREF oldTextColor;
+        SHORT fieldWidth = 0;
         HFONT oldFont = SelectObject (hdc, infoPtr->hFont);
         INT oldBkMode = SetBkMode (hdc, TRANSPARENT);
         WCHAR txt[80];
@@ -647,25 +675,36 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
         GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size);
         rcDraw->bottom = size.cy + 2;
 
-        prevright = checkbox->right = ((infoPtr->dwStyle & DTS_SHOWNONE) ? 18 : 2);
+        prevright = infoPtr->checkbox.right = ((infoPtr->dwStyle & DTS_SHOWNONE) ? 18 : 2);
 
         for (i = 0; i < infoPtr->nrFields; i++) {
             DATETIME_ReturnTxt (infoPtr, i, txt, sizeof(txt)/sizeof(txt[0]));
             GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size);
             DATETIME_ReturnFieldWidth (infoPtr, hdc, i, &fieldWidth);
             field = &infoPtr->fieldRect[i];
-            field->left  = prevright;
-            field->right = prevright + fieldWidth;
-            field->top   = rcDraw->top;
+            field->left   = prevright;
+            field->right  = prevright + fieldWidth;
+            field->top    = rcDraw->top;
             field->bottom = rcDraw->bottom;
             prevright = field->right;
 
             if (infoPtr->dwStyle & WS_DISABLED)
                 oldTextColor = SetTextColor (hdc, comctl32_color.clrGrayText);
             else if ((infoPtr->haveFocus) && (i == infoPtr->select)) {
-                /* fill if focussed */
+                RECT selection;
+
+                /* fill if focused */
                 HBRUSH hbr = CreateSolidBrush (comctl32_color.clrActiveCaption);
-                FillRect(hdc, field, hbr);
+
+                selection.left   = 0;
+                selection.top    = 0;
+                selection.right  = size.cx;
+                selection.bottom = size.cy;
+                /* center rectangle */
+                OffsetRect(&selection, (field->right  + field->left - size.cx)/2,
+                                       (field->bottom - size.cy)/2);
+
+                FillRect(hdc, &selection, hbr);
                 DeleteObject (hbr);
                 oldTextColor = SetTextColor (hdc, comctl32_color.clrWindow);
             }
@@ -673,7 +712,7 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
                 oldTextColor = SetTextColor (hdc, comctl32_color.clrWindowText);
 
             /* draw the date text using the colour set above */
-            DrawTextW (hdc, txt, strlenW(txt), field, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
+            DrawTextW (hdc, txt, strlenW(txt), field, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
             SetTextColor (hdc, oldTextColor);
         }
         SetBkMode (hdc, oldBkMode);
@@ -681,7 +720,7 @@ DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc)
     }
 
     if (!(infoPtr->dwStyle & DTS_UPDOWN)) {
-        DrawFrameControl(hdc, calbutton, DFC_SCROLL,
+        DrawFrameControl(hdc, &infoPtr->calbutton, DFC_SCROLL,
                          DFCS_SCROLLDOWN | (infoPtr->bCalDepressed ? DFCS_PUSHED : 0) |
                          (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
     }
@@ -698,30 +737,54 @@ DATETIME_HitTest (const DATETIME_INFO *infoPtr, POINT pt)
     if (PtInRect (&infoPtr->calbutton, pt)) return DTHT_MCPOPUP;
     if (PtInRect (&infoPtr->checkbox, pt)) return DTHT_CHECKBOX;
 
-    for (i=0; i < infoPtr->nrFields; i++) {
+    for (i = 0; i < infoPtr->nrFields; i++) {
         if (PtInRect (&infoPtr->fieldRect[i], pt)) return i;
     }
 
     return DTHT_NONE;
 }
 
+/* Returns index of a closest date field from given counting to left
+   or -1 if there's no such fields at left */
+static int DATETIME_GetPrevDateField(const DATETIME_INFO *infoPtr, int i)
+{
+    for(--i; i >= 0; i--)
+    {
+        if (infoPtr->fieldspec[i] & DTHT_DATEFIELD) return i;
+    }
+    return -1;
+}
 
 static LRESULT
 DATETIME_LButtonDown (DATETIME_INFO *infoPtr, INT x, INT y)
 {
     POINT pt;
-    int old, new;
+    int new;
 
     pt.x = x;
     pt.y = y;
-    old = infoPtr->select;
     new = DATETIME_HitTest (infoPtr, pt);
 
-    /* FIXME: might be conditions where we don't want to update infoPtr->select */
-    infoPtr->select = new;
-
     SetFocus(infoPtr->hwndSelf);
 
+    if (!(new & DTHT_NODATEMASK) || (new == DTHT_NONE))
+    {
+        if (new == DTHT_NONE)
+            new = infoPtr->nrFields - 1;
+        else
+        {
+            /* hitting string part moves selection to next date field to left */
+            if (infoPtr->fieldspec[new] & DT_STRING)
+            {
+                new = DATETIME_GetPrevDateField(infoPtr, new);
+                if (new == -1) return 0;
+            }
+            /* never select full day of week */
+            if (infoPtr->fieldspec[new] == FULLDAY) return 0;
+        }
+    }
+    infoPtr->select = new;
+
     if (infoPtr->select == DTHT_MCPOPUP) {
         RECT rcMonthCal;
         SendMessageW(infoPtr->hMonthCal, MCM_GETMINREQRECT, 0, (LPARAM)&rcMonthCal);
@@ -746,20 +809,23 @@ DATETIME_LButtonDown (DATETIME_INFO *infoPtr, INT x, INT y)
 
         if(IsWindowVisible(infoPtr->hMonthCal)) {
             ShowWindow(infoPtr->hMonthCal, SW_HIDE);
+            infoPtr->bDropdownEnabled = FALSE;
+            DATETIME_SendSimpleNotify (infoPtr, DTN_CLOSEUP);
         } else {
             const SYSTEMTIME *lprgSysTimeArray = &infoPtr->date;
             TRACE("update calendar %04d/%02d/%02d\n", 
             lprgSysTimeArray->wYear, lprgSysTimeArray->wMonth, lprgSysTimeArray->wDay);
             SendMessageW(infoPtr->hMonthCal, MCM_SETCURSEL, 0, (LPARAM)(&infoPtr->date));
 
-            if (infoPtr->bDropdownEnabled)
+            if (infoPtr->bDropdownEnabled) {
                 ShowWindow(infoPtr->hMonthCal, SW_SHOW);
+                DATETIME_SendSimpleNotify (infoPtr, DTN_DROPDOWN);
+            }
             infoPtr->bDropdownEnabled = TRUE;
         }
 
         TRACE ("dt:%p mc:%p mc parent:%p, desktop:%p\n",
                infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hwndNotify, GetDesktopWindow ());
-        DATETIME_SendSimpleNotify (infoPtr, DTN_DROPDOWN);
     }
 
     InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
@@ -865,7 +931,7 @@ DATETIME_EraseBackground (const DATETIME_INFO *infoPtr, HDC hdc)
 
 
 static LRESULT
-DATETIME_Notify (DATETIME_INFO *infoPtr, LPNMHDR lpnmh)
+DATETIME_Notify (DATETIME_INFO *infoPtr, const NMHDR *lpnmh)
 {
     TRACE ("Got notification %x from %p\n", lpnmh->code, lpnmh->hwndFrom);
     TRACE ("info: %p %p %p\n", infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hUpdown);
@@ -879,9 +945,10 @@ DATETIME_Notify (DATETIME_INFO *infoPtr, LPNMHDR lpnmh)
         SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_CHECKED, 0);
         InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
         DATETIME_SendDateTimeChangeNotify (infoPtr);
+        DATETIME_SendSimpleNotify(infoPtr, DTN_CLOSEUP);
     }
     if ((lpnmh->hwndFrom == infoPtr->hUpdown) && (lpnmh->code == UDN_DELTAPOS)) {
-        LPNMUPDOWN lpnmud = (LPNMUPDOWN)lpnmh;
+        const NM_UPDOWN *lpnmud = (const NM_UPDOWN*)lpnmh;
         TRACE("Delta pos %d\n", lpnmud->iDelta);
         infoPtr->pendingUpdown = lpnmud->iDelta;
     }
@@ -964,15 +1031,14 @@ DATETIME_Char (DATETIME_INFO *infoPtr, WPARAM vkCode)
             case TWODIGITYEAR:
                 date->wYear = date->wYear - (date->wYear%100) +
                         (date->wYear%10)*10 + num;
-                date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
-                        date->wDay,date->wMonth,date->wYear);
+                MONTHCAL_CalculateDayOfWeek(date, TRUE);
                 DATETIME_SendDateTimeChangeNotify (infoPtr);
                 break;
             case INVALIDFULLYEAR:
             case FULLYEAR:
-                date->wYear = (date->wYear%1000)*10 + num;
-                date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
-                        date->wDay,date->wMonth,date->wYear);
+                /* reset current year initialy */
+                date->wYear = ((date->wYear/1000) ? 0 : 1)*(date->wYear%1000)*10 + num;
+                MONTHCAL_CalculateDayOfWeek(date, TRUE);
                 DATETIME_SendDateTimeChangeNotify (infoPtr);
                 break;
             case ONEDIGITMONTH:
@@ -981,8 +1047,7 @@ DATETIME_Char (DATETIME_INFO *infoPtr, WPARAM vkCode)
                     date->wMonth = num;
                 else
                     date->wMonth = (date->wMonth%10)*10+num;
-                date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
-                        date->wDay,date->wMonth,date->wYear);
+                MONTHCAL_CalculateDayOfWeek(date, TRUE);
                 DATETIME_SendDateTimeChangeNotify (infoPtr);
                 break;
             case ONEDIGITDAY:
@@ -992,8 +1057,7 @@ DATETIME_Char (DATETIME_INFO *infoPtr, WPARAM vkCode)
                     date->wDay = num;
                 else
                     date->wDay = newDays;
-                date->wDayOfWeek = DATETIME_CalculateDayOfWeek(
-                        date->wDay,date->wMonth,date->wYear);
+                MONTHCAL_CalculateDayOfWeek(date, TRUE);
                 DATETIME_SendDateTimeChangeNotify (infoPtr);
                 break;
             case ONEDIGIT12HOUR:
@@ -1126,9 +1190,9 @@ DATETIME_SendDateTimeChangeNotify (const DATETIME_INFO *infoPtr)
     dtdtc.nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
     dtdtc.nmhdr.code     = DTN_DATETIMECHANGE;
 
-    dtdtc.dwFlags = (infoPtr->dwStyle & DTS_SHOWNONE) ? GDT_NONE : GDT_VALID;
+    dtdtc.dwFlags = infoPtr->dateValid ? GDT_VALID : GDT_NONE;
 
-    MONTHCAL_CopyTime (&infoPtr->date, &dtdtc.st);
+    dtdtc.st = infoPtr->date;
     return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY,
                                 dtdtc.nmhdr.idFrom, (LPARAM)&dtdtc);
 }
@@ -1186,12 +1250,27 @@ DATETIME_Size (DATETIME_INFO *infoPtr, INT width, INT height)
     return 0;
 }
 
+static LRESULT
+DATETIME_StyleChanging(DATETIME_INFO *infoPtr, WPARAM wStyleType, STYLESTRUCT *lpss)
+{
+    TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
+          wStyleType, lpss->styleOld, lpss->styleNew);
+
+    /* block DTS_SHOWNONE change */
+    if ((lpss->styleNew ^ lpss->styleOld) & DTS_SHOWNONE)
+    {
+        if (lpss->styleOld & DTS_SHOWNONE)
+            lpss->styleNew |= DTS_SHOWNONE;
+        else
+            lpss->styleNew &= ~DTS_SHOWNONE;
+    }
+
+    return 0;
+}
 
 static LRESULT 
 DATETIME_StyleChanged(DATETIME_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
 {
-    static const WCHAR buttonW[] = { 'b', 'u', 't', 't', 'o', 'n', 0 };
-
     TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
           wStyleType, lpss->styleOld, lpss->styleNew);
 
@@ -1200,7 +1279,7 @@ DATETIME_StyleChanged(DATETIME_INFO *infoPtr, WPARAM wStyleType, const STYLESTRU
     infoPtr->dwStyle = lpss->styleNew;
 
     if ( !(lpss->styleOld & DTS_SHOWNONE) && (lpss->styleNew & DTS_SHOWNONE) ) {
-        infoPtr->hwndCheckbut = CreateWindowExW (0, buttonW, 0, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
+        infoPtr->hwndCheckbut = CreateWindowExW (0, WC_BUTTONW, 0, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX,
                                                 2, 2, 13, 13, infoPtr->hwndSelf, 0, 
                                                (HINSTANCE)GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_HINSTANCE), 0);
         SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, 1, 0);
@@ -1235,7 +1314,6 @@ DATETIME_SetFont (DATETIME_INFO *infoPtr, HFONT font, BOOL repaint)
 static LRESULT
 DATETIME_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
 {
-    static const WCHAR SysMonthCal32W[] = { 'S', 'y', 's', 'M', 'o', 'n', 't', 'h', 'C', 'a', 'l', '3', '2', 0 };
     DATETIME_INFO *infoPtr = Alloc (sizeof(DATETIME_INFO));
     STYLESTRUCT ss = { 0, lpcs->style };
 
@@ -1256,7 +1334,7 @@ DATETIME_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
     DATETIME_SetFormatW (infoPtr, 0);
 
     /* create the monthcal control */
-    infoPtr->hMonthCal = CreateWindowExW (0, SysMonthCal32W, 0, WS_BORDER | WS_POPUP | WS_CLIPSIBLINGS, 
+    infoPtr->hMonthCal = CreateWindowExW (0, MONTHCAL_CLASSW, 0, WS_BORDER | WS_POPUP | WS_CLIPSIBLINGS,
                                          0, 0, 0, 0, infoPtr->hwndSelf, 0, 0, 0);
 
     /* initialize info structure */
@@ -1281,11 +1359,34 @@ DATETIME_Destroy (DATETIME_INFO *infoPtr)
     if (infoPtr->hMonthCal) 
         DestroyWindow(infoPtr->hMonthCal);
     SetWindowLongPtrW( infoPtr->hwndSelf, 0, 0 ); /* clear infoPtr */
+    Free (infoPtr->buflen);
+    Free (infoPtr->fieldRect);
+    Free (infoPtr->fieldspec);
     Free (infoPtr);
     return 0;
 }
 
 
+static INT
+DATETIME_GetText (DATETIME_INFO *infoPtr, INT count, LPWSTR dst)
+{
+    WCHAR buf[80];
+    int i;
+
+    if (!dst || (count <= 0)) return 0;
+
+    dst[0] = 0;
+    for (i = 0; i < infoPtr->nrFields; i++)
+    {
+        DATETIME_ReturnTxt(infoPtr, i, buf, sizeof(buf)/sizeof(buf[0]));
+        if ((strlenW(dst) + strlenW(buf)) < count)
+            strcatW(dst, buf);
+        else break;
+    }
+    return strlenW(dst);
+}
+
+
 static LRESULT WINAPI
 DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
@@ -1385,6 +1486,9 @@ DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     case WM_COMMAND:
         return DATETIME_Command (infoPtr, wParam, lParam);
 
+    case WM_STYLECHANGING:
+        return DATETIME_StyleChanging(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
+
     case WM_STYLECHANGED:
         return DATETIME_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
 
@@ -1394,6 +1498,12 @@ DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     case WM_GETFONT:
         return (LRESULT) infoPtr->hFont;
 
+    case WM_GETTEXT:
+        return (LRESULT) DATETIME_GetText(infoPtr, wParam, (LPWSTR)lParam);
+
+    case WM_SETTEXT:
+        return CB_ERR;
+
     default:
        if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
                ERR("unknown msg %04x wp=%08lx lp=%08lx\n",
index e3c03c8..9682344 100644 (file)
@@ -426,12 +426,27 @@ BOOL WINAPI DPA_Destroy (const HDPA hdpa)
  */
 BOOL WINAPI DPA_Grow (HDPA hdpa, INT nGrow)
 {
+    INT items;
     TRACE("(%p %d)\n", hdpa, nGrow);
 
     if (!hdpa)
         return FALSE;
 
-    hdpa->nGrow = max(8, nGrow);
+    nGrow = max( 8, nGrow );
+    items = nGrow * (((hdpa->nMaxCount - 1) / nGrow) + 1);
+    if (items > hdpa->nMaxCount)
+    {
+        void *ptr;
+
+        if (hdpa->ptrs)
+            ptr = HeapReAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, items * sizeof(LPVOID) );
+        else
+            ptr = HeapAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, items * sizeof(LPVOID) );
+        if (!ptr) return FALSE;
+        hdpa->nMaxCount = items;
+        hdpa->ptrs = ptr;
+    }
+    hdpa->nGrow = nGrow;
 
     return TRUE;
 }
index 9ecade5..2097edb 100644 (file)
@@ -334,7 +334,7 @@ INT WINAPI LBItemFromPt (HWND hwndLB, POINT pt, BOOL bAutoScroll)
 
         dwLastScrollTime = dwScrollTime;
 
-        SendMessageW (hwndLB, LB_SETTOPINDEX, (WPARAM)nIndex, 0);
+        SendMessageW (hwndLB, LB_SETTOPINDEX, nIndex, 0);
     }
 
     return -1;
index d84965c..d916c72 100644 (file)
@@ -374,8 +374,7 @@ HEADER_DrawItem (HEADER_INFO *infoPtr, HDC hdc, INT iItem, BOOL bHotTrack, LRESU
        dis.rcItem     = phdi->rect;
        dis.itemData   = phdi->lParam;
         oldBkMode = SetBkMode(hdc, TRANSPARENT);
-       SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM,
-                       (WPARAM)dis.CtlID, (LPARAM)&dis);
+        SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
         if (oldBkMode != TRANSPARENT)
             SetBkMode(hdc, oldBkMode);
     }
@@ -1214,20 +1213,64 @@ HEADER_GetOrderArray(const HEADER_INFO *infoPtr, INT size, LPINT order)
     return TRUE;
 }
 
+/* Returns index of first duplicate 'value' from [0,to) range,
+   or -1 if there isn't any */
+static INT has_duplicate(INT *array, INT to, INT value)
+{
+    INT i;
+    for(i = 0; i < to; i++)
+        if (array[i] == value) return i;
+    return -1;
+}
+
+/* returns next available value from [0,max] not to duplicate in [0,to) */
+static INT get_nextvalue(INT *array, INT to, INT max)
+{
+    INT i;
+    for(i = 0; i < max; i++)
+        if (has_duplicate(array, to, i) == -1) return i;
+    return 0;
+}
+
 static LRESULT
 HEADER_SetOrderArray(HEADER_INFO *infoPtr, INT size, const INT *order)
 {
-    INT i;
     HEADER_ITEM *lpItem;
+    INT i;
 
-    if ((UINT)size <infoPtr->uNumItem)
+    if ((UINT)size != infoPtr->uNumItem)
       return FALSE;
-    memcpy(infoPtr->order, order, infoPtr->uNumItem * sizeof(INT));
+
+    for (i=0; i<size; i++)
+    {
+        if (order[i] >= size || order[i] < 0)
+           /* on invalid index get next available */
+           /* FIXME: if i==0 array item is out of range behaviour is
+                     different, see tests */
+           infoPtr->order[i] = get_nextvalue(infoPtr->order, i, size);
+        else
+        {
+           INT j, dup;
+
+           infoPtr->order[i] = order[i];
+           j = i;
+           /* remove duplicates */
+           while ((dup = has_duplicate(infoPtr->order, j, order[j])) != -1)
+           {
+               INT next;
+
+               next = get_nextvalue(infoPtr->order, j, size);
+               infoPtr->order[dup] = next;
+               j--;
+           }
+        }
+    }
+    /* sync with item data */
     for (i=0; i<size; i++)
-      {
-        lpItem = &infoPtr->items[*order++];
-       lpItem->iOrder=i;
-      }
+    {
+        lpItem = &infoPtr->items[infoPtr->order[i]];
+        lpItem->iOrder = i;
+    }
     HEADER_SetItemBounds(infoPtr);
     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
     return TRUE;
@@ -1704,7 +1747,7 @@ HEADER_NotifyFormat (HEADER_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
        case NF_REQUERY:
            infoPtr->nNotifyFormat =
                SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT,
-                             (WPARAM)infoPtr->hwndSelf, (LPARAM)NF_QUERY);
+                             (WPARAM)infoPtr->hwndSelf, NF_QUERY);
            return infoPtr->nNotifyFormat;
     }
 
index 20596fa..b7818fb 100644 (file)
Binary files a/reactos/dll/win32/comctl32/idb_hist_large.bmp and b/reactos/dll/win32/comctl32/idb_hist_large.bmp differ
index 3cc2ab4..c735f54 100644 (file)
Binary files a/reactos/dll/win32/comctl32/idb_hist_small.bmp and b/reactos/dll/win32/comctl32/idb_hist_small.bmp differ
index 4f0e09e..7e19185 100644 (file)
Binary files a/reactos/dll/win32/comctl32/idb_std_large.bmp and b/reactos/dll/win32/comctl32/idb_std_large.bmp differ
index 8318e44..7db2f3c 100644 (file)
Binary files a/reactos/dll/win32/comctl32/idb_std_small.bmp and b/reactos/dll/win32/comctl32/idb_std_small.bmp differ
index 6331b5e..22e4d1d 100644 (file)
Binary files a/reactos/dll/win32/comctl32/idb_view_large.bmp and b/reactos/dll/win32/comctl32/idb_view_large.bmp differ
index d1632f2..6ba3d83 100644 (file)
Binary files a/reactos/dll/win32/comctl32/idb_view_small.bmp and b/reactos/dll/win32/comctl32/idb_view_small.bmp differ
index a2bc10a..11ff27f 100644 (file)
@@ -33,7 +33,7 @@
  *
  *  TODO:
  *    - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE
- *    - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA
+ *    - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE
  *    - Thread-safe locking
  */
 
@@ -51,6 +51,7 @@
 #include "winuser.h"
 #include "commctrl.h"
 #include "comctl32.h"
+#include "commoncontrols.h"
 #include "imagelist.h"
 #include "wine/debug.h"
 
@@ -78,12 +79,9 @@ typedef struct
 
 static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 };
 
-static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT width);
-
-static inline BOOL is_valid(HIMAGELIST himl)
-{
-    return himl && himl->magic == IMAGELIST_MAGIC;
-}
+static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count);
+static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv);
+static inline BOOL is_valid(HIMAGELIST himl);
 
 /*
  * An imagelist with N images is tiled like this:
@@ -109,9 +107,9 @@ static inline void imagelist_point_from_index( HIMAGELIST himl, UINT index, LPPO
     pt->y = (index/TILE_COUNT) * himl->cy;
 }
 
-static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, UINT cx, SIZE *sz )
+static inline void imagelist_get_bitmap_size( HIMAGELIST himl, UINT count, SIZE *sz )
 {
-    sz->cx = cx * TILE_COUNT;
+    sz->cx = himl->cx * TILE_COUNT;
     sz->cy = imagelist_height( count ) * himl->cy;
 }
 
@@ -140,6 +138,109 @@ static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDe
     }
 }
 
+/* add images with an alpha channel when the image list is 32 bpp */
+static BOOL add_with_alpha( HIMAGELIST himl, HDC hdc, int pos, int count,
+                            int width, int height, HBITMAP hbmImage, HBITMAP hbmMask )
+{
+    BOOL ret = FALSE;
+    HDC hdcMask = 0;
+    BITMAP bm;
+    BITMAPINFO *info, *mask_info = NULL;
+    DWORD *bits = NULL;
+    BYTE *mask_bits = NULL;
+    int i, j, n;
+    POINT pt;
+    DWORD mask_width;
+
+    if (!GetObjectW( hbmImage, sizeof(bm), &bm )) return FALSE;
+
+    /* if neither the imagelist nor the source bitmap can have an alpha channel, bail out now */
+    if (himl->uBitsPixel != 32 && bm.bmBitsPixel != 32) return FALSE;
+
+    SelectObject( hdc, hbmImage );
+    mask_width = (bm.bmWidth + 31) / 32 * 4;
+
+    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    info->bmiHeader.biWidth = bm.bmWidth;
+    info->bmiHeader.biHeight = -height;
+    info->bmiHeader.biPlanes = 1;
+    info->bmiHeader.biBitCount = 32;
+    info->bmiHeader.biCompression = BI_RGB;
+    info->bmiHeader.biSizeImage = bm.bmWidth * height * 4;
+    info->bmiHeader.biXPelsPerMeter = 0;
+    info->bmiHeader.biYPelsPerMeter = 0;
+    info->bmiHeader.biClrUsed = 0;
+    info->bmiHeader.biClrImportant = 0;
+    if (!(bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
+    if (!GetDIBits( hdc, hbmImage, 0, height, bits, info, DIB_RGB_COLORS )) goto done;
+
+    if (hbmMask)
+    {
+        if (!(mask_info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[2] ))))
+            goto done;
+        mask_info->bmiHeader = info->bmiHeader;
+        mask_info->bmiHeader.biBitCount = 1;
+        mask_info->bmiHeader.biSizeImage = mask_width * height;
+        if (!(mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage ))) goto done;
+        if (!GetDIBits( hdc, hbmMask, 0, height, mask_bits, mask_info, DIB_RGB_COLORS )) goto done;
+        hdcMask = CreateCompatibleDC( 0 );
+        SelectObject( hdcMask, hbmMask );
+    }
+
+    for (n = 0; n < count; n++)
+    {
+        int has_alpha = 0;
+
+        imagelist_point_from_index( himl, pos + n, &pt );
+
+        /* check if bitmap has an alpha channel */
+        for (i = 0; i < height && !has_alpha; i++)
+            for (j = n * width; j < (n + 1) * width; j++)
+                if ((has_alpha = ((bits[i * bm.bmWidth + j] & 0xff000000) != 0))) break;
+
+        if (!has_alpha)  /* generate alpha channel from the mask */
+        {
+            for (i = 0; i < height; i++)
+                for (j = n * width; j < (n + 1) * width; j++)
+                    if (!mask_bits || !((mask_bits[i * mask_width + j / 8] << (j % 8)) & 0x80))
+                        bits[i * bm.bmWidth + j] |= 0xff000000;
+                    else
+                        bits[i * bm.bmWidth + j] = 0;
+            if (hdcMask) StretchBlt( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
+                                     hdcMask, n * width, 0, width, height, SRCCOPY );
+        }
+        else
+        {
+            if (himl->has_alpha) himl->has_alpha[pos + n] = 1;
+
+            if (mask_info && himl->hbmMask)  /* generate the mask from the alpha channel */
+            {
+                for (i = 0; i < height; i++)
+                    for (j = n * width; j < (n + 1) * width; j++)
+                        if ((bits[i * bm.bmWidth + j] >> 24) > 25) /* more than 10% alpha */
+                            mask_bits[i * mask_width + j / 8] &= ~(0x80 >> (j % 8));
+                        else
+                            mask_bits[i * mask_width + j / 8] |= 0x80 >> (j % 8);
+                StretchDIBits( himl->hdcMask, pt.x, pt.y, himl->cx, himl->cy,
+                               n * width, 0, width, height, mask_bits, mask_info, DIB_RGB_COLORS, SRCCOPY );
+            }
+        }
+        StretchDIBits( himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
+                       n * width, 0, width, height, bits, info, DIB_RGB_COLORS, SRCCOPY );
+
+    }
+    ret = TRUE;
+
+done:
+    if (hdcMask) DeleteDC( hdcMask );
+    HeapFree( GetProcessHeap(), 0, info );
+    HeapFree( GetProcessHeap(), 0, mask_info );
+    HeapFree( GetProcessHeap(), 0, bits );
+    HeapFree( GetProcessHeap(), 0, mask_bits );
+    return ret;
+}
+
 /*************************************************************************
  * IMAGELIST_InternalExpandBitmaps [Internal]
  *
@@ -156,28 +257,29 @@ static inline void imagelist_copy_images( HIMAGELIST himl, HDC hdcSrc, HDC hdcDe
  *     This function CANNOT be used to reduce the number of images.
  */
 static void
-IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cy)
+IMAGELIST_InternalExpandBitmaps(HIMAGELIST himl, INT nImageCount)
 {
     HDC     hdcBitmap;
     HBITMAP hbmNewBitmap, hbmNull;
     INT     nNewCount;
     SIZE    sz;
 
-    if ((himl->cCurImage + nImageCount <= himl->cMaxImage)
-        && (himl->cy >= cy))
+    TRACE("%p has %d allocated %d images\n", himl, himl->cCurImage, himl->cMaxImage);
+
+    if (himl->cCurImage + nImageCount <= himl->cMaxImage)
        return;
 
-    nNewCount = himl->cCurImage + nImageCount + himl->cGrow;
+    nNewCount = himl->cCurImage + max(nImageCount, himl->cGrow) + 1;
 
-    imagelist_get_bitmap_size(himl, nNewCount, himl->cx, &sz);
+    imagelist_get_bitmap_size(himl, nNewCount, &sz);
 
-    TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, cy, nNewCount);
+    TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, sz.cx, sz.cy, nNewCount);
     hdcBitmap = CreateCompatibleDC (0);
 
-    hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, himl->cx);
+    hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
 
     if (hbmNewBitmap == 0)
-        ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, cy);
+        ERR("creating new image bitmap (x=%d y=%d)!\n", sz.cx, sz.cy);
 
     if (himl->cCurImage)
     {
@@ -209,6 +311,17 @@ IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cy)
         himl->hbmMask = hbmNewBitmap;
     }
 
+    if (himl->has_alpha)
+    {
+        char *new_alpha = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->has_alpha, nNewCount );
+        if (new_alpha) himl->has_alpha = new_alpha;
+        else
+        {
+            HeapFree( GetProcessHeap(), 0, himl->has_alpha );
+            himl->has_alpha = NULL;
+        }
+    }
+
     himl->cMaxImage = nNewCount;
 
     DeleteDC (hdcBitmap);
@@ -233,10 +346,9 @@ IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cy)
 INT WINAPI
 ImageList_Add (HIMAGELIST himl,        HBITMAP hbmImage, HBITMAP hbmMask)
 {
-    HDC     hdcBitmap, hdcTemp;
+    HDC     hdcBitmap, hdcTemp = 0;
     INT     nFirstIndex, nImageCount, i;
     BITMAP  bmp;
-    HBITMAP hOldBitmap, hOldBitmapTemp;
     POINT   pt;
 
     TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask);
@@ -246,13 +358,28 @@ ImageList_Add (HIMAGELIST himl,   HBITMAP hbmImage, HBITMAP hbmMask)
     if (!GetObjectW(hbmImage, sizeof(BITMAP), &bmp))
         return -1;
 
+    TRACE("himl %p, cCurImage %d, cMaxImage %d, cGrow %d, cx %d, cy %d\n",
+          himl, himl->cCurImage, himl->cMaxImage, himl->cGrow, himl->cx, himl->cy);
+
     nImageCount = bmp.bmWidth / himl->cx;
 
-    IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmHeight);
+    TRACE("%p has %d images (%d x %d)\n", hbmImage, nImageCount, bmp.bmWidth, bmp.bmHeight);
+
+    IMAGELIST_InternalExpandBitmaps(himl, nImageCount);
 
     hdcBitmap = CreateCompatibleDC(0);
 
-    hOldBitmap = SelectObject(hdcBitmap, hbmImage);
+    SelectObject(hdcBitmap, hbmImage);
+
+    if (add_with_alpha( himl, hdcBitmap, himl->cCurImage, nImageCount,
+                        himl->cx, min( himl->cy, bmp.bmHeight), hbmImage, hbmMask ))
+        goto done;
+
+    if (himl->hbmMask)
+    {
+        hdcTemp = CreateCompatibleDC(0);
+        SelectObject(hdcTemp, hbmMask);
+    }
 
     for (i=0; i<nImageCount; i++)
     {
@@ -266,22 +393,17 @@ ImageList_Add (HIMAGELIST himl,   HBITMAP hbmImage, HBITMAP hbmMask)
         if (!himl->hbmMask)
              continue;
 
-        hdcTemp   = CreateCompatibleDC(0);
-        hOldBitmapTemp = SelectObject(hdcTemp, hbmMask);
-
         BitBlt( himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
                 hdcTemp, i*himl->cx, 0, SRCCOPY );
 
-        SelectObject(hdcTemp, hOldBitmapTemp);
-        DeleteDC(hdcTemp);
-
         /* Remove the background from the image
         */
         BitBlt( himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
                 himl->hdcMask, pt.x, pt.y, 0x220326 ); /* NOTSRCAND */
     }
+    if (hdcTemp) DeleteDC(hdcTemp);
 
-    SelectObject(hdcBitmap, hOldBitmap);
+done:
     DeleteDC(hdcBitmap);
 
     nFirstIndex = himl->cCurImage;
@@ -331,12 +453,10 @@ INT WINAPI
 ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
 {
     HDC    hdcMask, hdcBitmap;
-    INT    i, nIndex, nImageCount;
+    INT    ret;
     BITMAP bmp;
-    HBITMAP hOldBitmap;
-    HBITMAP hMaskBitmap=0;
+    HBITMAP hMaskBitmap;
     COLORREF bkColor;
-    POINT  pt;
 
     TRACE("himl=%p hbitmap=%p clrmask=%x\n", himl, hBitmap, clrMask);
     if (!is_valid(himl))
@@ -345,18 +465,8 @@ ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
     if (!GetObjectW(hBitmap, sizeof(BITMAP), &bmp))
         return -1;
 
-    if (himl->cx > 0)
-       nImageCount = bmp.bmWidth / himl->cx;
-    else
-       nImageCount = 0;
-
-    IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmHeight);
-
-    nIndex = himl->cCurImage;
-    himl->cCurImage += nImageCount;
-
     hdcBitmap = CreateCompatibleDC(0);
-    hOldBitmap = SelectObject(hdcBitmap, hBitmap);
+    SelectObject(hdcBitmap, hBitmap);
 
     /* Create a temp Mask so we can remove the background of the Image */
     hdcMask = CreateCompatibleDC(0);
@@ -385,23 +495,13 @@ ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask)
      */
     BitBlt(hdcBitmap, 0, 0, bmp.bmWidth, bmp.bmHeight, hdcMask, 0, 0, 0x220326);
 
-    /* Copy result to the imagelist */
-    for (i=0; i<nImageCount; i++)
-    {
-        imagelist_point_from_index( himl, nIndex + i, &pt );
-        BitBlt(himl->hdcImage, pt.x, pt.y, himl->cx, bmp.bmHeight,
-                hdcBitmap, i*himl->cx, 0, SRCCOPY);
-        BitBlt(himl->hdcMask, pt.x, pt.y, himl->cx, bmp.bmHeight,
-                hdcMask, i*himl->cx, 0, SRCCOPY);
-    }
-
-    /* Clean up */
-    SelectObject(hdcBitmap, hOldBitmap);
     DeleteDC(hdcBitmap);
-    DeleteObject(hMaskBitmap);
     DeleteDC(hdcMask);
 
-    return nIndex;
+    ret = ImageList_Add( himl, hBitmap, hMaskBitmap );
+
+    DeleteObject(hMaskBitmap);
+    return ret;
 }
 
 
@@ -598,13 +698,12 @@ ImageList_Create (INT cx, INT cy, UINT flags,
 
     TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow);
 
-    himl = Alloc (sizeof(struct _IMAGELIST));
-    if (!himl)
+    /* Create the IImageList interface for the image list */
+    if (FAILED(ImageListImpl_CreateInstance(NULL, &IID_IImageList, (void **)&himl)))
         return NULL;
 
     cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3;
 
-    himl->magic     = IMAGELIST_MAGIC;
     himl->cx        = cx;
     himl->cy        = cy;
     himl->flags     = flags;
@@ -638,7 +737,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
         himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL);
 
     if (himl->cMaxImage > 0) {
-        himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, cx);
+        himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
        SelectObject(himl->hdcImage, himl->hbmImage);
     } else
         himl->hbmImage = 0;
@@ -646,7 +745,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
     if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) {
         SIZE sz;
 
-        imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
+        imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
         himl->hbmMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
         if (himl->hbmMask == 0) {
             ERR("Error creating mask bitmap!\n");
@@ -657,6 +756,11 @@ ImageList_Create (INT cx, INT cy, UINT flags,
     else
         himl->hbmMask = 0;
 
+    if (himl->uBitsPixel == 32)
+        himl->has_alpha = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, himl->cMaxImage );
+    else
+        himl->has_alpha = NULL;
+
     /* create blending brushes */
     hbmTemp = CreateBitmap (8, 8, 1, 1, aBitBlend25);
     himl->hbrBlend25 = CreatePatternBrush (hbmTemp);
@@ -670,7 +774,7 @@ ImageList_Create (INT cx, INT cy, UINT flags,
     return himl;
 
 cleanup:
-    if (himl) ImageList_Destroy(himl);
+    ImageList_Destroy(himl);
     return NULL;
 }
 
@@ -694,27 +798,7 @@ ImageList_Destroy (HIMAGELIST himl)
     if (!is_valid(himl))
        return FALSE;
 
-    /* delete image bitmaps */
-    if (himl->hbmImage)
-        DeleteObject (himl->hbmImage);
-    if (himl->hbmMask)
-        DeleteObject (himl->hbmMask);
-
-    /* delete image & mask DCs */
-    if (himl->hdcImage)
-        DeleteDC(himl->hdcImage);
-    if (himl->hdcMask)
-        DeleteDC(himl->hdcMask);
-
-    /* delete blending brushes */
-    if (himl->hbrBlend25)
-        DeleteObject (himl->hbrBlend25);
-    if (himl->hbrBlend50)
-        DeleteObject (himl->hbrBlend50);
-
-    ZeroMemory(himl, sizeof(*himl));
-    Free (himl);
-
+    IImageList_Release((IImageList *) himl);
     return TRUE;
 }
 
@@ -832,10 +916,7 @@ ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
     imldp.rgbFg   = CLR_DEFAULT;
     imldp.fStyle  = ILD_NORMAL;
     imldp.fState  = ILS_ALPHA;
-    imldp.Frame   = 128;
-
-    /* FIXME: instead of using the alpha blending, we should
-     * create a 50% mask, and draw it semitransparantly that way */
+    imldp.Frame   = 192;
     ImageList_DrawIndirect (&imldp);
 }
 
@@ -855,9 +936,6 @@ ImageList_InternalDragDraw (HDC hdc, INT x, INT y)
  * NOTES
  *     The position of the drag image is relative to the window, not
  *     the client area.
- *
- * BUGS
- *     The drag image should be drawn semitransparent.
  */
 
 BOOL WINAPI
@@ -941,9 +1019,6 @@ ImageList_DragMove (INT x, INT y)
  * RETURNS
  *     Success: TRUE
  *     Failure: FALSE
- *
- * BUGS
- *     The drag image should be drawn semitransparent.
  */
 
 BOOL WINAPI
@@ -1081,6 +1156,73 @@ ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y,
 }
 
 
+static BOOL alpha_blend_image( HIMAGELIST himl, HDC dest_dc, int dest_x, int dest_y,
+                               int src_x, int src_y, int cx, int cy, BLENDFUNCTION func )
+{
+    BOOL ret = FALSE;
+    HDC hdc;
+    HBITMAP bmp = 0, mask = 0;
+    BITMAPINFO *info;
+    void *bits, *mask_bits;
+    unsigned int *ptr;
+    int i, j;
+
+    if (!(hdc = CreateCompatibleDC( 0 ))) return FALSE;
+    if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
+    info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    info->bmiHeader.biWidth = cx;
+    info->bmiHeader.biHeight = cy;
+    info->bmiHeader.biPlanes = 1;
+    info->bmiHeader.biBitCount = 32;
+    info->bmiHeader.biCompression = BI_RGB;
+    info->bmiHeader.biSizeImage = cx * cy * 4;
+    info->bmiHeader.biXPelsPerMeter = 0;
+    info->bmiHeader.biYPelsPerMeter = 0;
+    info->bmiHeader.biClrUsed = 0;
+    info->bmiHeader.biClrImportant = 0;
+    if (!(bmp = CreateDIBSection( himl->hdcImage, info, DIB_RGB_COLORS, &bits, 0, 0 ))) goto done;
+    SelectObject( hdc, bmp );
+    BitBlt( hdc, 0, 0, cx, cy, himl->hdcImage, src_x, src_y, SRCCOPY );
+
+    if (himl->uBitsPixel == 32)  /* we already have an alpha channel in this case */
+    {
+        /* pre-multiply by the alpha channel */
+        for (i = 0, ptr = bits; i < cx * cy; i++, ptr++)
+        {
+            DWORD alpha = *ptr >> 24;
+            *ptr = ((*ptr & 0xff000000) |
+                    (((*ptr & 0x00ff0000) * alpha / 255) & 0x00ff0000) |
+                    (((*ptr & 0x0000ff00) * alpha / 255) & 0x0000ff00) |
+                    (((*ptr & 0x000000ff) * alpha / 255)));
+        }
+    }
+    else if (himl->hbmMask)
+    {
+        unsigned int width_bytes = (cx + 31) / 32 * 4;
+        /* generate alpha channel from the mask */
+        info->bmiHeader.biBitCount = 1;
+        info->bmiHeader.biSizeImage = width_bytes * cy;
+        if (!(mask = CreateDIBSection( himl->hdcMask, info, DIB_RGB_COLORS, &mask_bits, 0, 0 )))
+            goto done;
+        SelectObject( hdc, mask );
+        BitBlt( hdc, 0, 0, cx, cy, himl->hdcMask, src_x, src_y, SRCCOPY );
+        SelectObject( hdc, bmp );
+        for (i = 0, ptr = bits; i < cy; i++)
+            for (j = 0; j < cx; j++, ptr++)
+                if ((((BYTE *)mask_bits)[i * width_bytes + j / 8] << (j % 8)) & 0x80) *ptr = 0;
+                else *ptr |= 0xff000000;
+    }
+
+    ret = GdiAlphaBlend( dest_dc, dest_x, dest_y, cx, cy, hdc, 0, 0, cx, cy, func );
+
+done:
+    DeleteDC( hdc );
+    if (bmp) DeleteObject( bmp );
+    if (mask) DeleteObject( mask );
+    HeapFree( GetProcessHeap(), 0, info );
+    return ret;
+}
+
 /*************************************************************************
  * ImageList_DrawIndirect [COMCTL32.@]
  *
@@ -1105,7 +1247,9 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
     HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp;
     BOOL bIsTransparent, bBlend, bResult = FALSE, bMask;
     HIMAGELIST himl;
+    HBRUSH hOldBrush;
     POINT pt;
+    BOOL has_alpha;
 
     if (!pimldp || !(himl = pimldp->himl)) return FALSE;
     if (!is_valid(himl)) return FALSE;
@@ -1149,18 +1293,46 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
   
     /*
      * To obtain a transparent look, background color should be set
-     * to white and foreground color to black when blting the
+     * to white and foreground color to black when blitting the
      * monochrome mask.
      */
     oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) );
     oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) );
 
+    has_alpha = (himl->has_alpha && himl->has_alpha[pimldp->i]);
+    if (!bMask && (has_alpha || (fState & ILS_ALPHA)))
+    {
+        COLORREF colour;
+        BLENDFUNCTION func;
+
+        func.BlendOp = AC_SRC_OVER;
+        func.BlendFlags = 0;
+        func.SourceConstantAlpha = (fState & ILS_ALPHA) ? pimldp->Frame : 255;
+        func.AlphaFormat = AC_SRC_ALPHA;
+
+        if (bIsTransparent)
+        {
+            bResult = alpha_blend_image( himl, pimldp->hdcDst, pimldp->x, pimldp->y,
+                                         pt.x, pt.y, cx, cy, func );
+            goto end;
+        }
+        colour = pimldp->rgbBk;
+        if (colour == CLR_DEFAULT) colour = himl->clrBk;
+        if (colour == CLR_NONE) colour = GetBkColor( pimldp->hdcDst );
+
+        hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour));
+        PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
+        alpha_blend_image( himl, hImageDC, 0, 0, pt.x, pt.y, cx, cy, func );
+        DeleteObject (SelectObject (hImageDC, hOldBrush));
+        bResult = BitBlt( pimldp->hdcDst, pimldp->x,  pimldp->y, cx, cy, hImageDC, 0, 0, SRCCOPY );
+        goto end;
+    }
+
     /*
      * Draw the initial image
      */
     if( bMask ) {
        if (himl->hbmMask) {
-            HBRUSH hOldBrush;
             hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst)));
             PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY );
             BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, pt.x, pt.y, SRCPAINT);
@@ -1172,14 +1344,13 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
                 goto end;
             }
        } else {
-           HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
+           hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH));
            PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY);
            SelectObject(hImageDC, hOldBrush);
        }
     } else {
        /* blend the image with the needed solid background */
         COLORREF colour = RGB(0,0,0);
-        HBRUSH hOldBrush;
 
         if( !bIsTransparent )
         {
@@ -1204,7 +1375,7 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
 
     /* Time for blending, if required */
     if (bBlend) {
-       HBRUSH hBlendBrush, hOldBrush;
+       HBRUSH hBlendBrush;
         COLORREF clrBlend = pimldp->rgbFg;
        HDC hBlendMaskDC = hImageListDC;
        HBITMAP hOldBitmap;
@@ -1248,7 +1419,6 @@ ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp)
     if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n");
     if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n");
     if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n");
-    if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n");
 
     if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n");
     if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n");
@@ -1306,13 +1476,13 @@ ImageList_Duplicate (HIMAGELIST himlSrc)
     }
 
     himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags,
-                                himlSrc->cInitial, himlSrc->cGrow);
+                                himlSrc->cCurImage, himlSrc->cGrow);
 
     if (himlDst)
     {
         SIZE sz;
 
-        imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, himlSrc->cx, &sz);
+        imagelist_get_bitmap_size(himlSrc, himlSrc->cCurImage, &sz);
         BitBlt (himlDst->hdcImage, 0, 0, sz.cx, sz.cy,
                 himlSrc->hdcImage, 0, 0, SRCCOPY);
 
@@ -1322,6 +1492,8 @@ ImageList_Duplicate (HIMAGELIST himlSrc)
 
        himlDst->cCurImage = himlSrc->cCurImage;
        himlDst->cMaxImage = himlSrc->cMaxImage;
+        if (himlSrc->has_alpha && himlDst->has_alpha)
+            memcpy( himlDst->has_alpha, himlSrc->has_alpha, himlDst->cCurImage );
     }
     return himlDst;
 }
@@ -1656,7 +1828,7 @@ ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow,
     LPWSTR lpbmpW;
     DWORD len;
 
-    if (!HIWORD(lpbmp))
+    if (IS_INTRESOURCE(lpbmp))
         return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask,
                                     uType, uFlags);
 
@@ -2080,14 +2252,14 @@ ImageList_Remove (HIMAGELIST himl, INT i)
         for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
              himl->nOvlIdx[nCount] = -1;
 
-        hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cx);
+        hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
         SelectObject (himl->hdcImage, hbmNewImage);
         DeleteObject (himl->hbmImage);
         himl->hbmImage = hbmNewImage;
 
         if (himl->hbmMask) {
 
-            imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
+            imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
             hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
             SelectObject (himl->hdcMask, hbmNewMask);
             DeleteObject (himl->hbmMask);
@@ -2102,9 +2274,9 @@ ImageList_Remove (HIMAGELIST himl, INT i)
         TRACE(" - Number of images: %d / %d (Old/New)\n",
                  himl->cCurImage, himl->cCurImage - 1);
 
-        hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cx);
+        hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
 
-        imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz );
+        imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz );
         if (himl->hbmMask)
             hbmNewMask = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
         else
@@ -2181,7 +2353,6 @@ ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
 {
     HDC hdcImage;
     BITMAP bmp;
-    HBITMAP hOldBitmap;
     POINT pt;
 
     TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask);
@@ -2202,7 +2373,10 @@ ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
     hdcImage = CreateCompatibleDC (0);
 
     /* Replace Image */
-    hOldBitmap = SelectObject (hdcImage, hbmImage);
+    SelectObject (hdcImage, hbmImage);
+
+    if (add_with_alpha( himl, hdcImage, i, 1, bmp.bmWidth, bmp.bmHeight, hbmImage, hbmMask ))
+        goto done;
 
     imagelist_point_from_index(himl, i, &pt);
     StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
@@ -2227,7 +2401,7 @@ ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage,
                 himl->hdcMask, pt.x, pt.y, 0x220326); /* NOTSRCAND */
     }
 
-    SelectObject (hdcImage, hOldBitmap);
+done:
     DeleteDC (hdcImage);
 
     return TRUE;
@@ -2254,7 +2428,6 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
 {
     HDC     hdcImage;
     HICON   hBestFitIcon;
-    HBITMAP hbmOldSrc;
     ICONINFO  ii;
     BITMAP  bmp;
     BOOL    ret;
@@ -2304,7 +2477,7 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
 
     if (nIndex == -1) {
         if (himl->cCurImage + 1 > himl->cMaxImage)
-            IMAGELIST_InternalExpandBitmaps (himl, 1, 0);
+            IMAGELIST_InternalExpandBitmaps(himl, 1);
 
         nIndex = himl->cCurImage;
         himl->cCurImage++;
@@ -2315,6 +2488,25 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
     if (hdcImage == 0)
        ERR("invalid hdcImage!\n");
 
+    if (himl->uBitsPixel == 32)
+    {
+        if (!ii.hbmColor)
+        {
+            UINT height = bmp.bmHeight / 2;
+            HDC hdcMask = CreateCompatibleDC( 0 );
+            HBITMAP color = CreateBitmap( bmp.bmWidth, height, 1, 1, NULL );
+            SelectObject( hdcImage, color );
+            SelectObject( hdcMask, ii.hbmMask );
+            BitBlt( hdcImage, 0, 0, bmp.bmWidth, height, hdcMask, 0, height, SRCCOPY );
+            add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, height, color, ii.hbmMask );
+            DeleteDC( hdcMask );
+            DeleteObject( color );
+        }
+        else add_with_alpha( himl, hdcImage, nIndex, 1, bmp.bmWidth, bmp.bmHeight, ii.hbmColor, ii.hbmMask );
+
+        goto done;
+    }
+
     imagelist_point_from_index(himl, nIndex, &pt);
 
     SetTextColor(himl->hdcImage, RGB(0,0,0));
@@ -2322,7 +2514,7 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
 
     if (ii.hbmColor)
     {
-        hbmOldSrc = SelectObject (hdcImage, ii.hbmColor);
+        SelectObject (hdcImage, ii.hbmColor);
         StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
                     hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
         if (himl->hbmMask)
@@ -2335,7 +2527,7 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
     else
     {
         UINT height = bmp.bmHeight / 2;
-        hbmOldSrc = SelectObject (hdcImage, ii.hbmMask);
+        SelectObject (hdcImage, ii.hbmMask);
         StretchBlt (himl->hdcImage, pt.x, pt.y, himl->cx, himl->cy,
                     hdcImage, 0, height, bmp.bmWidth, height, SRCCOPY);
         if (himl->hbmMask)
@@ -2343,8 +2535,7 @@ ImageList_ReplaceIcon (HIMAGELIST himl, INT nIndex, HICON hIcon)
                         hdcImage, 0, 0, bmp.bmWidth, height, SRCCOPY);
     }
 
-    SelectObject (hdcImage, hbmOldSrc);
-
+done:
     DestroyIcon(hBestFitIcon);
     if (hdcImage)
        DeleteDC (hdcImage);
@@ -2539,14 +2730,14 @@ ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy)
     for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++)
         himl->nOvlIdx[nCount] = -1;
 
-    hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage, himl->cx);
+    hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage);
     SelectObject (himl->hdcImage, hbmNew);
     DeleteObject (himl->hbmImage);
     himl->hbmImage = hbmNew;
 
     if (himl->hbmMask) {
         SIZE sz;
-        imagelist_get_bitmap_size(himl, himl->cMaxImage, himl->cx, &sz);
+        imagelist_get_bitmap_size(himl, himl->cMaxImage, &sz);
         hbmNew = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
         SelectObject (himl->hdcMask, hbmNew);
         DeleteObject (himl->hbmMask);
@@ -2594,7 +2785,7 @@ ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
 
     hdcBitmap = CreateCompatibleDC (0);
 
-    hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount, himl->cx);
+    hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount);
 
     if (hbmNewBitmap != 0)
     {
@@ -2614,7 +2805,7 @@ ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount)
     if (himl->hbmMask)
     {
         SIZE sz;
-        imagelist_get_bitmap_size( himl, nNewCount, himl->cx, &sz );
+        imagelist_get_bitmap_size( himl, nNewCount, &sz );
         hbmNewBitmap = CreateBitmap (sz.cx, sz.cy, 1, 1, NULL);
         if (hbmNewBitmap != 0)
         {
@@ -2813,13 +3004,13 @@ ImageList_Write (HIMAGELIST himl, LPSTREAM pstm)
 }
 
 
-static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count, UINT width)
+static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT count)
 {
     HBITMAP hbmNewBitmap;
     UINT ilc = (himl->flags & 0xFE);
     SIZE sz;
 
-    imagelist_get_bitmap_size( himl, count, width, &sz );
+    imagelist_get_bitmap_size( himl, count, &sz );
 
     if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR)
     {
@@ -2925,8 +3116,466 @@ ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST
 HRESULT WINAPI
 ImageList_CoCreateInstance (REFCLSID rclsid, const IUnknown *punkOuter, REFIID riid, void **ppv)
 {
-    FIXME("STUB: %s %p %s %p\n", debugstr_guid(rclsid), punkOuter, debugstr_guid(riid), ppv);
-    return E_NOINTERFACE;
+    TRACE("(%s,%p,%s,%p)\n", debugstr_guid(rclsid), punkOuter, debugstr_guid(riid), ppv);
+
+    if (!IsEqualCLSID(&CLSID_ImageList, rclsid))
+        return E_NOINTERFACE;
+
+    return ImageListImpl_CreateInstance(punkOuter, riid, ppv);
+}
+
+
+/*************************************************************************
+ * IImageList implementation
+ */
+
+static HRESULT WINAPI ImageListImpl_QueryInterface(IImageList *iface,
+    REFIID iid, void **ppv)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IImageList, iid))
+        *ppv = This;
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ImageListImpl_AddRef(IImageList *iface)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+    return ref;
+}
+
+static ULONG WINAPI ImageListImpl_Release(IImageList *iface)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        /* delete image bitmaps */
+        if (This->hbmImage) DeleteObject (This->hbmImage);
+        if (This->hbmMask)  DeleteObject (This->hbmMask);
+
+        /* delete image & mask DCs */
+        if (This->hdcImage) DeleteDC (This->hdcImage);
+        if (This->hdcMask)  DeleteDC (This->hdcMask);
+
+        /* delete blending brushes */
+        if (This->hbrBlend25) DeleteObject (This->hbrBlend25);
+        if (This->hbrBlend50) DeleteObject (This->hbrBlend50);
+
+        This->lpVtbl = NULL;
+        HeapFree(GetProcessHeap(), 0, This->has_alpha);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI ImageListImpl_Add(IImageList *iface, HBITMAP hbmImage,
+    HBITMAP hbmMask, int *pi)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    int ret;
+
+    if (!pi)
+        return E_FAIL;
+
+    ret = ImageList_Add(This, hbmImage, hbmMask);
+
+    if (ret == -1)
+        return E_FAIL;
+
+    *pi = ret;
+    return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_ReplaceIcon(IImageList *iface, int i,
+    HICON hicon, int *pi)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    int ret;
+
+    if (!pi)
+        return E_FAIL;
+
+    ret = ImageList_ReplaceIcon(This, i, hicon);
+
+    if (ret == -1)
+        return E_FAIL;
+
+    *pi = ret;
+    return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_SetOverlayImage(IImageList *iface,
+    int iImage, int iOverlay)
+{
+    return ImageList_SetOverlayImage((HIMAGELIST) iface, iImage, iOverlay)
+        ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_Replace(IImageList *iface, int i,
+    HBITMAP hbmImage, HBITMAP hbmMask)
+{
+    return ImageList_Replace((HIMAGELIST) iface, i, hbmImage, hbmMask) ? S_OK :
+        E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_AddMasked(IImageList *iface, HBITMAP hbmImage,
+    COLORREF crMask, int *pi)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    int ret;
+
+    if (!pi)
+        return E_FAIL;
+
+    ret = ImageList_AddMasked(This, hbmImage, crMask);
+
+    if (ret == -1)
+        return E_FAIL;
+
+    *pi = ret;
+    return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_Draw(IImageList *iface,
+    IMAGELISTDRAWPARAMS *pimldp)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    HIMAGELIST old_himl = 0;
+    int ret = 0;
+
+    if (!pimldp)
+        return E_FAIL;
+
+    /* As far as I can tell, Windows simply ignores the contents of pimldp->himl
+       so we shall simulate the same */
+    old_himl = pimldp->himl;
+    pimldp->himl = This;
+
+    ret = ImageList_DrawIndirect(pimldp);
+
+    pimldp->himl = old_himl;
+    return ret ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_Remove(IImageList *iface, int i)
+{
+    return (ImageList_Remove((HIMAGELIST) iface, i) == 0) ? E_FAIL : S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_GetIcon(IImageList *iface, int i, UINT flags,
+    HICON *picon)
+{
+    HICON hIcon;
+
+    if (!picon)
+        return E_FAIL;
+
+    hIcon = ImageList_GetIcon((HIMAGELIST) iface, i, flags);
+
+    if (hIcon == NULL)
+        return E_FAIL;
+
+    *picon = hIcon;
+    return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_GetImageInfo(IImageList *iface, int i,
+    IMAGEINFO *pImageInfo)
+{
+    return ImageList_GetImageInfo((HIMAGELIST) iface, i, pImageInfo) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_Copy(IImageList *iface, int iDst,
+    IUnknown *punkSrc, int iSrc, UINT uFlags)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    IImageList *src = NULL;
+    HRESULT ret;
+
+    if (!punkSrc)
+        return E_FAIL;
+
+    /* TODO: Add test for IID_ImageList2 too */
+    if (FAILED(IImageList_QueryInterface(punkSrc, &IID_IImageList,
+            (void **) &src)))
+        return E_FAIL;
+
+    if (ImageList_Copy(This, iDst, (HIMAGELIST) src, iSrc, uFlags))
+        ret = S_OK;
+    else
+        ret = E_FAIL;
+
+    IImageList_Release(src);
+    return ret;
+}
+
+static HRESULT WINAPI ImageListImpl_Merge(IImageList *iface, int i1,
+    IUnknown *punk2, int i2, int dx, int dy, REFIID riid, PVOID *ppv)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    IImageList *iml2 = NULL;
+    HIMAGELIST hNew;
+    HRESULT ret = E_FAIL;
+
+    if (!punk2 || !ppv)
+        return E_FAIL;
+
+    /* TODO: Add test for IID_ImageList2 too */
+    if (FAILED(IImageList_QueryInterface(punk2, &IID_IImageList,
+            (void **) &iml2)))
+        return E_FAIL;
+
+    hNew = ImageList_Merge(This, i1, (HIMAGELIST) iml2, i2, dx, dy);
+
+    /* Get the interface for the new image list */
+    if (hNew)
+        ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
+
+    IImageList_Release(iml2);
+    return ret;
+}
+
+static HRESULT WINAPI ImageListImpl_Clone(IImageList *iface, REFIID riid,
+    PVOID *ppv)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    HIMAGELIST hNew;
+    HRESULT ret = E_FAIL;
+
+    if (!ppv)
+        return E_FAIL;
+
+    hNew = ImageList_Duplicate(This);
+
+    /* Get the interface for the new image list */
+    if (hNew)
+        ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
+
+    return ret;
+}
+
+static HRESULT WINAPI ImageListImpl_GetImageRect(IImageList *iface, int i,
+    RECT *prc)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    IMAGEINFO info;
+
+    if (!prc)
+        return E_FAIL;
+
+    if (!ImageList_GetImageInfo(This, i, &info))
+        return E_FAIL;
+
+    return CopyRect(prc, &info.rcImage) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_GetIconSize(IImageList *iface, int *cx,
+    int *cy)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+
+    return ImageList_GetIconSize(This, cx, cy) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_SetIconSize(IImageList *iface, int cx,
+    int cy)
+{
+    return ImageList_SetIconSize((HIMAGELIST) iface, cx, cy) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_GetImageCount(IImageList *iface, int *pi)
+{
+    if (!pi)
+        return E_FAIL;
+
+    *pi = ImageList_GetImageCount((HIMAGELIST) iface);
+    return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_SetImageCount(IImageList *iface,
+    UINT uNewCount)
+{
+    return ImageList_SetImageCount((HIMAGELIST) iface, uNewCount) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_SetBkColor(IImageList *iface, COLORREF clrBk,
+    COLORREF *pclr)
+{
+    if (!pclr)
+        return E_FAIL;
+
+    *pclr = ImageList_SetBkColor((HIMAGELIST) iface, clrBk);
+    return *pclr == CLR_NONE ? E_FAIL : S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_GetBkColor(IImageList *iface, COLORREF *pclr)
+{
+    if (!pclr)
+        return E_FAIL;
+
+    *pclr = ImageList_GetBkColor((HIMAGELIST) iface);
+    return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_BeginDrag(IImageList *iface, int iTrack,
+    int dxHotspot, int dyHotspot)
+{
+    return ImageList_BeginDrag((HIMAGELIST) iface, iTrack, dxHotspot, dyHotspot) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_EndDrag(IImageList *iface)
+{
+    ImageList_EndDrag();
+    return S_OK;
+}
+
+static HRESULT WINAPI ImageListImpl_DragEnter(IImageList *iface, HWND hwndLock,
+    int x, int y)
+{
+    return ImageList_DragEnter(hwndLock, x, y) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_DragLeave(IImageList *iface, HWND hwndLock)
+{
+    return ImageList_DragLeave(hwndLock) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_DragMove(IImageList *iface, int x, int y)
+{
+    return ImageList_DragMove(x, y) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_SetDragCursorImage(IImageList *iface,
+    IUnknown *punk, int iDrag, int dxHotspot, int dyHotspot)
+{
+    IImageList *iml2 = NULL;
+    HRESULT ret;
+
+    if (!punk)
+        return E_FAIL;
+
+    /* TODO: Add test for IID_ImageList2 too */
+    if (FAILED(IImageList_QueryInterface(punk, &IID_IImageList,
+            (void **) &iml2)))
+        return E_FAIL;
+
+    ret = ImageList_SetDragCursorImage((HIMAGELIST) iml2, iDrag, dxHotspot,
+        dyHotspot);
+
+    IImageList_Release(iml2);
+
+    return ret ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_DragShowNolock(IImageList *iface, BOOL fShow)
+{
+    return ImageList_DragShowNolock(fShow) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI ImageListImpl_GetDragImage(IImageList *iface, POINT *ppt,
+    POINT *pptHotspot, REFIID riid, PVOID *ppv)
+{
+    HRESULT ret = E_FAIL;
+    HIMAGELIST hNew;
+
+    if (!ppv)
+        return E_FAIL;
+
+    hNew = ImageList_GetDragImage(ppt, pptHotspot);
+
+    /* Get the interface for the new image list */
+    if (hNew)
+        ret = HIMAGELIST_QueryInterface(hNew, riid, ppv);
+
+    return ret;
+}
+
+static HRESULT WINAPI ImageListImpl_GetItemFlags(IImageList *iface, int i,
+    DWORD *dwFlags)
+{
+    FIXME("STUB: %p %d %p\n", iface, i, dwFlags);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImageListImpl_GetOverlayImage(IImageList *iface, int iOverlay,
+    int *piIndex)
+{
+    HIMAGELIST This = (HIMAGELIST) iface;
+    int i;
+
+    if ((iOverlay < 0) || (iOverlay > This->cCurImage))
+        return E_FAIL;
+
+    for (i = 0; i < MAX_OVERLAYIMAGE; i++)
+    {
+        if (This->nOvlIdx[i] == iOverlay)
+        {
+            *piIndex = i + 1;
+            return S_OK;
+        }
+    }
+
+    return E_FAIL;
+}
+
+
+static const IImageListVtbl ImageListImpl_Vtbl = {
+    ImageListImpl_QueryInterface,
+    ImageListImpl_AddRef,
+    ImageListImpl_Release,
+    ImageListImpl_Add,
+    ImageListImpl_ReplaceIcon,
+    ImageListImpl_SetOverlayImage,
+    ImageListImpl_Replace,
+    ImageListImpl_AddMasked,
+    ImageListImpl_Draw,
+    ImageListImpl_Remove,
+    ImageListImpl_GetIcon,
+    ImageListImpl_GetImageInfo,
+    ImageListImpl_Copy,
+    ImageListImpl_Merge,
+    ImageListImpl_Clone,
+    ImageListImpl_GetImageRect,
+    ImageListImpl_GetIconSize,
+    ImageListImpl_SetIconSize,
+    ImageListImpl_GetImageCount,
+    ImageListImpl_SetImageCount,
+    ImageListImpl_SetBkColor,
+    ImageListImpl_GetBkColor,
+    ImageListImpl_BeginDrag,
+    ImageListImpl_EndDrag,
+    ImageListImpl_DragEnter,
+    ImageListImpl_DragLeave,
+    ImageListImpl_DragMove,
+    ImageListImpl_SetDragCursorImage,
+    ImageListImpl_DragShowNolock,
+    ImageListImpl_GetDragImage,
+    ImageListImpl_GetItemFlags,
+    ImageListImpl_GetOverlayImage
+};
+
+static inline BOOL is_valid(HIMAGELIST himl)
+{
+    return himl && himl->lpVtbl == &ImageListImpl_Vtbl;
 }
 
 /*************************************************************************
@@ -2947,6 +3596,31 @@ ImageList_CoCreateInstance (REFCLSID rclsid, const IUnknown *punkOuter, REFIID r
 HRESULT WINAPI
 HIMAGELIST_QueryInterface (HIMAGELIST himl, REFIID riid, void **ppv)
 {
-    FIXME("STUB: %p %s %p\n", himl, debugstr_guid(riid), ppv);
-    return E_NOINTERFACE;
+    TRACE("(%p,%s,%p)\n", himl, debugstr_guid(riid), ppv);
+    return IImageList_QueryInterface((IImageList *) himl, riid, ppv);
+}
+
+static HRESULT ImageListImpl_CreateInstance(const IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    HIMAGELIST This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct _IMAGELIST));
+    if (!This) return E_OUTOFMEMORY;
+
+    ZeroMemory(This, sizeof(struct _IMAGELIST));
+
+    This->lpVtbl = &ImageListImpl_Vtbl;
+    This->ref = 1;
+
+    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
+    IUnknown_Release((IUnknown*)This);
+
+    return ret;
 }
index 73ccd8a..f6f1d1b 100644 (file)
 #include "winbase.h"
 #include "wingdi.h"
 
-/* the ones with offsets at the end are the same as in Windows */
 struct _IMAGELIST
 {
-    DWORD       magic;                  /* 00: 'SAMX' */
-    INT         cCurImage;              /* 04: ImageCount */
-    INT         cMaxImage;              /* 08: maximages */
-    INT         cGrow;                  /* 0c: cGrow */
-    INT         cx;                     /* 10: cx */
-    INT         cy;                     /* 14: cy */
+    const struct IImageListVtbl *lpVtbl; /* 00: IImageList vtable */
+
+    INT         cCurImage;               /* 04: ImageCount */
+    INT         cMaxImage;               /* 08: maximages */
+    INT         cGrow;                   /* 0C: cGrow */
+    INT         cx;                      /* 10: cx */
+    INT         cy;                      /* 14: cy */
     DWORD       x4;
-    UINT        flags;                  /* 1c: flags */
-    COLORREF    clrFg;                  /* 20: foreground color */
-    COLORREF    clrBk;                  /* 24: background color */
+    UINT        flags;                   /* 1C: flags */
+    COLORREF    clrFg;                   /* 20: foreground color */
+    COLORREF    clrBk;                   /* 24: background color */
 
 
-    HBITMAP     hbmImage;               /* 30: images Bitmap */
-    HBITMAP     hbmMask;                /* 34: masks  Bitmap */
-    HDC         hdcImage;               /* 38: images MemDC  */
-    HDC         hdcMask;                /* 3C: masks  MemDC  */
-    INT         nOvlIdx[15];            /* 40: overlay images index */
+    HBITMAP     hbmImage;                /* 28: images Bitmap */
+    HBITMAP     hbmMask;                 /* 2C: masks  Bitmap */
+    HDC         hdcImage;                /* 30: images MemDC  */
+    HDC         hdcMask;                 /* 34: masks  MemDC  */
+    INT         nOvlIdx[15];             /* 38: overlay images index */
 
     /* not yet found out */
     HBRUSH  hbrBlend25;
     HBRUSH  hbrBlend50;
     INT     cInitial;
     UINT    uBitsPixel;
+    char   *has_alpha;
+
+    LONG        ref;                     /* reference count */
 };
 
 #define IMAGELIST_MAGIC 0x53414D58
index 42ac703..03b8d1c 100644 (file)
@@ -189,7 +189,6 @@ static LRESULT IPADDRESS_Draw (const IPADDRESS_INFO *infoPtr, HDC hdc)
 
 static LRESULT IPADDRESS_Create (HWND hwnd, const CREATESTRUCTA *lpCreate)
 {
-    static const WCHAR EDIT[] = { 'E', 'd', 'i', 't', 0 };
     IPADDRESS_INFO *infoPtr;
     RECT rcClient, edit;
     int i, fieldsize;
@@ -230,7 +229,7 @@ static LRESULT IPADDRESS_Create (HWND hwnd, const CREATESTRUCTA *lpCreate)
         edit.left = rcClient.left + i*fieldsize + 6;
         edit.right = rcClient.left + (i+1)*fieldsize - 2;
         part->EditHwnd =
-               CreateWindowW (EDIT, NULL, WS_CHILD | WS_VISIBLE | ES_CENTER,
+               CreateWindowW (WC_EDITW, NULL, WS_CHILD | WS_VISIBLE | ES_CENTER,
                                edit.left, edit.top, edit.right - edit.left,
                               edit.bottom - edit.top, hwnd, (HMENU) 1,
                               (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), NULL);
index 4e13577..2c27aa9 100644 (file)
 
 WINE_DEFAULT_DEBUG_CHANNEL(listview);
 
+/* make sure you set this to 0 for production use! */
+#define DEBUG_RANGES 1
+
 typedef struct tagCOLUMN_INFO
 {
   RECT rcHeader;       /* tracks the header's rectangle */
@@ -2965,7 +2968,11 @@ static INT CALLBACK ranges_cmp(LPVOID range1, LPVOID range2, LPARAM flags)
     return cmp;
 }
 
-#define ranges_check(ranges, desc) if (TRACE_ON(listview)) ranges_assert(ranges, desc, __FUNCTION__, __LINE__)
+#if DEBUG_RANGES
+#define ranges_check(ranges, desc) ranges_assert(ranges, desc, __FUNCTION__, __LINE__)
+#else
+#define ranges_check(ranges, desc) do { } while(0)
+#endif
 
 static void ranges_assert(RANGES ranges, LPCSTR desc, const char *func, int line)
 {
@@ -6946,7 +6953,7 @@ static BOOL LISTVIEW_GetItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT
  */
 static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc)
 {
-    POINT Position, Origin;
+    POINT Position;
     LVITEMW lvItem;
     INT nColumn;
     
@@ -6954,7 +6961,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
 
     nColumn = lprc->top;
 
-    TRACE("(nItem=%d, nSubItem=%d, type=%d)\n", nItem, lprc->top, lprc->left);
+    TRACE("(nItem=%d, nSubItem=%d)\n", nItem, lprc->top);
     /* On WinNT, a subitem of '0' calls LISTVIEW_GetItemRect */
     if (lprc->top == 0)
         return LISTVIEW_GetItemRect(infoPtr, nItem, lprc);
@@ -6979,8 +6986,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
         }
     }
 
-    if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &Position)) return FALSE;
-    LISTVIEW_GetOrigin(infoPtr, &Origin);
+    LISTVIEW_GetOrigin(infoPtr, &Position);
 
     if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE;
 
@@ -6988,6 +6994,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
     lvItem.iItem = nItem;
     lvItem.iSubItem = nColumn;
     
+    if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE;
     switch(lprc->left)
     {
     case LVIR_ICON:
@@ -7004,9 +7011,7 @@ static BOOL LISTVIEW_GetSubItemRect(const LISTVIEW_INFO *infoPtr, INT nItem, LPR
        return FALSE;
     }
 
-    OffsetRect(lprc, Origin.x, Position.y);
-    TRACE("return rect %s\n", wine_dbgstr_rect(lprc));
-
+    OffsetRect(lprc, Position.x, Position.y);
     return TRUE;
 }
 
index 7a49c70..a9795e0 100644 (file)
@@ -1,11 +1,12 @@
-/* Month calendar control
-
+/*
+ * Month calendar control
  *
  * Copyright 1998, 1999 Eric Kohl (ekohl@abo.rhein-zeitung.de)
  * Copyright 1999 Alex Priem (alexp@sci.kun.nl)
  * Copyright 1999 Chris Morgan <cmorgan@wpi.edu> and
  *               James Abbatiello <abbeyj@wpi.edu>
  * Copyright 2000 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
+ * Copyright 2009 Nikolay Sivov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -36,9 +37,6 @@
  *    -- handle resources better (doesn't work now); 
  *    -- take care of internationalization.
  *    -- keyboard handling.
- *    -- GetRange: At the moment, we copy ranges anyway, regardless of
- *                 infoPtr->rangeValid; an invalid range is simply filled 
- *                 with zeros in SetRange.  Is this the right behavior?
  *    -- search for FIXME
  */
 
@@ -66,14 +64,19 @@ WINE_DEFAULT_DEBUG_CHANNEL(monthcal);
 #define MC_SEL_LBUTDOWN            2   /* Left button pressed in calendar */
 #define MC_PREVPRESSED      4   /* Prev month button pressed */
 #define MC_NEXTPRESSED      8   /* Next month button pressed */
-#define MC_NEXTMONTHDELAY   350        /* when continuously pressing `next */
-                                                                               /* month', wait 500 ms before going */
-                                                                               /* to the next month */
-#define MC_NEXTMONTHTIMER   1                  /* Timer ID's */
-#define MC_PREVMONTHTIMER   2
+#define MC_PREVNEXTMONTHDELAY   350    /* when continuously pressing `next/prev
+                                          month', wait 500 ms before going
+                                          to the next/prev month */
+#define MC_TODAYUPDATEDELAY 120000 /* time between today check for update (2 min) */
+
+#define MC_PREVNEXTMONTHTIMER   1      /* Timer ID's */
+#define MC_TODAYUPDATETIMER     2
 
 #define countof(arr) (sizeof(arr)/sizeof(arr[0]))
 
+/* convert from days to 100 nanoseconds unit - used as FILETIME unit */
+#define DAYSTO100NSECS(days) (((ULONGLONG)(days))*24*60*60*10000000)
+
 typedef struct
 {
     HWND       hwndSelf;
@@ -90,23 +93,26 @@ typedef struct
     int                textWidth;
     int                height_increment;
     int                width_increment;
-    int                firstDayplace; /* place of the first day of the current month */
     INT                delta;  /* scroll rate; # of months that the */
                         /* control moves when user clicks a scroll button */
     int                visible;        /* # of months visible */
-    int                firstDay;       /* Start month calendar with firstDay's day */
-    int                firstDayHighWord;    /* High word only used externally */
+    int                firstDay;       /* Start month calendar with firstDay's day,
+                                  stored in SYSTEMTIME format */
+    BOOL       firstDaySet;    /* first week day differs from locale defined */
+
+    BOOL       isUnicode;      /* value set with MCM_SETUNICODE format */
+
     int                monthRange;
     MONTHDAYSTATE *monthdayState;
     SYSTEMTIME todaysDate;
-    DWORD      currentMonth;
-    DWORD      currentYear;
+    BOOL       todaySet;       /* Today was forced with MCM_SETTODAY */
     int                status;         /* See MC_SEL flags */
-    int                curSelDay;      /* current selected day */
-    int                firstSelDay;    /* first selected day */
+    SYSTEMTIME firstSel;       /* first selected day */
     INT                maxSelCount;
     SYSTEMTIME minSel;
     SYSTEMTIME maxSel;
+    SYSTEMTIME  curSel;         /* contains currently selected year, month and day */
+    SYSTEMTIME  focusedSel;     /* date currently focused with mouse movement */
     DWORD      rangeValid;
     SYSTEMTIME minDate;
     SYSTEMTIME maxDate;
@@ -123,29 +129,65 @@ typedef struct
     HWND hwndNotify;    /* Window to receive the notifications */
     HWND hWndYearEdit;  /* Window Handle of edit box to handle years */
     HWND hWndYearUpDown;/* Window Handle of updown box to handle years */
+    WNDPROC EditWndProc;  /* original Edit window procedure */
 } MONTHCAL_INFO, *LPMONTHCAL_INFO;
 
+static const WCHAR themeClass[] = { 'S','c','r','o','l','l','b','a','r',0 };
 
-/* Offsets of days in the week to the weekday of january 1 in a leap year */
-static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+/* empty SYSTEMTIME const */
+static const SYSTEMTIME st_null;
+/* valid date limits */
+static const SYSTEMTIME max_allowed_date = { .wYear = 9999, .wMonth = 12, .wDay = 31 };
+static const SYSTEMTIME min_allowed_date = { .wYear = 1752, .wMonth = 9,  .wDay = 14 };
 
-static const WCHAR themeClass[] = { 'S','c','r','o','l','l','b','a','r',0 };
 
 #define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)GetWindowLongPtrW(hwnd, 0))
 
 /* helper functions  */
 
+/* send a single MCN_SELCHANGE notification */
+static inline void MONTHCAL_NotifySelectionChange(const MONTHCAL_INFO *infoPtr)
+{
+    NMSELCHANGE nmsc;
+
+    nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
+    nmsc.nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
+    nmsc.nmhdr.code     = MCN_SELCHANGE;
+    nmsc.stSelStart     = infoPtr->minSel;
+    nmsc.stSelEnd       = infoPtr->maxSel;
+    SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
+}
+
+/* send a single MCN_SELECT notification */
+static inline void MONTHCAL_NotifySelect(const MONTHCAL_INFO *infoPtr)
+{
+    NMSELCHANGE nmsc;
+
+    nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
+    nmsc.nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
+    nmsc.nmhdr.code     = MCN_SELECT;
+    nmsc.stSelStart     = infoPtr->minSel;
+    nmsc.stSelEnd       = infoPtr->maxSel;
+
+    SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
+}
+
 /* returns the number of days in any given month, checking for leap days */
 /* january is 1, december is 12 */
 int MONTHCAL_MonthLength(int month, int year)
 {
-  const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
-  /*Wrap around, this eases handling*/
+  const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+  /* Wrap around, this eases handling. Getting length only we shouldn't care
+     about year change here cause January and December have
+     the same day quantity */
   if(month == 0)
     month = 12;
-  if(month == 13)
+  else if(month == 13)
     month = 1;
 
+  /* special case for calendar transition year */
+  if(month == min_allowed_date.wMonth && year == min_allowed_date.wYear) return 19;
+
   /* if we have a leap year add 1 day to February */
   /* a leap year is a year either divisible by 400 */
   /* or divisible by 4 and not by 100 */
@@ -165,17 +207,206 @@ static inline BOOL MONTHCAL_IsDateEqual(const SYSTEMTIME *first, const SYSTEMTIM
          (first->wDay  == second->wDay);
 }
 
-/* make sure that time is valid */
-static BOOL MONTHCAL_ValidateTime(SYSTEMTIME time)
+/* make sure that date fields are valid */
+static BOOL MONTHCAL_ValidateDate(const SYSTEMTIME *time)
 {
-  if(time.wMonth < 1 || time.wMonth > 12 ) return FALSE;
-  if(time.wDayOfWeek > 6) return FALSE;
-  if(time.wDay > MONTHCAL_MonthLength(time.wMonth, time.wYear))
+  if(time->wMonth < 1 || time->wMonth > 12 ) return FALSE;
+  if(time->wDayOfWeek > 6) return FALSE;
+  if(time->wDay > MONTHCAL_MonthLength(time->wMonth, time->wYear))
          return FALSE;
 
   return TRUE;
 }
 
+/* Copies timestamp part only.
+ *
+ * PARAMETERS
+ *
+ *  [I] from : source date
+ *  [O] to   : dest date
+ */
+static void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to)
+{
+  to->wHour   = from->wHour;
+  to->wMinute = from->wMinute;
+  to->wSecond = from->wSecond;
+}
+
+/* Copies date part only.
+ *
+ * PARAMETERS
+ *
+ *  [I] from : source date
+ *  [O] to   : dest date
+ */
+static void MONTHCAL_CopyDate(const SYSTEMTIME *from, SYSTEMTIME *to)
+{
+  to->wYear  = from->wYear;
+  to->wMonth = from->wMonth;
+  to->wDay   = from->wDay;
+  to->wDayOfWeek = from->wDayOfWeek;
+}
+
+/* Compares two dates in SYSTEMTIME format
+ *
+ * PARAMETERS
+ *
+ *  [I] first  : pointer to valid first date data to compare
+ *  [I] second : pointer to valid second date data to compare
+ *
+ * RETURN VALUE
+ *
+ *  -1 : first <  second
+ *   0 : first == second
+ *   1 : first >  second
+ *
+ *  Note that no date validation performed, alreadt validated values expected.
+ */
+static LONG MONTHCAL_CompareSystemTime(const SYSTEMTIME *first, const SYSTEMTIME *second)
+{
+  FILETIME ft_first, ft_second;
+
+  SystemTimeToFileTime(first, &ft_first);
+  SystemTimeToFileTime(second, &ft_second);
+
+  return CompareFileTime(&ft_first, &ft_second);
+}
+
+static LONG MONTHCAL_CompareMonths(const SYSTEMTIME *first, const SYSTEMTIME *second)
+{
+  SYSTEMTIME st_first, st_second;
+
+  st_first = st_second = st_null;
+  MONTHCAL_CopyDate(first, &st_first);
+  MONTHCAL_CopyDate(second, &st_second);
+  st_first.wDay = st_second.wDay = 1;
+
+  return MONTHCAL_CompareSystemTime(&st_first, &st_second);
+}
+
+static LONG MONTHCAL_CompareDate(const SYSTEMTIME *first, const SYSTEMTIME *second)
+{
+  SYSTEMTIME st_first, st_second;
+
+  st_first = st_second = st_null;
+  MONTHCAL_CopyDate(first, &st_first);
+  MONTHCAL_CopyDate(second, &st_second);
+
+  return MONTHCAL_CompareSystemTime(&st_first, &st_second);
+}
+
+/* Checks largest possible date range and configured one
+ *
+ * PARAMETERS
+ *
+ *  [I] infoPtr : valid pointer to control data
+ *  [I] date    : pointer to valid date data to check
+ *  [I] fix     : make date fit valid range
+ *
+ * RETURN VALUE
+ *
+ *  TRUE  - date whithin largest and configured range
+ *  FALSE - date is outside largest or configured range
+ */
+static BOOL MONTHCAL_IsDateInValidRange(const MONTHCAL_INFO *infoPtr,
+                                        SYSTEMTIME *date, BOOL fix)
+{
+  const SYSTEMTIME *fix_st = NULL;
+
+  if(MONTHCAL_CompareSystemTime(date, &max_allowed_date) == 1) {
+     fix_st = &max_allowed_date;
+  }
+  else if(MONTHCAL_CompareSystemTime(date, &min_allowed_date) == -1) {
+     fix_st = &min_allowed_date;
+  }
+  else if(infoPtr->rangeValid & GDTR_MAX) {
+     if((MONTHCAL_CompareSystemTime(date, &infoPtr->maxDate) == 1)) {
+       fix_st = &infoPtr->maxDate;
+     }
+  }
+  else if(infoPtr->rangeValid & GDTR_MIN) {
+     if((MONTHCAL_CompareSystemTime(date, &infoPtr->minDate) == -1)) {
+       fix_st = &infoPtr->minDate;
+     }
+  }
+
+  if (fix && fix_st) {
+    date->wYear  = fix_st->wYear;
+    date->wMonth = fix_st->wMonth;
+  }
+
+  return fix_st ? FALSE : TRUE;
+}
+
+/* Checks passed range width with configured maximum selection count
+ *
+ * PARAMETERS
+ *
+ *  [I] infoPtr : valid pointer to control data
+ *  [I] range0  : pointer to valid date data (requested bound)
+ *  [I] range1  : pointer to valid date data (primary bound)
+ *  [O] adjust  : returns adjusted range bound to fit maximum range (optional)
+ *
+ *  Adjust value computed basing on primary bound and current maximum selection
+ *  count. For simple range check (without adjusted value required) (range0, range1)
+ *  relation means nothing.
+ *
+ * RETURN VALUE
+ *
+ *  TRUE  - range is shorter or equal to maximum
+ *  FALSE - range is larger than maximum
+ */
+static BOOL MONTHCAL_IsSelRangeValid(const MONTHCAL_INFO *infoPtr,
+                                     const SYSTEMTIME *range0,
+                                     const SYSTEMTIME *range1,
+                                     SYSTEMTIME *adjust)
+{
+  ULARGE_INTEGER ul_range0, ul_range1, ul_diff;
+  FILETIME ft_range0, ft_range1;
+  LONG cmp;
+
+  SystemTimeToFileTime(range0, &ft_range0);
+  SystemTimeToFileTime(range1, &ft_range1);
+
+  ul_range0.u.LowPart  = ft_range0.dwLowDateTime;
+  ul_range0.u.HighPart = ft_range0.dwHighDateTime;
+  ul_range1.u.LowPart  = ft_range1.dwLowDateTime;
+  ul_range1.u.HighPart = ft_range1.dwHighDateTime;
+
+  cmp = CompareFileTime(&ft_range0, &ft_range1);
+
+  if(cmp == 1)
+     ul_diff.QuadPart = ul_range0.QuadPart - ul_range1.QuadPart;
+  else
+     ul_diff.QuadPart = -ul_range0.QuadPart + ul_range1.QuadPart;
+
+  if(ul_diff.QuadPart >= DAYSTO100NSECS(infoPtr->maxSelCount)) {
+
+     if(adjust) {
+       if(cmp == 1)
+          ul_range0.QuadPart = ul_range1.QuadPart + DAYSTO100NSECS(infoPtr->maxSelCount - 1);
+       else
+          ul_range0.QuadPart = ul_range1.QuadPart - DAYSTO100NSECS(infoPtr->maxSelCount - 1);
+
+       ft_range0.dwLowDateTime  = ul_range0.u.LowPart;
+       ft_range0.dwHighDateTime = ul_range0.u.HighPart;
+       FileTimeToSystemTime(&ft_range0, adjust);
+     }
+
+     return FALSE;
+  }
+  else return TRUE;
+}
+
+/* Used in MCM_SETRANGE/MCM_SETSELRANGE to determine resulting time part.
+   Milliseconds are intentionally not validated. */
+static BOOL MONTHCAL_ValidateTime(const SYSTEMTIME *time)
+{
+  if((time->wHour > 24) || (time->wMinute > 59) || (time->wSecond > 59))
+    return FALSE;
+  else
+    return TRUE;
+}
 
 /* Note:Depending on DST, this may be offset by a day.
    Need to find out if we're on a DST place & adjust the clock accordingly.
@@ -184,14 +415,89 @@ static BOOL MONTHCAL_ValidateTime(SYSTEMTIME time)
    0 = Sunday.
 */
 
-/* returns the day in the week(0 == sunday, 6 == saturday) */
-/* day(1 == 1st, 2 == 2nd... etc), year is the  year value */
-static int MONTHCAL_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year)
+/* Returns the day in the week
+ *
+ * PARAMETERS
+ *  [i] date    : input date
+ *  [I] inplace : set calculated value back to date structure
+ *
+ * RETURN VALUE
+ *   day of week in SYSTEMTIME format: (0 == sunday,..., 6 == saturday)
+ */
+int MONTHCAL_CalculateDayOfWeek(SYSTEMTIME *date, BOOL inplace)
+{
+  SYSTEMTIME st = st_null;
+  FILETIME ft;
+
+  MONTHCAL_CopyDate(date, &st);
+
+  SystemTimeToFileTime(&st, &ft);
+  FileTimeToSystemTime(&ft, &st);
+
+  if (inplace) date->wDayOfWeek = st.wDayOfWeek;
+
+  return st.wDayOfWeek;
+}
+
+/* properly updates date to point on next month */
+static inline void MONTHCAL_GetNextMonth(SYSTEMTIME *date)
 {
-  year-=(month < 3);
+  if(++date->wMonth > 12)
+  {
+    date->wMonth = 1;
+    date->wYear++;
+  }
+  MONTHCAL_CalculateDayOfWeek(date, TRUE);
+}
+
+/* properly updates date to point on prev month */
+static inline void MONTHCAL_GetPrevMonth(SYSTEMTIME *date)
+{
+  if(--date->wMonth < 1)
+  {
+    date->wMonth = 12;
+    date->wYear--;
+  }
+  MONTHCAL_CalculateDayOfWeek(date, TRUE);
+}
+
+/* Returns full date for a first currently visible day */
+static void MONTHCAL_GetMinDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
+{
+  SYSTEMTIME st_first = infoPtr->curSel;
+  int firstDay;
+
+  st_first.wDay = 1;
+  firstDay = MONTHCAL_CalculateDayOfWeek(&st_first, FALSE);
 
-  return((year + year/4 - year/100 + year/400 +
-         DayOfWeekTable[month-1] + day ) % 7);
+  *date = infoPtr->curSel;
+  MONTHCAL_GetPrevMonth(date);
+
+  date->wDay = MONTHCAL_MonthLength(date->wMonth, date->wYear) +
+               (infoPtr->firstDay - firstDay) % 7 + 1;
+
+  if(date->wDay > MONTHCAL_MonthLength(date->wMonth, date->wYear))
+    date->wDay -= 7;
+
+  /* fix day of week */
+  MONTHCAL_CalculateDayOfWeek(date, TRUE);
+}
+
+/* Returns full date for a last currently visible day */
+static void MONTHCAL_GetMaxDate(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *date)
+{
+  SYSTEMTIME st;
+
+  *date = infoPtr->curSel;
+  MONTHCAL_GetNextMonth(date);
+
+  MONTHCAL_GetMinDate(infoPtr, &st);
+  /* Use month length to get max day. 42 means max day count in calendar area */
+  date->wDay = 42 - (MONTHCAL_MonthLength(st.wMonth, st.wYear) - st.wDay + 1) -
+                     MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+
+  /* fix day of week */
+  MONTHCAL_CalculateDayOfWeek(date, TRUE);
 }
 
 /* From a given point, calculate the row (weekpos), column(daypos)
@@ -202,6 +508,7 @@ static int MONTHCAL_CalcDayFromPos(const MONTHCAL_INFO *infoPtr, int x, int y,
 {
   int retval, firstDay;
   RECT rcClient;
+  SYSTEMTIME st = infoPtr->curSel;
 
   GetClientRect(infoPtr->hwndSelf, &rcClient);
 
@@ -214,44 +521,53 @@ static int MONTHCAL_CalcDayFromPos(const MONTHCAL_INFO *infoPtr, int x, int y,
   *daypos = (x - infoPtr->days.left ) / infoPtr->width_increment;
   *weekpos = (y - infoPtr->days.top ) / infoPtr->height_increment;
 
-  firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear)+6 - infoPtr->firstDay)%7;
+  st.wDay = 1;
+  firstDay = (MONTHCAL_CalculateDayOfWeek(&st, FALSE) + 6 - infoPtr->firstDay) % 7;
   retval = *daypos + (7 * *weekpos) - firstDay;
   return retval;
 }
 
-/* day is the day of the month, 1 == 1st day of the month */
-/* sets x and y to be the position of the day */
-/* x == day, y == week where(0,0) == firstDay, 1st week */
-static void MONTHCAL_CalcDayXY(const MONTHCAL_INFO *infoPtr, int day, int month,
-                                 int *x, int *y)
+/* Sets the RECT struct r to the rectangle around the date
+ *
+ * PARAMETERS
+ *
+ *  [I] infoPtr : pointer to control data
+ *  [I] date : date value
+ *  [O] x : day column (zero based)
+ *  [O] y : week column (zero based)
+ */
+static void MONTHCAL_CalcDayXY(const MONTHCAL_INFO *infoPtr,
+                               const SYSTEMTIME *date, int *x, int *y)
 {
-  int firstDay, prevMonth;
+  SYSTEMTIME st = infoPtr->curSel;
+  LONG cmp;
+  int first;
 
-  firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear) +6 - infoPtr->firstDay)%7;
+  st.wDay = 1;
+  first = (MONTHCAL_CalculateDayOfWeek(&st, FALSE) + 6 - infoPtr->firstDay) % 7;
 
-  if(month==infoPtr->currentMonth) {
-    *x = (day + firstDay) % 7;
-    *y = (day + firstDay - *x) / 7;
-    return;
-  }
-  if(month < infoPtr->currentMonth) {
-    prevMonth = month - 1;
-    if(prevMonth==0)
-       prevMonth = 12;
+  cmp = MONTHCAL_CompareMonths(date, &infoPtr->curSel);
 
-    *x = (MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) - firstDay) % 7;
+  /* previous month */
+  if(cmp == -1) {
+    *x = (first - MONTHCAL_MonthLength(date->wMonth, infoPtr->curSel.wYear) + date->wDay) % 7;
     *y = 0;
     return;
   }
 
-  *y = MONTHCAL_MonthLength(month, infoPtr->currentYear - 1) / 7;
-  *x = (day + firstDay + MONTHCAL_MonthLength(month,
-       infoPtr->currentYear)) % 7;
+  /* next month calculation is same as for current,
+     just add current month length */
+  if(cmp == 1) {
+    first += MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+  }
+
+  *x = (date->wDay + first) % 7;
+  *y = (date->wDay + first - *x) / 7;
 }
 
 
 /* x: column(day), y: row(week) */
-static void MONTHCAL_CalcDayRect(const MONTHCAL_INFO *infoPtr, RECT *r, int x, int y)
+static inline void MONTHCAL_CalcDayRect(const MONTHCAL_INFO *infoPtr, RECT *r, int x, int y)
 {
   r->left = infoPtr->days.left + x * infoPtr->width_increment;
   r->right = r->left + infoPtr->width_increment;
@@ -260,29 +576,67 @@ static void MONTHCAL_CalcDayRect(const MONTHCAL_INFO *infoPtr, RECT *r, int x, i
 }
 
 
-/* sets the RECT struct r to the rectangle around the day and month */
-/* day is the day value of the month(1 == 1st), month is the month */
-/* value(january == 1, december == 12) */
+/* Sets the RECT struct r to the rectangle around the date */
 static inline void MONTHCAL_CalcPosFromDay(const MONTHCAL_INFO *infoPtr,
-                                            int day, int month, RECT *r)
+                                           const SYSTEMTIME *date, RECT *r)
 {
   int x, y;
 
-  MONTHCAL_CalcDayXY(infoPtr, day, month, &x, &y);
+  MONTHCAL_CalcDayXY(infoPtr, date, &x, &y);
   MONTHCAL_CalcDayRect(infoPtr, r, x, y);
 }
 
+/* Focused day helper:
+
+   - set focused date to given value;
+   - reset to zero value if NULL passed;
+   - invalidate previous and new day rectangle only if needed.
 
-/* day is the day in the month(1 == 1st of the month) */
-/* month is the month value(1 == january, 12 == december) */
-static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month)
+   Returns TRUE if focused day changed, FALSE otherwise.
+*/
+static BOOL MONTHCAL_SetDayFocus(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *st)
+{
+  RECT r;
+
+  if(st)
+  {
+    /* there's nothing to do if it's the same date,
+       mouse move within same date rectangle case */
+    if(MONTHCAL_IsDateEqual(&infoPtr->focusedSel, st)) return FALSE;
+
+    /* invalidate old focused day */
+    MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->focusedSel, &r);
+    InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
+
+    infoPtr->focusedSel = *st;
+  }
+
+  MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->focusedSel, &r);
+
+  if(!st && MONTHCAL_ValidateDate(&infoPtr->focusedSel))
+    infoPtr->focusedSel = st_null;
+
+  /* on set invalidates new day, on reset clears previous focused day */
+  InvalidateRect(infoPtr->hwndSelf, &r, FALSE);
+
+  return TRUE;
+}
+
+/* Draw today day mark rectangle
+ *
+ * [I] hdc : context to draw in
+ * [I] day : day to mark with rectangle
+ *
+ */
+static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc,
+                               const SYSTEMTIME *date)
 {
   HPEN hRedPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
   HPEN hOldPen2 = SelectObject(hdc, hRedPen);
   HBRUSH hOldBrush;
   RECT day_rect;
 
-  MONTHCAL_CalcPosFromDay(infoPtr, day, month, &day_rect);
+  MONTHCAL_CalcPosFromDay(infoPtr, date, &day_rect);
 
   hOldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
   Rectangle(hdc, day_rect.left, day_rect.top, day_rect.right, day_rect.bottom);
@@ -292,78 +646,64 @@ static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, i
   SelectObject(hdc, hOldPen2);
 }
 
-static void MONTHCAL_DrawDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month,
-                             int x, int y, int bold)
+static void MONTHCAL_DrawDay(const MONTHCAL_INFO *infoPtr, HDC hdc, const SYSTEMTIME *st,
+                             int bold, const PAINTSTRUCT *ps)
 {
   static const WCHAR fmtW[] = { '%','d',0 };
   WCHAR buf[10];
-  RECT r;
-  static BOOL haveBoldFont, haveSelectedDay = FALSE;
+  RECT r, r_temp;
+  static BOOL bold_selected;
+  BOOL selected_day = FALSE;
   HBRUSH hbr;
   COLORREF oldCol = 0;
-  COLORREF oldBk = 0;
-
-  wsprintfW(buf, fmtW, day);
+  COLORREF oldBk  = 0;
 
 /* No need to check styles: when selection is not valid, it is set to zero.
  * 1<day<31, so everything is OK.
  */
 
-  MONTHCAL_CalcDayRect(infoPtr, &r, x, y);
+  MONTHCAL_CalcPosFromDay(infoPtr, st, &r);
+  if(!IntersectRect(&r_temp, &(ps->rcPaint), &r)) return;
 
-  if((day>=infoPtr->minSel.wDay) && (day<=infoPtr->maxSel.wDay)
-       && (month==infoPtr->currentMonth)) {
-    RECT r2;
+  if ((MONTHCAL_CompareDate(st, &infoPtr->minSel) >= 0) &&
+      (MONTHCAL_CompareDate(st, &infoPtr->maxSel) <= 0)) {
 
-    TRACE("%d %d %d\n",day, infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
+    TRACE("%d %d %d\n", st->wDay, infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
     TRACE("%s\n", wine_dbgstr_rect(&r));
     oldCol = SetTextColor(hdc, infoPtr->monthbk);
     oldBk = SetBkColor(hdc, infoPtr->trailingtxt);
     hbr = GetSysColorBrush(COLOR_HIGHLIGHT);
     FillRect(hdc, &r, hbr);
 
-    /* FIXME: this may need to be changed now b/c of the other
-       drawing changes 11/3/99 CMM */
-    r2.left   = r.left - 0.25 * infoPtr->textWidth;
-    r2.top    = r.top;
-    r2.right  = r.left + 0.5 * infoPtr->textWidth;
-    r2.bottom = r.bottom;
-    if(haveSelectedDay) FillRect(hdc, &r2, hbr);
-      haveSelectedDay = TRUE;
-  } else {
-    haveSelectedDay = FALSE;
+    selected_day = TRUE;
   }
 
-  /* need to add some code for multiple selections */
-
-  if((bold) &&(!haveBoldFont)) {
+  if(bold && !bold_selected) {
     SelectObject(hdc, infoPtr->hBoldFont);
-    haveBoldFont = TRUE;
+    bold_selected = TRUE;
   }
-  if((!bold) &&(haveBoldFont)) {
+  if(!bold && bold_selected) {
     SelectObject(hdc, infoPtr->hFont);
-    haveBoldFont = FALSE;
+    bold_selected = FALSE;
   }
 
   SetBkMode(hdc,TRANSPARENT);
+  wsprintfW(buf, fmtW, st->wDay);
   DrawTextW(hdc, buf, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
 
-  if(haveSelectedDay) {
+  if(selected_day) {
     SetTextColor(hdc, oldCol);
     SetBkColor(hdc, oldBk);
   }
-
-  /* draw a rectangle around the currently selected days text */
-  if((day==infoPtr->curSelDay) && (month==infoPtr->currentMonth))
-    DrawFocusRect(hdc, &r);
 }
 
 
-static void paint_button (const MONTHCAL_INFO *infoPtr, HDC hdc, BOOL btnNext,
-                          BOOL pressed, RECT* r)
+static void MONTHCAL_PaintButton(MONTHCAL_INFO *infoPtr, HDC hdc, BOOL btnNext)
 {
     HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
-    
+    RECT *r = btnNext ? &infoPtr->titlebtnnext : &infoPtr->titlebtnprev;
+    BOOL pressed = btnNext ? (infoPtr->status & MC_NEXTPRESSED) :
+                             (infoPtr->status & MC_PREVPRESSED);
     if (theme)
     {
         static const int states[] = {
@@ -394,350 +734,305 @@ static void paint_button (const MONTHCAL_INFO *infoPtr, HDC hdc, BOOL btnNext,
         DrawFrameControl(hdc, r, DFC_SCROLL, style);
     }
 }
-
-
-static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+/* paint a title with buttons and month/year string */
+static void MONTHCAL_PaintTitle(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
 {
-  static const WCHAR todayW[] = { 'T','o','d','a','y',':',0 };
-  static const WCHAR fmt1W[] = { '%','s',' ','%','l','d',0 };
-  static const WCHAR fmt2W[] = { '%','s',' ','%','s',0 };
-  static const WCHAR fmt3W[] = { '%','d',0 };
-  RECT *title=&infoPtr->title;
-  RECT *prev=&infoPtr->titlebtnprev;
-  RECT *next=&infoPtr->titlebtnnext;
-  RECT *titlemonth=&infoPtr->titlemonth;
-  RECT *titleyear=&infoPtr->titleyear;
-  RECT dayrect;
-  RECT *days=&dayrect;
-  RECT rtoday;
-  int i, j, m, mask, day, firstDay, weeknum, weeknum1,prevMonth;
-  int textHeight = infoPtr->textHeight;
-  SIZE size;
+  static const WCHAR fmt_monthW[] = { '%','s',' ','%','l','d',0 };
+  WCHAR buf_month[80], buf_fmt[80];
   HBRUSH hbr;
-  HFONT currentFont;
-  WCHAR buf[20];
-  WCHAR buf1[20];
-  WCHAR buf2[32];
-  COLORREF oldTextColor, oldBkColor;
-  RECT rcTemp;
-  RECT rcDay; /* used in MONTHCAL_CalcDayRect() */
-  SYSTEMTIME localtime;
-  int startofprescal;
-
-  oldTextColor = SetTextColor(hdc, comctl32_color.clrWindowText);
+  RECT *title = &infoPtr->title;
+  SIZE sz;
 
-  /* fill background */
-  hbr = CreateSolidBrush (infoPtr->bk);
-  FillRect(hdc, &ps->rcPaint, hbr);
+  /* fill header box */
+  hbr =  CreateSolidBrush(infoPtr->titlebk);
+  FillRect(hdc, title, hbr);
   DeleteObject(hbr);
 
-  /* draw header */
-  if(IntersectRect(&rcTemp, &(ps->rcPaint), title))
-  {
-    hbr =  CreateSolidBrush(infoPtr->titlebk);
-    FillRect(hdc, title, hbr);
-    DeleteObject(hbr);
-  }
+  /* navigation buttons */
+  MONTHCAL_PaintButton(infoPtr, hdc, FALSE);
+  MONTHCAL_PaintButton(infoPtr, hdc, TRUE);
 
-  /* if the previous button is pressed draw it depressed */
-  if(IntersectRect(&rcTemp, &(ps->rcPaint), prev))
-    paint_button (infoPtr, hdc, FALSE, infoPtr->status & MC_PREVPRESSED, prev);
+  /* month/year string */
+  SetBkColor(hdc, infoPtr->titlebk);
+  SetTextColor(hdc, infoPtr->titletxt);
+  SelectObject(hdc, infoPtr->hBoldFont);
 
-  /* if next button is depressed draw it depressed */
-  if(IntersectRect(&rcTemp, &(ps->rcPaint), next))
-    paint_button (infoPtr, hdc, TRUE, infoPtr->status & MC_NEXTPRESSED, next);
+  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+infoPtr->curSel.wMonth-1,
+                 buf_month, countof(buf_month));
 
-  oldBkColor = SetBkColor(hdc, infoPtr->titlebk);
-  SetTextColor(hdc, infoPtr->titletxt);
-  currentFont = SelectObject(hdc, infoPtr->hBoldFont);
+  wsprintfW(buf_fmt, fmt_monthW, buf_month, infoPtr->curSel.wYear);
+  DrawTextW(hdc, buf_fmt, strlenW(buf_fmt), title,
+                      DT_CENTER | DT_VCENTER | DT_SINGLELINE);
 
-  GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+infoPtr->currentMonth -1,
-                 buf1,countof(buf1));
-  wsprintfW(buf, fmt1W, buf1, infoPtr->currentYear);
+  /* update title rectangles with current month - used while testing hits */
+  GetTextExtentPoint32W(hdc, buf_fmt, strlenW(buf_fmt), &sz);
+  infoPtr->titlemonth.left = title->right / 2 + title->left / 2 - sz.cx / 2;
+  infoPtr->titleyear.right = title->right / 2 + title->left / 2 + sz.cx / 2;
 
-  if(IntersectRect(&rcTemp, &(ps->rcPaint), title))
-  {
-    DrawTextW(hdc, buf, strlenW(buf), title,
-                        DT_CENTER | DT_VCENTER | DT_SINGLELINE);
-  }
+  GetTextExtentPoint32W(hdc, buf_month, strlenW(buf_month), &sz);
+  infoPtr->titlemonth.right = infoPtr->titlemonth.left + sz.cx;
+  infoPtr->titleyear.left   = infoPtr->titlemonth.right;
+}
 
-/* titlemonth left/right contained rect for whole titletxt('June  1999')
-  * MCM_HitTestInfo wants month & year rects, so prepare these now.
-  *(no, we can't draw them separately; the whole text is centered)
+static void MONTHCAL_PaintWeeknumbers(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+  static const WCHAR fmt_weekW[] = { '%','d',0 };
+  INT mindays, weeknum, weeknum1, startofprescal;
+  SYSTEMTIME st = infoPtr->curSel;
+  RECT r;
+  WCHAR buf[80];
+  INT i, prev_month;
+
+  if (!(infoPtr->dwStyle & MCS_WEEKNUMBERS)) return;
+
+  MONTHCAL_GetMinDate(infoPtr, &st);
+  startofprescal = st.wDay;
+  st = infoPtr->curSel;
+
+  prev_month = infoPtr->curSel.wMonth - 1;
+  if(prev_month == 0) prev_month = 12;
+
+  /*
+     Rules what week to call the first week of a new year:
+     LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?):
+     The week containing Jan 1 is the first week of year
+     LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany):
+     First week of year must contain 4 days of the new year
+     LOCALE_IFIRSTWEEKOFYEAR == 1  (what contries?)
+     The first week of the year must contain only days of the new year
   */
-  GetTextExtentPoint32W(hdc, buf, strlenW(buf), &size);
-  titlemonth->left = title->right / 2 + title->left / 2 - size.cx / 2;
-  titleyear->right = title->right / 2 + title->left / 2 + size.cx / 2;
-  GetTextExtentPoint32W(hdc, buf1, strlenW(buf1), &size);
-  titlemonth->right = titlemonth->left + size.cx;
-  titleyear->left = titlemonth->right;
-
-  /* draw month area */
-  rcTemp.top=infoPtr->wdays.top;
-  rcTemp.left=infoPtr->wdays.left;
-  rcTemp.bottom=infoPtr->todayrect.bottom;
-  rcTemp.right =infoPtr->todayrect.right;
-  if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcTemp))
+  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, countof(buf));
+  weeknum = atoiW(buf);
+  switch (weeknum)
   {
-    hbr =  CreateSolidBrush(infoPtr->monthbk);
-    FillRect(hdc, &rcTemp, hbr);
-    DeleteObject(hbr);
+    case 1: mindays = 6;
+       break;
+    case 2: mindays = 3;
+       break;
+    case 0: mindays = 0;
+        break;
+    default:
+        WARN("Unknown LOCALE_IFIRSTWEEKOFYEAR value %d, defaulting to 0\n", weeknum);
+       mindays = 0;
   }
 
-/* draw line under day abbreviations */
-
-  MoveToEx(hdc, infoPtr->days.left + 3, title->bottom + textHeight + 1, NULL);
-  LineTo(hdc, infoPtr->days.right - 3, title->bottom + textHeight + 1);
-
-  prevMonth = infoPtr->currentMonth - 1;
-  if(prevMonth == 0) /* if currentMonth is january(1) prevMonth is */
-    prevMonth = 12;    /* december(12) of the previous year */
-
-  infoPtr->wdays.left   = infoPtr->days.left   = infoPtr->weeknums.right;
-/* draw day abbreviations */
-
-  SelectObject(hdc, infoPtr->hFont);
-  SetBkColor(hdc, infoPtr->monthbk);
-  SetTextColor(hdc, infoPtr->trailingtxt);
-
-  /* copy this rect so we can change the values without changing */
-  /* the original version */
-  days->left = infoPtr->wdays.left;
-  days->right = days->left + infoPtr->width_increment;
-  days->top = infoPtr->wdays.top;
-  days->bottom = infoPtr->wdays.bottom;
-
-  i = infoPtr->firstDay;
-
-  for(j=0; j<7; j++) {
-    GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf));
-    DrawTextW(hdc, buf, strlenW(buf), days, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
-    days->left+=infoPtr->width_increment;
-    days->right+=infoPtr->width_increment;
+  if (infoPtr->curSel.wMonth == 1)
+  {
+    /* calculate all those exceptions for january */
+    st.wDay = st.wMonth = 1;
+    weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
+    if ((infoPtr->firstDay - weeknum1) % 7 > mindays)
+       weeknum = 1;
+    else
+    {
+       weeknum = 0;
+       for(i = 0; i < 11; i++)
+          weeknum += MONTHCAL_MonthLength(i+1, infoPtr->curSel.wYear - 1);
+
+       weeknum  += startofprescal + 7;
+       weeknum  /= 7;
+       st.wYear -= 1;
+       weeknum1  = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
+       if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
+    }
+  }
+  else
+  {
+    weeknum = 0;
+    for(i = 0; i < prev_month - 1; i++)
+       weeknum += MONTHCAL_MonthLength(i+1, infoPtr->curSel.wYear);
+
+    weeknum += startofprescal + 7;
+    weeknum /= 7;
+    st.wDay = st.wMonth = 1;
+    weeknum1 = MONTHCAL_CalculateDayOfWeek(&st, FALSE);
+    if ((infoPtr->firstDay - weeknum1) % 7 > mindays) weeknum++;
   }
 
-/* draw day numbers; first, the previous month */
-
-  firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear);
-
-  day = MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)  +
-    (infoPtr->firstDay + 7  - firstDay)%7 + 1;
-  if (day > MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear))
-    day -=7;
-  startofprescal = day;
-  mask = 1<<(day-1);
+  r = infoPtr->weeknums;
+  r.bottom = r.top + infoPtr->height_increment;
 
-  i = 0;
-  m = 0;
-  while(day <= MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)) {
-    MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0);
-    if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
+  for(i = 0; i < 6; i++) {
+    if((i == 0) && (weeknum > 50))
+    {
+        wsprintfW(buf, fmt_weekW, weeknum);
+        weeknum = 0;
+    }
+    else if((i == 5) && (weeknum > 47))
     {
-      MONTHCAL_DrawDay(infoPtr, hdc, day, prevMonth, i, 0,
-          infoPtr->monthdayState[m] & mask);
+       wsprintfW(buf, fmt_weekW, 1);
     }
+    else
+       wsprintfW(buf, fmt_weekW, weeknum + i);
 
-    mask<<=1;
-    day++;
-    i++;
+    DrawTextW(hdc, buf, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+    OffsetRect(&r, 0, infoPtr->height_increment);
   }
 
-/* draw `current' month  */
+  /* line separator for week numbers column */
+  MoveToEx(hdc, infoPtr->weeknums.right, infoPtr->weeknums.top + 3 , NULL);
+  LineTo(hdc,   infoPtr->weeknums.right, infoPtr->weeknums.bottom);
+}
 
-  day = 1; /* start at the beginning of the current month */
+/* paint a calendar area */
+static void MONTHCAL_PaintCalendar(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+  INT prev_month, i, j;
+  WCHAR buf[80];
+  HBRUSH hbr;
+  RECT r;
+  int mask;
+  SYSTEMTIME st;
 
-  infoPtr->firstDayplace = i;
-  SetTextColor(hdc, infoPtr->txt);
-  m++;
-  mask = 1;
+  UnionRect(&r, &infoPtr->wdays, &infoPtr->todayrect);
 
-  /* draw the first week of the current month */
-  while(i<7) {
-    MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0);
-    if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
-    {
+  hbr =  CreateSolidBrush(infoPtr->monthbk);
+  FillRect(hdc, &r, hbr);
+  DeleteObject(hbr);
 
-      MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, 0,
-       infoPtr->monthdayState[m] & mask);
+  /* draw line under day abbreviations */
+  MoveToEx(hdc, infoPtr->days.left + 3,
+                infoPtr->title.bottom + infoPtr->textHeight + 1, NULL);
+  LineTo(hdc, infoPtr->days.right - 3,
+              infoPtr->title.bottom + infoPtr->textHeight + 1);
 
-      if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) &&
-          (day==infoPtr->todaysDate.wDay) &&
-         (infoPtr->currentYear == infoPtr->todaysDate.wYear)) {
-        if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
-         MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth);
-      }
-    }
+  prev_month = infoPtr->curSel.wMonth - 1;
+  if(prev_month == 0) prev_month = 12;
 
-    mask<<=1;
-    day++;
-    i++;
-  }
+  infoPtr->wdays.left = infoPtr->days.left = infoPtr->weeknums.right;
 
-  j = 1; /* move to the 2nd week of the current month */
-  i = 0; /* move back to sunday */
-  while(day <= MONTHCAL_MonthLength(infoPtr->currentMonth, infoPtr->currentYear)) {
-    MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j);
-    if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
-    {
-      MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, j,
-          infoPtr->monthdayState[m] & mask);
-
-      if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) &&
-          (day==infoPtr->todaysDate.wDay) &&
-          (infoPtr->currentYear == infoPtr->todaysDate.wYear))
-        if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
-         MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth);
-    }
-    mask<<=1;
-    day++;
-    i++;
-    if(i>6) { /* past saturday, goto the next weeks sunday */
-      i = 0;
-      j++;
-    }
+  /* 1. draw day abbreviations */
+  SelectObject(hdc, infoPtr->hFont);
+  SetBkColor(hdc, infoPtr->monthbk);
+  SetTextColor(hdc, infoPtr->trailingtxt);
+  /* rectangle to draw a single day abbreviation within */
+  r = infoPtr->wdays;
+  r.right = r.left + infoPtr->width_increment;
+
+  i = infoPtr->firstDay;
+  for(j = 0; j < 7; j++) {
+    GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf));
+    DrawTextW(hdc, buf, strlenW(buf), &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+    OffsetRect(&r, infoPtr->width_increment, 0);
   }
 
-/*  draw `next' month */
+  /* 2. previous and next months */
+  if (!(infoPtr->dwStyle & MCS_NOTRAILINGDATES))
+  {
+    SYSTEMTIME st_max;
+
+    SetTextColor(hdc, infoPtr->trailingtxt);
 
-  day = 1; /* start at the first day of the next month */
-  m++;
-  mask = 1;
+    MONTHCAL_GetMinDate(infoPtr, &st);
 
-  SetTextColor(hdc, infoPtr->trailingtxt);
-  while((i<7) &&(j<6)) {
-    MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j);
-    if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay))
-    {
-      MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth + 1, i, j,
-               infoPtr->monthdayState[m] & mask);
+    /* draw prev month */
+    mask = 1 << (st.wDay-1);
+    while(st.wDay <= MONTHCAL_MonthLength(prev_month, infoPtr->curSel.wYear)) {
+      MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[0] & mask, ps);
+      mask <<= 1;
+      st.wDay++;
     }
 
-    mask<<=1;
-    day++;
-    i++;
-    if(i==7) { /* past saturday, go to next week's sunday */
-      i = 0;
-      j++;
+    /* draw next month */
+    st = infoPtr->curSel;
+    st.wDay = 1;
+    MONTHCAL_GetNextMonth(&st);
+    MONTHCAL_GetMaxDate(infoPtr, &st_max);
+    mask = 1;
+    while(st.wDay <= st_max.wDay) {
+      MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[2] & mask, ps);
+      mask <<= 1;
+      st.wDay++;
     }
   }
-  SetTextColor(hdc, infoPtr->txt);
-
 
-/* draw `today' date if style allows it, and draw a circle before today's
- * date if necessary */
+  /* 3. current month */
+  SetTextColor(hdc, infoPtr->txt);
+  st = infoPtr->curSel;
+  st.wDay = 1;
+  mask = 1;
+  while(st.wDay <= MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear)) {
+    MONTHCAL_DrawDay(infoPtr, hdc, &st, infoPtr->monthdayState[1] & mask,
+                     ps);
+    mask <<= 1;
+    st.wDay++;
+  }
 
+  /* 4. bottom today date */
   if(!(infoPtr->dwStyle & MCS_NOTODAY))  {
-    if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))  {
-      /*day is the number of days from nextmonth we put on the calendar */
-      MONTHCAL_CircleDay(infoPtr, hdc,
-                        day+MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear),
-                        infoPtr->currentMonth);
+    static const WCHAR todayW[] = { 'T','o','d','a','y',':',0 };
+    static const WCHAR fmt_todayW[] = { '%','s',' ','%','s',0 };
+    WCHAR buf_todayW[30], buf_dateW[20];
+    RECT rtoday;
+
+    if(!(infoPtr->dwStyle & MCS_NOTODAYCIRCLE)) {
+      SYSTEMTIME fake_st;
+
+      MONTHCAL_GetMaxDate(infoPtr, &fake_st);
+      /* this is always safe cause next month will never fully fit calendar */
+      fake_st.wDay += 1;
+      MONTHCAL_CircleDay(infoPtr, hdc, &fake_st);
     }
-    if (!LoadStringW(COMCTL32_hModule,IDM_TODAY,buf1,countof(buf1)))
-      {
+    if (!LoadStringW(COMCTL32_hModule, IDM_TODAY, buf_todayW, countof(buf_todayW)))
+    {
        WARN("Can't load resource\n");
-       strcpyW(buf1, todayW);
-      }
+       strcpyW(buf_todayW, todayW);
+    }
     MONTHCAL_CalcDayRect(infoPtr, &rtoday, 1, 6);
-    MONTHCAL_CopyTime(&infoPtr->todaysDate,&localtime);
-    GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&localtime,NULL,buf2,countof(buf2));
-    wsprintfW(buf, fmt2W, buf1, buf2);
+    GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &infoPtr->todaysDate, NULL,
+                                                        buf_dateW, countof(buf_dateW));
     SelectObject(hdc, infoPtr->hBoldFont);
 
+    wsprintfW(buf, fmt_todayW, buf_todayW, buf_dateW);
     DrawTextW(hdc, buf, -1, &rtoday, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE);
-    if(IntersectRect(&rcTemp, &(ps->rcPaint), &rtoday))
-    {
-      DrawTextW(hdc, buf, -1, &rtoday, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
-    }
+    DrawTextW(hdc, buf, -1, &rtoday, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
     SelectObject(hdc, infoPtr->hFont);
   }
 
-/*eventually draw week numbers*/
-  if(infoPtr->dwStyle & MCS_WEEKNUMBERS)  {
-    /* display weeknumbers*/
-    int mindays;
-
-    /* Rules what week to call the first week of a new year:
-       LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?):
-       The week containing Jan 1 is the first week of year
-       LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany):
-       First week of year must contain 4 days of the new year
-       LOCALE_IFIRSTWEEKOFYEAR == 1  (what contries?)
-       The first week of the year must contain only days of the new year
-    */
-    GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, countof(buf));
-    weeknum = atoiW(buf);
-    switch (weeknum)
-      {
-      case 1: mindays = 6;
-       break;
-      case 2: mindays = 3;
-       break;
-      case 0:
-      default:
-       mindays = 0;
-      }
-    if (infoPtr->currentMonth < 2)
-      {
-       /* calculate all those exceptions for january */
-       weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear);
-       if ((infoPtr->firstDay +7 - weeknum1)%7 > mindays)
-           weeknum =1;
-       else
-         {
-           weeknum = 0;
-           for(i=0; i<11; i++)
-             weeknum+=MONTHCAL_MonthLength(i+1, infoPtr->currentYear-1);
-           weeknum +=startofprescal+ 7;
-           weeknum /=7;
-           weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear-1);
-           if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays)
-             weeknum++;
-         }
-      }
-    else
-      {
-       weeknum = 0;
-       for(i=0; i<prevMonth-1; i++)
-         weeknum+=MONTHCAL_MonthLength(i+1, infoPtr->currentYear);
-       weeknum +=startofprescal+ 7;
-       weeknum /=7;
-       weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear);
-       if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays)
-         weeknum++;
-      }
-    days->left = infoPtr->weeknums.left;
-    days->right = infoPtr->weeknums.right;
-    days->top = infoPtr->weeknums.top;
-    days->bottom = days->top +infoPtr->height_increment;
-    for(i=0; i<6; i++) {
-      if((i==0)&&(weeknum>50))
-       {
-         wsprintfW(buf, fmt3W, weeknum);
-         weeknum=0;
-       }
-      else if((i==5)&&(weeknum>47))
-       {
-         wsprintfW(buf, fmt3W, 1);
-       }
-      else
-       wsprintfW(buf, fmt3W, weeknum + i);
-      DrawTextW(hdc, buf, -1, days, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
-      days->top+=infoPtr->height_increment;
-      days->bottom+=infoPtr->height_increment;
-    }
-
-    MoveToEx(hdc, infoPtr->weeknums.right, infoPtr->weeknums.top + 3 , NULL);
-    LineTo(hdc,   infoPtr->weeknums.right, infoPtr->weeknums.bottom );
-
+  /* 5. today mark + focus */
+  if((infoPtr->curSel.wMonth == infoPtr->todaysDate.wMonth) &&
+     (infoPtr->curSel.wYear  == infoPtr->todaysDate.wYear) &&
+    !(infoPtr->dwStyle & MCS_NOTODAYCIRCLE))
+  {
+    MONTHCAL_CircleDay(infoPtr, hdc, &infoPtr->todaysDate);
   }
-  /* currentFont was font at entering Refresh */
 
-  SetBkColor(hdc, oldBkColor);
-  SelectObject(hdc, currentFont);
-  SetTextColor(hdc, oldTextColor);
+  if(!MONTHCAL_IsDateEqual(&infoPtr->focusedSel, &st_null))
+  {
+    MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->focusedSel, &r);
+    DrawFocusRect(hdc, &r);
+  }
 }
 
+static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps)
+{
+  RECT *title = &infoPtr->title;
+  COLORREF old_text_clr, old_bk_clr;
+  HFONT old_font;
+  RECT r_temp;
+
+  old_text_clr = SetTextColor(hdc, comctl32_color.clrWindowText);
+  old_bk_clr   = GetBkColor(hdc);
+  old_font     = GetCurrentObject(hdc, OBJ_FONT);
+
+  /* draw title, redraw all its elements */
+  if(IntersectRect(&r_temp, &(ps->rcPaint), title))
+    MONTHCAL_PaintTitle(infoPtr, hdc, ps);
+
+  /* draw calendar area */
+  UnionRect(&r_temp, &infoPtr->wdays, &infoPtr->todayrect);
+  if(IntersectRect(&r_temp, &(ps->rcPaint), &r_temp))
+    MONTHCAL_PaintCalendar(infoPtr, hdc, ps);
+
+  /* week numbers */
+  MONTHCAL_PaintWeeknumbers(infoPtr, hdc, ps);
+
+  /* restore context */
+  SetBkColor(hdc, old_bk_clr);
+  SelectObject(hdc, old_font);
+  SetTextColor(hdc, old_text_clr);
+}
 
 static LRESULT
 MONTHCAL_GetMinReqRect(const MONTHCAL_INFO *infoPtr, LPRECT lpRect)
@@ -746,12 +1041,16 @@ MONTHCAL_GetMinReqRect(const MONTHCAL_INFO *infoPtr, LPRECT lpRect)
 
   if(!lpRect) return FALSE;
 
-  lpRect->left = infoPtr->title.left;
-  lpRect->top = infoPtr->title.top;
-  lpRect->right = infoPtr->title.right;
+  lpRect->left   = infoPtr->title.left;
+  lpRect->top    = infoPtr->title.top;
+  lpRect->right  = infoPtr->title.right;
   lpRect->bottom = infoPtr->todayrect.bottom;
+
   AdjustWindowRect(lpRect, infoPtr->dwStyle, FALSE);
 
+  /* minimal rectangle is zero based */
+  OffsetRect(lpRect, -lpRect->left, -lpRect->top);
+
   TRACE("%s\n", wine_dbgstr_rect(lpRect));
 
   return TRUE;
@@ -845,56 +1144,120 @@ MONTHCAL_SetMonthDelta(MONTHCAL_INFO *infoPtr, INT delta)
 }
 
 
-static LRESULT
+static inline LRESULT
 MONTHCAL_GetFirstDayOfWeek(const MONTHCAL_INFO *infoPtr)
 {
-  return MAKELONG(infoPtr->firstDay, infoPtr->firstDayHighWord);
+  int day;
+
+  /* convert from SYSTEMTIME to locale format */
+  day = (infoPtr->firstDay >= 0) ? (infoPtr->firstDay+6)%7 : infoPtr->firstDay;
+
+  return MAKELONG(day, infoPtr->firstDaySet);
 }
 
 
-/* sets the first day of the week that will appear in the control */
-/* 0 == Sunday, 6 == Saturday */
-/* FIXME: this needs to be implemented properly in MONTHCAL_Refresh() */
-/* FIXME: we need more error checking here */
+/* Sets the first day of the week that will appear in the control
+ *
+ *
+ * PARAMETERS:
+ *  [I] infoPtr : valid pointer to control data
+ *  [I] day : day number to set as new first day (0 == Monday,...,6 == Sunday)
+ *
+ *
+ * RETURN VALUE:
+ *  Low word contains previous first day,
+ *  high word indicates was first day forced with this message before or is
+ *  locale difined (TRUE - was forced, FALSE - wasn't).
+ *
+ * FIXME: this needs to be implemented properly in MONTHCAL_Refresh()
+ * FIXME: we need more error checking here
+ */
 static LRESULT
 MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, INT day)
 {
-  int prev = MAKELONG(infoPtr->firstDay, infoPtr->firstDayHighWord);
-  int localFirstDay;
-  WCHAR buf[40];
-
-  TRACE("day %d\n", day);
+  LRESULT prev = MONTHCAL_GetFirstDayOfWeek(infoPtr);
+  int new_day;
 
-  GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, buf, countof(buf));
-  TRACE("%s %d\n", debugstr_w(buf), strlenW(buf));
-
-  localFirstDay = atoiW(buf);
+  TRACE("%d\n", day);
 
   if(day == -1)
   {
-    infoPtr->firstDay = localFirstDay;
-    infoPtr->firstDayHighWord = FALSE;
+    WCHAR buf[80];
+
+    GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, buf, countof(buf));
+    TRACE("%s %d\n", debugstr_w(buf), strlenW(buf));
+
+    new_day = atoiW(buf);
+
+    infoPtr->firstDaySet = FALSE;
   }
   else if(day >= 7)
   {
-    infoPtr->firstDay = 6; /* max first day allowed */
-    infoPtr->firstDayHighWord = TRUE;
+    new_day = 6; /* max first day allowed */
+    infoPtr->firstDaySet = TRUE;
   }
   else
   {
-    infoPtr->firstDay = day;
-    infoPtr->firstDayHighWord = TRUE;
+    /* Native behaviour for that case is broken: invalid date number >31
+       got displayed at (0,0) position, current month starts always from
+       (1,0) position. Should be implemnted here as well. */
+    if (day < -1)
+      FIXME("No bug compatibility for day=%d\n", day);
+
+    new_day = day;
+    infoPtr->firstDaySet = TRUE;
   }
 
+  /* convert from locale to SYSTEMTIME format */
+  infoPtr->firstDay = (new_day >= 0) ? (++new_day) % 7 : new_day;
+
+  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+
   return prev;
 }
 
 
 static LRESULT
-MONTHCAL_GetMonthRange(const MONTHCAL_INFO *infoPtr)
+MONTHCAL_GetMonthRange(const MONTHCAL_INFO *infoPtr, DWORD flag, SYSTEMTIME *st)
 {
   TRACE("\n");
 
+  if(st)
+  {
+    switch (flag) {
+    case GMR_VISIBLE:
+    {
+        /*FIXME: currently multicalendar feature isn't implemented, so entirely
+                 visible month is current */
+        st[0] = st[1] = infoPtr->curSel;
+
+        if (infoPtr->curSel.wMonth == min_allowed_date.wMonth &&
+            infoPtr->curSel.wYear  == min_allowed_date.wYear)
+        {
+            st[0].wDay = min_allowed_date.wDay;
+        }
+        else
+            st[0].wDay = 1;
+        MONTHCAL_CalculateDayOfWeek(&st[0], TRUE);
+
+        st[1].wDay = MONTHCAL_MonthLength(st[1].wMonth, st[1].wYear);
+        MONTHCAL_CalculateDayOfWeek(&st[1], TRUE);
+        /* a single current month used */
+        return 1;
+    }
+    case GMR_DAYSTATE:
+    {
+        /*FIXME: currently multicalendar feature isn't implemented,
+                 min date from previous month and max date from next one returned */
+        MONTHCAL_GetMinDate(infoPtr, &st[0]);
+        MONTHCAL_GetMaxDate(infoPtr, &st[1]);
+        break;
+    }
+    default:
+        WARN("Unknown flag value, got %d\n", flag);
+    }
+  }
+
   return infoPtr->monthRange;
 }
 
@@ -913,29 +1276,35 @@ MONTHCAL_SetRange(MONTHCAL_INFO *infoPtr, SHORT limits, SYSTEMTIME *range)
 
     TRACE("%x %p\n", limits, range);
 
-    if ((limits & GDTR_MIN && !MONTHCAL_ValidateTime(range[0])) ||
-        (limits & GDTR_MAX && !MONTHCAL_ValidateTime(range[1])))
+    if ((limits & GDTR_MIN && !MONTHCAL_ValidateDate(&range[0])) ||
+        (limits & GDTR_MAX && !MONTHCAL_ValidateDate(&range[1])))
         return FALSE;
 
     if (limits & GDTR_MIN)
     {
-        MONTHCAL_CopyTime(&range[0], &infoPtr->minDate);
+        if (!MONTHCAL_ValidateTime(&range[0]))
+            MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[0]);
+
+        infoPtr->minDate = range[0];
         infoPtr->rangeValid |= GDTR_MIN;
     }
     if (limits & GDTR_MAX)
     {
-        MONTHCAL_CopyTime(&range[1], &infoPtr->maxDate);
+        if (!MONTHCAL_ValidateTime(&range[1]))
+            MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[1]);
+
+        infoPtr->maxDate = range[1];
         infoPtr->rangeValid |= GDTR_MAX;
     }
 
     /* Only one limit set - we are done */
     if ((infoPtr->rangeValid & (GDTR_MIN | GDTR_MAX)) != (GDTR_MIN | GDTR_MAX))
         return TRUE;
-    
+
     SystemTimeToFileTime(&infoPtr->maxDate, &ft_max);
     SystemTimeToFileTime(&infoPtr->minDate, &ft_min);
 
-    if (CompareFileTime(&ft_min, &ft_max) > 0)
+    if (CompareFileTime(&ft_min, &ft_max) >= 0)
     {
         if ((limits & (GDTR_MIN | GDTR_MAX)) == (GDTR_MIN | GDTR_MAX))
         {
@@ -946,9 +1315,10 @@ MONTHCAL_SetRange(MONTHCAL_INFO *infoPtr, SHORT limits, SYSTEMTIME *range)
         }
         else
         {
-            /* Reset the other limit. */
-            /* FIXME: native sets date&time to 0. Should we do this too? */
-            infoPtr->rangeValid &= limits & GDTR_MIN ? ~GDTR_MAX : ~GDTR_MIN ;
+            /* reset the other limit */
+            if (limits & GDTR_MIN) infoPtr->maxDate = st_null;
+            if (limits & GDTR_MAX) infoPtr->minDate = st_null;
+            infoPtr->rangeValid &= limits & GDTR_MIN ? ~GDTR_MAX : ~GDTR_MIN;
         }
     }
 
@@ -963,8 +1333,8 @@ MONTHCAL_GetRange(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *range)
 
   if(!range) return FALSE;
 
-  MONTHCAL_CopyTime(&infoPtr->maxDate, &range[1]);
-  MONTHCAL_CopyTime(&infoPtr->minDate, &range[0]);
+  range[1] = infoPtr->maxDate;
+  range[0] = infoPtr->minDate;
 
   return infoPtr->rangeValid;
 }
@@ -991,34 +1361,46 @@ MONTHCAL_GetCurSel(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
   if(!curSel) return FALSE;
   if(infoPtr->dwStyle & MCS_MULTISELECT) return FALSE;
 
-  MONTHCAL_CopyTime(&infoPtr->minSel, curSel);
+  *curSel = infoPtr->curSel;
   TRACE("%d/%d/%d\n", curSel->wYear, curSel->wMonth, curSel->wDay);
   return TRUE;
 }
 
-/* FIXME: if the specified date is not visible, make it visible */
-/* FIXME: redraw? */
 static LRESULT
 MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, SYSTEMTIME *curSel)
 {
+  SYSTEMTIME prev = infoPtr->curSel;
+
   TRACE("%p\n", curSel);
   if(!curSel) return FALSE;
   if(infoPtr->dwStyle & MCS_MULTISELECT) return FALSE;
 
-  if(!MONTHCAL_ValidateTime(*curSel)) return FALSE;
+  if(!MONTHCAL_ValidateDate(curSel)) return FALSE;
+  /* exit earlier if selection equals current */
+  if (MONTHCAL_IsDateEqual(&infoPtr->curSel, curSel)) return TRUE;
 
-  MONTHCAL_CopyTime(curSel, &infoPtr->minSel);
-  MONTHCAL_CopyTime(curSel, &infoPtr->maxSel);
+  if(!MONTHCAL_IsDateInValidRange(infoPtr, curSel, FALSE)) return FALSE;
 
-  /* exit earlier if selection equals current */
-  if (infoPtr->currentMonth == curSel->wMonth &&
-      infoPtr->currentYear  == curSel->wYear  &&
-      infoPtr->curSelDay    == curSel->wDay) return TRUE;
+  infoPtr->minSel = *curSel;
+  infoPtr->maxSel = *curSel;
 
-  infoPtr->currentMonth = curSel->wMonth;
-  infoPtr->currentYear  = curSel->wYear;
+  /* if selection is still in current month, reduce rectangle */
+  prev.wDay = curSel->wDay;
+  if (MONTHCAL_IsDateEqual(&prev, curSel))
+  {
+    RECT r_prev, r_new;
 
-  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+    /* note that infoPtr->curSel isn't updated yet */
+    MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->curSel, &r_prev);
+    MONTHCAL_CalcPosFromDay(infoPtr, curSel, &r_new);
+
+    InvalidateRect(infoPtr->hwndSelf, &r_prev, FALSE);
+    InvalidateRect(infoPtr->hwndSelf, &r_new,  FALSE);
+  }
+  else
+    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+
+  infoPtr->curSel = *curSel;
 
   return TRUE;
 }
@@ -1036,9 +1418,10 @@ MONTHCAL_SetMaxSelCount(MONTHCAL_INFO *infoPtr, INT max)
 {
   TRACE("%d\n", max);
 
-  if(infoPtr->dwStyle & MCS_MULTISELECT)  {
-    infoPtr->maxSelCount = max;
-  }
+  if(!(infoPtr->dwStyle & MCS_MULTISELECT)) return FALSE;
+  if(max <= 0) return FALSE;
+
+  infoPtr->maxSelCount = max;
 
   return TRUE;
 }
@@ -1053,8 +1436,8 @@ MONTHCAL_GetSelRange(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *range)
 
   if(infoPtr->dwStyle & MCS_MULTISELECT)
   {
-    MONTHCAL_CopyTime(&infoPtr->maxSel, &range[1]);
-    MONTHCAL_CopyTime(&infoPtr->minSel, &range[0]);
+    range[1] = infoPtr->maxSel;
+    range[0] = infoPtr->minSel;
     TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
     return TRUE;
   }
@@ -1072,8 +1455,46 @@ MONTHCAL_SetSelRange(MONTHCAL_INFO *infoPtr, SYSTEMTIME *range)
 
   if(infoPtr->dwStyle & MCS_MULTISELECT)
   {
-    MONTHCAL_CopyTime(&range[1], &infoPtr->maxSel);
-    MONTHCAL_CopyTime(&range[0], &infoPtr->minSel);
+    SYSTEMTIME old_range[2];
+
+    /* adjust timestamps */
+    if(!MONTHCAL_ValidateTime(&range[0]))
+      MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[0]);
+    if(!MONTHCAL_ValidateTime(&range[1]))
+      MONTHCAL_CopyTime(&infoPtr->todaysDate, &range[1]);
+
+    /* maximum range exceeded */
+    if(!MONTHCAL_IsSelRangeValid(infoPtr, &range[0], &range[1], NULL)) return FALSE;
+
+    old_range[0] = infoPtr->minSel;
+    old_range[1] = infoPtr->maxSel;
+
+    /* swap if min > max */
+    if(MONTHCAL_CompareSystemTime(&range[0], &range[1]) <= 0)
+    {
+      infoPtr->minSel = range[0];
+      infoPtr->maxSel = range[1];
+    }
+    else
+    {
+      infoPtr->minSel = range[1];
+      infoPtr->maxSel = range[0];
+    }
+    infoPtr->curSel = infoPtr->minSel;
+
+    /* update day of week */
+    MONTHCAL_CalculateDayOfWeek(&infoPtr->minSel, TRUE);
+    MONTHCAL_CalculateDayOfWeek(&infoPtr->maxSel, TRUE);
+    MONTHCAL_CalculateDayOfWeek(&infoPtr->curSel, TRUE);
+
+    /* redraw if bounds changed */
+    /* FIXME: no actual need to redraw everything */
+    if(!MONTHCAL_IsDateEqual(&old_range[0], &range[0]) ||
+       !MONTHCAL_IsDateEqual(&old_range[1], &range[1]))
+    {
+       InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+    }
+
     TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay);
     return TRUE;
   }
@@ -1088,26 +1509,49 @@ MONTHCAL_GetToday(const MONTHCAL_INFO *infoPtr, SYSTEMTIME *today)
   TRACE("%p\n", today);
 
   if(!today) return FALSE;
-  MONTHCAL_CopyTime(&infoPtr->todaysDate, today);
+  *today = infoPtr->todaysDate;
   return TRUE;
 }
 
+/* Internal helper for MCM_SETTODAY handler and auto update timer handler
+ *
+ * RETURN VALUE
+ *
+ *  TRUE  - today date changed
+ *  FALSE - today date isn't changed
+ */
+static BOOL
+MONTHCAL_UpdateToday(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *today)
+{
+  RECT new_r, old_r;
+
+  if(MONTHCAL_IsDateEqual(today, &infoPtr->todaysDate)) return FALSE;
 
+  MONTHCAL_CalcPosFromDay(infoPtr, &infoPtr->todaysDate, &old_r);
+  MONTHCAL_CalcPosFromDay(infoPtr, today, &new_r);
+
+  infoPtr->todaysDate = *today;
+
+  /* only two days need redrawing */
+  InvalidateRect(infoPtr->hwndSelf, &old_r, FALSE);
+  InvalidateRect(infoPtr->hwndSelf, &new_r, FALSE);
+  return TRUE;
+}
+
+/* MCM_SETTODAT handler */
 static LRESULT
-MONTHCAL_SetToday(MONTHCAL_INFO *infoPtr, SYSTEMTIME *today)
+MONTHCAL_SetToday(MONTHCAL_INFO *infoPtr, const SYSTEMTIME *today)
 {
   TRACE("%p\n", today);
 
   if(!today) return FALSE;
 
-  if(MONTHCAL_IsDateEqual(today, &infoPtr->todaysDate)) return TRUE;
+  /* remember if date was set successfully */
+  if(MONTHCAL_UpdateToday(infoPtr, today)) infoPtr->todaySet = TRUE;
 
-  MONTHCAL_CopyTime(today, &infoPtr->todaysDate);
-  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
   return TRUE;
 }
 
-
 static LRESULT
 MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
 {
@@ -1115,6 +1559,7 @@ MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
   DWORD retval;
   int day,wday,wnum;
 
+  if(!lpht || lpht->cbSize < MCHITTESTINFO_V1_SIZE) return -1;
 
   x = lpht->pt.x;
   y = lpht->pt.y;
@@ -1160,57 +1605,48 @@ MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
   day = MONTHCAL_CalcDayFromPos(infoPtr,x,y,&wday,&wnum);
   if(PtInRect(&infoPtr->wdays, lpht->pt)) {
     retval = MCHT_CALENDARDAY;
-    lpht->st.wYear  = infoPtr->currentYear;
-    lpht->st.wMonth = (day < 1)? infoPtr->currentMonth -1 : infoPtr->currentMonth;
+    lpht->st.wYear  = infoPtr->curSel.wYear;
+    lpht->st.wMonth = (day < 1)? infoPtr->curSel.wMonth -1 : infoPtr->curSel.wMonth;
     lpht->st.wDay   = (day < 1)?
-      MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day : day;
+      MONTHCAL_MonthLength(infoPtr->curSel.wMonth-1, infoPtr->curSel.wYear) -day : day;
     goto done;
   }
   if(PtInRect(&infoPtr->weeknums, lpht->pt)) {
     retval = MCHT_CALENDARWEEKNUM;
-    lpht->st.wYear  = infoPtr->currentYear;
-    lpht->st.wMonth = (day < 1) ? infoPtr->currentMonth -1 :
-      (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ?
-      infoPtr->currentMonth +1 :infoPtr->currentMonth;
+    lpht->st.wYear  = infoPtr->curSel.wYear;
+    lpht->st.wMonth = (day < 1) ? infoPtr->curSel.wMonth -1 :
+      (day > MONTHCAL_MonthLength(infoPtr->curSel.wMonth,infoPtr->curSel.wYear)) ?
+      infoPtr->curSel.wMonth +1 :infoPtr->curSel.wMonth;
     lpht->st.wDay   = (day < 1 ) ?
-      MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day :
-      (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ?
-      day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) : day;
+      MONTHCAL_MonthLength(infoPtr->curSel.wMonth-1,infoPtr->curSel.wYear) -day :
+      (day > MONTHCAL_MonthLength(infoPtr->curSel.wMonth,infoPtr->curSel.wYear)) ?
+      day - MONTHCAL_MonthLength(infoPtr->curSel.wMonth,infoPtr->curSel.wYear) : day;
     goto done;
   }
   if(PtInRect(&infoPtr->days, lpht->pt))
-    {
-      lpht->st.wYear  = infoPtr->currentYear;
-      if ( day < 1)
-       {
+  {
+      lpht->st.wYear  = infoPtr->curSel.wYear;
+      lpht->st.wMonth = infoPtr->curSel.wMonth;
+      if (day < 1)
+      {
          retval = MCHT_CALENDARDATEPREV;
-         lpht->st.wMonth = infoPtr->currentMonth - 1;
-         if (lpht->st.wMonth <1)
-           {
-             lpht->st.wMonth = 12;
-             lpht->st.wYear--;
-           }
-         lpht->st.wDay   = MONTHCAL_MonthLength(lpht->st.wMonth,lpht->st.wYear) -day;
-       }
-      else if (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear))
-       {
+         MONTHCAL_GetPrevMonth(&lpht->st);
+         lpht->st.wDay = MONTHCAL_MonthLength(lpht->st.wMonth, lpht->st.wYear) + day;
+      }
+      else if (day > MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear))
+      {
          retval = MCHT_CALENDARDATENEXT;
-         lpht->st.wMonth = infoPtr->currentMonth + 1;
-         if (lpht->st.wMonth <12)
-           {
-             lpht->st.wMonth = 1;
-             lpht->st.wYear++;
-           }
-         lpht->st.wDay   = day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) ;
-       }
+         MONTHCAL_GetNextMonth(&lpht->st);
+         lpht->st.wDay = day - MONTHCAL_MonthLength(infoPtr->curSel.wMonth, infoPtr->curSel.wYear);
+      }
       else {
        retval = MCHT_CALENDARDATE;
-       lpht->st.wMonth = infoPtr->currentMonth;
-       lpht->st.wDay   = day;
-       lpht->st.wDayOfWeek   = MONTHCAL_CalculateDayOfWeek(day,lpht->st.wMonth,lpht->st.wYear);
+       lpht->st.wDay = day;
       }
+      /* always update day of week */
+      MONTHCAL_CalculateDayOfWeek(&lpht->st, TRUE);
       goto done;
-    }
+  }
   if(PtInRect(&infoPtr->todayrect, lpht->pt)) {
     retval = MCHT_TODAYLINK;
     goto done;
@@ -1225,20 +1661,12 @@ MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, MCHITTESTINFO *lpht)
   return retval;
 }
 
-
-static void MONTHCAL_GoToNextMonth(MONTHCAL_INFO *infoPtr)
+/* MCN_GETDAYSTATE notification helper */
+static void MONTHCAL_NotifyDayState(MONTHCAL_INFO *infoPtr)
 {
-  TRACE("MONTHCAL_GoToNextMonth\n");
-
-  infoPtr->currentMonth++;
-  if(infoPtr->currentMonth > 12) {
-    infoPtr->currentYear++;
-    infoPtr->currentMonth = 1;
-  }
-
   if(infoPtr->dwStyle & MCS_DAYSTATE) {
     NMDAYSTATE nmds;
-    int i;
+    INT i;
 
     nmds.nmhdr.hwndFrom = infoPtr->hwndSelf;
     nmds.nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
@@ -1247,51 +1675,58 @@ static void MONTHCAL_GoToNextMonth(MONTHCAL_INFO *infoPtr)
     nmds.prgDayState   = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE));
 
     nmds.stStart = infoPtr->todaysDate;
-    nmds.stStart.wYear = infoPtr->currentYear;
-    nmds.stStart.wMonth = infoPtr->currentMonth;
+    nmds.stStart.wYear  = infoPtr->curSel.wYear;
+    nmds.stStart.wMonth = infoPtr->curSel.wMonth;
     nmds.stStart.wDay = 1;
 
     SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmds.nmhdr.idFrom, (LPARAM)&nmds);
-    for(i=0; i<infoPtr->monthRange; i++)
+    for(i = 0; i < infoPtr->monthRange; i++)
       infoPtr->monthdayState[i] = nmds.prgDayState[i];
+
+    Free(nmds.prgDayState);
   }
 }
 
-
-static void MONTHCAL_GoToPrevMonth(MONTHCAL_INFO *infoPtr)
+static void MONTHCAL_GoToPrevNextMonth(MONTHCAL_INFO *infoPtr, BOOL prev)
 {
-  TRACE("\n");
+  SYSTEMTIME st = infoPtr->curSel;
 
-  infoPtr->currentMonth--;
-  if(infoPtr->currentMonth < 1) {
-    infoPtr->currentYear--;
-    infoPtr->currentMonth = 12;
-  }
+  TRACE("%s\n", prev ? "prev" : "next");
 
-  if(infoPtr->dwStyle & MCS_DAYSTATE) {
-    NMDAYSTATE nmds;
-    int i;
+  if(prev) MONTHCAL_GetPrevMonth(&st); else MONTHCAL_GetNextMonth(&st);
 
-    nmds.nmhdr.hwndFrom = infoPtr->hwndSelf;
-    nmds.nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
-    nmds.nmhdr.code     = MCN_GETDAYSTATE;
-    nmds.cDayState     = infoPtr->monthRange;
-    nmds.prgDayState   = Alloc
-                        (infoPtr->monthRange * sizeof(MONTHDAYSTATE));
+  if(!MONTHCAL_IsDateInValidRange(infoPtr, &st, FALSE)) return;
 
-    nmds.stStart = infoPtr->todaysDate;
-    nmds.stStart.wYear = infoPtr->currentYear;
-    nmds.stStart.wMonth = infoPtr->currentMonth;
-    nmds.stStart.wDay = 1;
+  if(infoPtr->dwStyle & MCS_MULTISELECT)
+  {
+    SYSTEMTIME range[2];
 
-    SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmds.nmhdr.idFrom, (LPARAM)&nmds);
-    for(i=0; i<infoPtr->monthRange; i++)
-       infoPtr->monthdayState[i] = nmds.prgDayState[i];
+    range[0] = infoPtr->minSel;
+    range[1] = infoPtr->maxSel;
+
+    if(prev)
+    {
+      MONTHCAL_GetPrevMonth(&range[0]);
+      MONTHCAL_GetPrevMonth(&range[1]);
+    }
+    else
+    {
+      MONTHCAL_GetNextMonth(&range[0]);
+      MONTHCAL_GetNextMonth(&range[1]);
+    }
+
+    MONTHCAL_SetSelRange(infoPtr, range);
   }
+  else
+    MONTHCAL_SetCurSel(infoPtr, &st);
+
+  MONTHCAL_NotifyDayState(infoPtr);
+
+  MONTHCAL_NotifySelectionChange(infoPtr);
 }
 
 static LRESULT
-MONTHCAL_RButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
+MONTHCAL_RButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam)
 {
   static const WCHAR todayW[] = { 'G','o',' ','t','o',' ','T','o','d','a','y',':',0 };
   HMENU hMenu;
@@ -1299,182 +1734,205 @@ MONTHCAL_RButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
   WCHAR buf[32];
 
   hMenu = CreatePopupMenu();
-  if (!LoadStringW(COMCTL32_hModule,IDM_GOTODAY,buf,countof(buf)))
-    {
+  if (!LoadStringW(COMCTL32_hModule, IDM_GOTODAY, buf, countof(buf)))
+  {
       WARN("Can't load resource\n");
       strcpyW(buf, todayW);
-    }
-  AppendMenuW(hMenu, MF_STRING|MF_ENABLED,1, buf);
-  menupoint.x=(short)LOWORD(lParam);
-  menupoint.y=(short)HIWORD(lParam);
+  }
+  AppendMenuW(hMenu, MF_STRING|MF_ENABLED, 1, buf);
+  menupoint.x = (short)LOWORD(lParam);
+  menupoint.y = (short)HIWORD(lParam);
   ClientToScreen(infoPtr->hwndSelf, &menupoint);
-  if( TrackPopupMenu(hMenu,TPM_RIGHTBUTTON| TPM_NONOTIFY|TPM_RETURNCMD,
+  if( TrackPopupMenu(hMenu, TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD,
                     menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL))
-    {
-      infoPtr->currentMonth=infoPtr->todaysDate.wMonth;
-      infoPtr->currentYear=infoPtr->todaysDate.wYear;
+  {
+      infoPtr->curSel = infoPtr->todaysDate;
+      infoPtr->minSel = infoPtr->todaysDate;
+      infoPtr->maxSel = infoPtr->todaysDate;
       InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
-    }
+  }
+
   return 0;
 }
 
-static LRESULT
-MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
+/***
+ * DESCRIPTION:
+ * Subclassed edit control windproc function
+ *
+ * PARAMETER(S):
+ * [I] hwnd : the edit window handle
+ * [I] uMsg : the message that is to be processed
+ * [I] wParam : first message parameter
+ * [I] lParam : second message parameter
+ *
+ */
+static LRESULT CALLBACK EditWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
-  static const WCHAR EditW[] = { 'E','D','I','T',0 };
-  MCHITTESTINFO ht;
-  DWORD hit;
-  HMENU hMenu;
-  RECT rcDay; /* used in determining area to invalidate */
-  WCHAR buf[32];
-  int i;
-  POINT menupoint;
+    MONTHCAL_INFO *infoPtr = (MONTHCAL_INFO *)GetWindowLongPtrW(GetParent(hwnd), 0);
 
-  TRACE("%lx\n", lParam);
+    TRACE("(hwnd=%p, uMsg=%x, wParam=%lx, lParam=%lx)\n",
+         hwnd, uMsg, wParam, lParam);
 
-  if (infoPtr->hWndYearUpDown)
+    switch (uMsg)
     {
-      infoPtr->currentYear=SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, 0);
-      if(!DestroyWindow(infoPtr->hWndYearUpDown))
-       {
-         FIXME("Can't destroy Updown Control\n");
-       }
-      else
-       infoPtr->hWndYearUpDown=0;
-      if(!DestroyWindow(infoPtr->hWndYearEdit))
+       case WM_GETDLGCODE:
+         return DLGC_WANTARROWS | DLGC_WANTALLKEYS;
+
+       case WM_DESTROY:
        {
-         FIXME("Can't destroy Updown Control\n");
+           WNDPROC editProc = infoPtr->EditWndProc;
+           infoPtr->EditWndProc = NULL;
+           SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (DWORD_PTR)editProc);
+           return CallWindowProcW(editProc, hwnd, uMsg, wParam, lParam);
        }
-      else
-       infoPtr->hWndYearEdit=0;
-      InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+
+       case WM_KILLFOCUS:
+           break;
+
+       case WM_KEYDOWN:
+           if ((VK_ESCAPE == (INT)wParam) || (VK_RETURN == (INT)wParam))
+               break;
+
+       default:
+           return CallWindowProcW(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam);
     }
 
+    SendMessageW(infoPtr->hWndYearUpDown, WM_CLOSE, 0, 0);
+    SendMessageW(hwnd, WM_CLOSE, 0, 0);
+    return 0;
+}
+
+/* creates updown control and edit box */
+static void MONTHCAL_EditYear(MONTHCAL_INFO *infoPtr)
+{
+    infoPtr->hWndYearEdit =
+       CreateWindowExW(0, WC_EDITW, 0, WS_VISIBLE | WS_CHILD | ES_READONLY,
+                       infoPtr->titleyear.left + 3, infoPtr->titlebtnnext.top,
+                       infoPtr->titleyear.right - infoPtr->titleyear.left + 4,
+                       infoPtr->textHeight, infoPtr->hwndSelf,
+                       NULL, NULL, NULL);
+
+    SendMessageW(infoPtr->hWndYearEdit, WM_SETFONT, (WPARAM)infoPtr->hBoldFont, TRUE);
+
+    infoPtr->hWndYearUpDown =
+       CreateWindowExW(0, UPDOWN_CLASSW, 0,
+                       WS_VISIBLE | WS_CHILD | UDS_SETBUDDYINT | UDS_NOTHOUSANDS | UDS_ARROWKEYS,
+                       infoPtr->titleyear.right + 7, infoPtr->titlebtnnext.top,
+                       18, infoPtr->textHeight, infoPtr->hwndSelf,
+                       NULL, NULL, NULL);
+
+    /* attach edit box */
+    SendMessageW(infoPtr->hWndYearUpDown, UDM_SETRANGE, 0,
+                 MAKELONG(max_allowed_date.wYear, min_allowed_date.wYear));
+    SendMessageW(infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM)infoPtr->hWndYearEdit, 0);
+    SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, infoPtr->curSel.wYear);
+
+    /* subclass edit box */
+    infoPtr->EditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hWndYearEdit,
+                                  GWLP_WNDPROC, (DWORD_PTR)EditWndProc);
+
+    SetFocus(infoPtr->hWndYearEdit);
+}
+
+static LRESULT
+MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
+{
+  MCHITTESTINFO ht;
+  DWORD hit;
+
+  /* Actually we don't need input focus for calendar, this is used to kill
+     year updown and its buddy edit box */
+  if (IsWindow(infoPtr->hWndYearUpDown))
+  {
+      SetFocus(infoPtr->hwndSelf);
+      return 0;
+  }
+
+  SetCapture(infoPtr->hwndSelf);
+
+  ht.cbSize = sizeof(MCHITTESTINFO);
   ht.pt.x = (short)LOWORD(lParam);
   ht.pt.y = (short)HIWORD(lParam);
+
   hit = MONTHCAL_HitTest(infoPtr, &ht);
 
-  /* FIXME: these flags should be checked by */
-  /*((hit & MCHT_XXX) == MCHT_XXX) b/c some of the flags are */
-  /* multi-bit */
-  if(hit ==MCHT_TITLEBTNNEXT) {
-    MONTHCAL_GoToNextMonth(infoPtr);
+  TRACE("%x at (%d, %d)\n", hit, ht.pt.x, ht.pt.y);
+
+  switch(hit)
+  {
+  case MCHT_TITLEBTNNEXT:
+    MONTHCAL_GoToPrevNextMonth(infoPtr, FALSE);
     infoPtr->status = MC_NEXTPRESSED;
-    SetTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER, MC_NEXTMONTHDELAY, 0);
+    SetTimer(infoPtr->hwndSelf, MC_PREVNEXTMONTHTIMER, MC_PREVNEXTMONTHDELAY, 0);
     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
     return 0;
-  }
-  if(hit == MCHT_TITLEBTNPREV){
-    MONTHCAL_GoToPrevMonth(infoPtr);
+
+  case MCHT_TITLEBTNPREV:
+    MONTHCAL_GoToPrevNextMonth(infoPtr, TRUE);
     infoPtr->status = MC_PREVPRESSED;
-    SetTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER, MC_NEXTMONTHDELAY, 0);
+    SetTimer(infoPtr->hwndSelf, MC_PREVNEXTMONTHTIMER, MC_PREVNEXTMONTHDELAY, 0);
     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
     return 0;
-  }
 
-  if(hit == MCHT_TITLEMONTH) {
-    hMenu = CreatePopupMenu();
+  case MCHT_TITLEMONTH:
+  {
+    HMENU hMenu = CreatePopupMenu();
+    WCHAR buf[32];
+    POINT menupoint;
+    INT i;
 
-    for (i=0; i<12;i++)
-      {
-       GetLocaleInfoW(LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+i, buf,countof(buf));
-       AppendMenuW(hMenu, MF_STRING|MF_ENABLED,i+1, buf);
-      }
-    menupoint.x=infoPtr->titlemonth.right;
-    menupoint.y=infoPtr->titlemonth.bottom;
+    for (i = 0; i < 12; i++)
+    {
+       GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SMONTHNAME1+i, buf, countof(buf));
+       AppendMenuW(hMenu, MF_STRING|MF_ENABLED, i + 1, buf);
+    }
+    menupoint.x = ht.pt.x;
+    menupoint.y = ht.pt.y;
     ClientToScreen(infoPtr->hwndSelf, &menupoint);
-    i= TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD,
-                     menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL);
-    if ((i>0) && (i<13))
-      {
-       infoPtr->currentMonth=i;
+    i = TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD,
+                      menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL);
+
+    if ((i > 0) && (i < 13) && infoPtr->curSel.wMonth != i)
+    {
+       infoPtr->curSel.wMonth = i;
+       MONTHCAL_IsDateInValidRange(infoPtr, &infoPtr->curSel, TRUE);
        InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
-      }
+    }
+    return 0;
   }
-  if(hit == MCHT_TITLEYEAR) {
-    infoPtr->hWndYearEdit=CreateWindowExW(0,
-                        EditW,
-                          0,
-                        WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT,
-                        infoPtr->titleyear.left+3,infoPtr->titlebtnnext.top,
-                        infoPtr->titleyear.right-infoPtr->titleyear.left+4,
-                        infoPtr->textHeight,
-                        infoPtr->hwndSelf,
-                        NULL,
-                        NULL,
-                        NULL);
-    SendMessageW( infoPtr->hWndYearEdit, WM_SETFONT, (WPARAM) infoPtr->hBoldFont, (LPARAM)TRUE);
-    infoPtr->hWndYearUpDown=CreateWindowExW(0,
-                        UPDOWN_CLASSW,
-                          0,
-                        WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT|UDS_NOTHOUSANDS|UDS_ARROWKEYS,
-                        infoPtr->titleyear.right+7,infoPtr->titlebtnnext.top,
-                        18,
-                        infoPtr->textHeight,
-                        infoPtr->hwndSelf,
-                        NULL,
-                        NULL,
-                        NULL);
-    SendMessageW(infoPtr->hWndYearUpDown, UDM_SETRANGE, 0, MAKELONG (9999, 1753));
-    SendMessageW(infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM) infoPtr->hWndYearEdit, 0);
-    SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, infoPtr->currentYear);
+  case MCHT_TITLEYEAR:
+  {
+    MONTHCAL_EditYear(infoPtr);
     return 0;
-
   }
-  if(hit == MCHT_TODAYLINK) {
-    NMSELCHANGE nmsc;
-
-    infoPtr->curSelDay = infoPtr->todaysDate.wDay;
-    infoPtr->firstSelDay = infoPtr->todaysDate.wDay;
-    infoPtr->currentMonth=infoPtr->todaysDate.wMonth;
-    infoPtr->currentYear=infoPtr->todaysDate.wYear;
-    MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minSel);
-    MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxSel);
+  case MCHT_TODAYLINK:
+  {
+    infoPtr->curSel = infoPtr->todaysDate;
+    infoPtr->minSel = infoPtr->todaysDate;
+    infoPtr->maxSel = infoPtr->todaysDate;
     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
 
-    nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
-    nmsc.nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
-    nmsc.nmhdr.code     = MCN_SELCHANGE;
-    MONTHCAL_CopyTime(&infoPtr->minSel, &nmsc.stSelStart);
-    MONTHCAL_CopyTime(&infoPtr->maxSel, &nmsc.stSelEnd);
-    SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
-
-    nmsc.nmhdr.code     = MCN_SELECT;
-    SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
+    MONTHCAL_NotifySelectionChange(infoPtr);
+    MONTHCAL_NotifySelect(infoPtr);
     return 0;
   }
-  if(hit == MCHT_CALENDARDATE) {
-    SYSTEMTIME selArray[2];
-    NMSELCHANGE nmsc;
-
-    MONTHCAL_CopyTime(&ht.st, &selArray[0]);
-    MONTHCAL_CopyTime(&ht.st, &selArray[1]);
-    MONTHCAL_SetSelRange(infoPtr, selArray);
-    MONTHCAL_SetCurSel(infoPtr, &selArray[0]);
-    TRACE("MCHT_CALENDARDATE\n");
-    nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
-    nmsc.nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
-    nmsc.nmhdr.code     = MCN_SELCHANGE;
-    MONTHCAL_CopyTime(&infoPtr->minSel,&nmsc.stSelStart);
-    MONTHCAL_CopyTime(&infoPtr->maxSel,&nmsc.stSelEnd);
-
-    SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
-
+  case MCHT_CALENDARDATENEXT:
+  case MCHT_CALENDARDATEPREV:
+  case MCHT_CALENDARDATE:
+  {
+    SYSTEMTIME st[2];
 
-    /* redraw both old and new days if the selected day changed */
-    if(infoPtr->curSelDay != ht.st.wDay) {
-      MONTHCAL_CalcPosFromDay(infoPtr, ht.st.wDay, ht.st.wMonth, &rcDay);
-      InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE);
+    MONTHCAL_CopyDate(&ht.st, &infoPtr->firstSel);
 
-      MONTHCAL_CalcPosFromDay(infoPtr, infoPtr->curSelDay, infoPtr->currentMonth, &rcDay);
-      InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE);
-    }
+    st[0] = st[1] = ht.st;
+    /* clear selection range */
+    MONTHCAL_SetSelRange(infoPtr, st);
 
-    infoPtr->firstSelDay = ht.st.wDay;
-    infoPtr->curSelDay = ht.st.wDay;
     infoPtr->status = MC_SEL_LBUTDOWN;
+    MONTHCAL_SetDayFocus(infoPtr, &ht.st);
     return 0;
   }
+  }
 
   return 1;
 }
@@ -1483,90 +1941,90 @@ MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam)
 static LRESULT
 MONTHCAL_LButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam)
 {
-  NMSELCHANGE nmsc;
   NMHDR nmhdr;
-  BOOL redraw = FALSE;
   MCHITTESTINFO ht;
   DWORD hit;
 
   TRACE("\n");
 
-  if(infoPtr->status & MC_NEXTPRESSED) {
-    KillTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER);
-    infoPtr->status &= ~MC_NEXTPRESSED;
-    redraw = TRUE;
-  }
-  if(infoPtr->status & MC_PREVPRESSED) {
-    KillTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER);
-    infoPtr->status &= ~MC_PREVPRESSED;
-    redraw = TRUE;
-  }
-
-  ht.pt.x = (short)LOWORD(lParam);
-  ht.pt.y = (short)HIWORD(lParam);
-  hit = MONTHCAL_HitTest(infoPtr, &ht);
+  if(infoPtr->status & (MC_PREVPRESSED | MC_NEXTPRESSED)) {
+    RECT *r;
 
-  infoPtr->status = MC_SEL_LBUTUP;
+    KillTimer(infoPtr->hwndSelf, MC_PREVNEXTMONTHTIMER);
+    r = infoPtr->status & MC_PREVPRESSED ? &infoPtr->titlebtnprev : &infoPtr->titlebtnnext;
+    infoPtr->status &= ~(MC_PREVPRESSED | MC_NEXTPRESSED);
 
-  if(hit ==MCHT_CALENDARDATENEXT) {
-    MONTHCAL_GoToNextMonth(infoPtr);
-    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
-    return TRUE;
-  }
-  if(hit == MCHT_CALENDARDATEPREV){
-    MONTHCAL_GoToPrevMonth(infoPtr);
-    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
-    return TRUE;
+    InvalidateRect(infoPtr->hwndSelf, r, FALSE);
   }
+
+  ReleaseCapture();
+
+  /* always send NM_RELEASEDCAPTURE notification */
   nmhdr.hwndFrom = infoPtr->hwndSelf;
   nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
   nmhdr.code     = NM_RELEASEDCAPTURE;
   TRACE("Sent notification from %p to %p\n", infoPtr->hwndSelf, infoPtr->hwndNotify);
 
   SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhdr.idFrom, (LPARAM)&nmhdr);
-  /* redraw if necessary */
-  if(redraw)
-    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
-  /* only send MCN_SELECT if currently displayed month's day was selected */
-  if(hit == MCHT_CALENDARDATE) {
-    nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf;
-    nmsc.nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
-    nmsc.nmhdr.code     = MCN_SELECT;
-    MONTHCAL_CopyTime(&infoPtr->minSel, &nmsc.stSelStart);
-    MONTHCAL_CopyTime(&infoPtr->maxSel, &nmsc.stSelEnd);
 
-    SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc);
+  if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0;
+
+  ht.cbSize = sizeof(MCHITTESTINFO);
+  ht.pt.x = (short)LOWORD(lParam);
+  ht.pt.y = (short)HIWORD(lParam);
+  hit = MONTHCAL_HitTest(infoPtr, &ht);
+
+  infoPtr->status = MC_SEL_LBUTUP;
+  MONTHCAL_SetDayFocus(infoPtr, NULL);
+
+  if((hit & MCHT_CALENDARDATE) == MCHT_CALENDARDATE)
+  {
+    SYSTEMTIME sel = infoPtr->curSel;
+
+    /* will be invalidated here */
+    MONTHCAL_SetCurSel(infoPtr, &ht.st);
 
+    /* send MCN_SELCHANGE only if new date selected */
+    if (!MONTHCAL_IsDateEqual(&sel, &ht.st))
+        MONTHCAL_NotifySelectionChange(infoPtr);
+
+    MONTHCAL_NotifySelect(infoPtr);
   }
+
   return 0;
 }
 
 
 static LRESULT
-MONTHCAL_Timer(MONTHCAL_INFO *infoPtr, WPARAM wParam)
+MONTHCAL_Timer(MONTHCAL_INFO *infoPtr, WPARAM id)
 {
-  BOOL redraw = FALSE;
+  TRACE("%ld\n", id);
 
-  TRACE("%ld\n", wParam);
-
-  switch(wParam) {
-  case MC_NEXTMONTHTIMER:
-    redraw = TRUE;
-    MONTHCAL_GoToNextMonth(infoPtr);
-    break;
-  case MC_PREVMONTHTIMER:
-    redraw = TRUE;
-    MONTHCAL_GoToPrevMonth(infoPtr);
+  switch(id) {
+  case MC_PREVNEXTMONTHTIMER:
+    if(infoPtr->status & MC_NEXTPRESSED) MONTHCAL_GoToPrevNextMonth(infoPtr, FALSE);
+    if(infoPtr->status & MC_PREVPRESSED) MONTHCAL_GoToPrevNextMonth(infoPtr, TRUE);
+    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
     break;
+  case MC_TODAYUPDATETIMER:
+  {
+    SYSTEMTIME st;
+
+    if(infoPtr->todaySet) return 0;
+
+    GetLocalTime(&st);
+    MONTHCAL_UpdateToday(infoPtr, &st);
+
+    /* notification sent anyway */
+    MONTHCAL_NotifySelectionChange(infoPtr);
+
+    return 0;
+  }
   default:
-    ERR("got unknown timer\n");
+    ERR("got unknown timer %ld\n", id);
     break;
   }
 
-  /* redraw only if necessary */
-  if(redraw)
-    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
-
   return 0;
 }
 
@@ -1575,11 +2033,13 @@ static LRESULT
 MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, LPARAM lParam)
 {
   MCHITTESTINFO ht;
-  int oldselday, selday, hit;
+  SYSTEMTIME st_ht;
+  INT hit;
   RECT r;
 
   if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0;
 
+  ht.cbSize = sizeof(MCHITTESTINFO);
   ht.pt.x = (short)LOWORD(lParam);
   ht.pt.y = (short)HIWORD(lParam);
 
@@ -1587,58 +2047,46 @@ MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, LPARAM lParam)
 
   /* not on the calendar date numbers? bail out */
   TRACE("hit:%x\n",hit);
-  if((hit & MCHT_CALENDARDATE) != MCHT_CALENDARDATE) return 0;
-
-  selday = ht.st.wDay;
-  oldselday = infoPtr->curSelDay;
-  infoPtr->curSelDay = selday;
-  MONTHCAL_CalcPosFromDay(infoPtr, selday, ht.st. wMonth, &r);
-
-  if(infoPtr->dwStyle & MCS_MULTISELECT)  {
-    SYSTEMTIME selArray[2];
-    int i;
-
-    MONTHCAL_GetSelRange(infoPtr, selArray);
-    i = 0;
-    if(infoPtr->firstSelDay==selArray[0].wDay) i=1;
-    TRACE("oldRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i);
-    if(infoPtr->firstSelDay==selArray[1].wDay) {
-      /* 1st time we get here: selArray[0]=selArray[1])  */
-      /* if we're still at the first selected date, return */
-      if(infoPtr->firstSelDay==selday) goto done;
-      if(selday<infoPtr->firstSelDay) i = 0;
-    }
+  if((hit & MCHT_CALENDARDATE) != MCHT_CALENDARDATE)
+  {
+    MONTHCAL_SetDayFocus(infoPtr, NULL);
+    return 0;
+  }
 
-    if(abs(infoPtr->firstSelDay - selday) >= infoPtr->maxSelCount) {
-      if(selday>infoPtr->firstSelDay)
-        selday = infoPtr->firstSelDay + infoPtr->maxSelCount;
-      else
-        selday = infoPtr->firstSelDay - infoPtr->maxSelCount;
-    }
+  st_ht = ht.st;
 
-    if(selArray[i].wDay!=selday) {
-      TRACE("newRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i);
+  /* if pointer is over focused day still there's nothing to do */
+  if(!MONTHCAL_SetDayFocus(infoPtr, &ht.st)) return 0;
 
-      selArray[i].wDay = selday;
+  MONTHCAL_CalcPosFromDay(infoPtr, &ht.st, &r);
 
-      if(selArray[0].wDay>selArray[1].wDay) {
-        DWORD tempday;
-        tempday = selArray[1].wDay;
-        selArray[1].wDay = selArray[0].wDay;
-        selArray[0].wDay = tempday;
-      }
+  if(infoPtr->dwStyle & MCS_MULTISELECT) {
+    SYSTEMTIME st[2];
 
-      MONTHCAL_SetSelRange(infoPtr, selArray);
-    }
+    MONTHCAL_GetSelRange(infoPtr, st);
+
+    /* If we're still at the first selected date and range is empty, return.
+       If range isn't empty we should change range to a single firstSel */
+    if(MONTHCAL_IsDateEqual(&infoPtr->firstSel, &st_ht) &&
+       MONTHCAL_IsDateEqual(&st[0], &st[1])) goto done;
+
+    MONTHCAL_IsSelRangeValid(infoPtr, &st_ht, &infoPtr->firstSel, &st_ht);
+
+    st[0] = infoPtr->firstSel;
+    /* we should overwrite timestamp here */
+    MONTHCAL_CopyDate(&st_ht, &st[1]);
+
+    /* bounds will be swapped here if needed */
+    MONTHCAL_SetSelRange(infoPtr, st);
+
+    return 0;
   }
 
 done:
 
-  /* only redraw if the currently selected day changed */
-  /* FIXME: this should specify a rectangle containing only the days that changed */
-  /* using InvalidateRect */
-  if(oldselday != infoPtr->curSelDay)
-    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
+  /* FIXME: this should specify a rectangle containing only the days that changed
+     using InvalidateRect */
+  InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
 
   return 0;
 }
@@ -1663,21 +2111,39 @@ MONTHCAL_Paint(MONTHCAL_INFO *infoPtr, HDC hdc_paint)
   return 0;
 }
 
+static LRESULT
+MONTHCAL_EraseBkgnd(const MONTHCAL_INFO *infoPtr, HDC hdc)
+{
+  HBRUSH hbr;
+  RECT rc;
+
+  if (!GetClipBox(hdc, &rc)) return FALSE;
+
+  /* fill background */
+  hbr = CreateSolidBrush (infoPtr->bk);
+  FillRect(hdc, &rc, hbr);
+  DeleteObject(hbr);
+
+  return TRUE;
+}
 
 static LRESULT
-MONTHCAL_KillFocus(const MONTHCAL_INFO *infoPtr, HWND hFocusWnd)
+MONTHCAL_PrintClient(MONTHCAL_INFO *infoPtr, HDC hdc, DWORD options)
 {
-  TRACE("\n");
+  FIXME("Partial Stub: (hdc=%p options=0x%08x)\n", hdc, options);
 
-  if (infoPtr->hwndNotify != hFocusWnd)
-    ShowWindow(infoPtr->hwndSelf, SW_HIDE);
-  else
-    InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
+  if ((options & PRF_CHECKVISIBLE) && !IsWindowVisible(infoPtr->hwndSelf))
+      return 0;
+
+  if (options & PRF_ERASEBKGND)
+      MONTHCAL_EraseBkgnd(infoPtr, hdc);
+
+  if (options & PRF_CLIENT)
+      MONTHCAL_Paint(infoPtr, hdc);
 
   return 0;
 }
 
-
 static LRESULT
 MONTHCAL_SetFocus(const MONTHCAL_INFO *infoPtr)
 {
@@ -1691,7 +2157,6 @@ MONTHCAL_SetFocus(const MONTHCAL_INFO *infoPtr)
 /* sets the size information */
 static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
 {
-  static const WCHAR SunW[] = { 'S','u','n',0 };
   static const WCHAR O0W[] = { '0','0',0 };
   HDC hdc = GetDC(infoPtr->hwndSelf);
   RECT *title=&infoPtr->title;
@@ -1703,11 +2168,12 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
   RECT *weeknumrect=&infoPtr->weeknums;
   RECT *days=&infoPtr->days;
   RECT *todayrect=&infoPtr->todayrect;
-  SIZE size;
+  SIZE size, sz;
   TEXTMETRICW tm;
   HFONT currentFont;
-  int xdiv, left_offset;
+  INT xdiv, dx, dy, i;
   RECT rcClient;
+  WCHAR buff[80];
 
   GetClientRect(infoPtr->hwndSelf, &rcClient);
 
@@ -1716,7 +2182,26 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
   /* get the height and width of each day's text */
   GetTextMetricsW(hdc, &tm);
   infoPtr->textHeight = tm.tmHeight + tm.tmExternalLeading + tm.tmInternalLeading;
-  GetTextExtentPoint32W(hdc, SunW, 3, &size);
+
+  /* find largest abbreviated day name for current locale */
+  size.cx = sz.cx = 0;
+  for (i = 0; i < 7; i++)
+  {
+      if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1 + i,
+                        buff, countof(buff)))
+      {
+          GetTextExtentPoint32W(hdc, buff, lstrlenW(buff), &sz);
+          if (sz.cx > size.cx) size.cx = sz.cx;
+      }
+      else /* locale independent fallback on failure */
+      {
+          static const WCHAR SunW[] = { 'S','u','n',0 };
+
+          GetTextExtentPoint32W(hdc, SunW, lstrlenW(SunW), &size);
+          break;
+      }
+  }
+
   infoPtr->textWidth = size.cx + 2;
 
   /* recalculate the height and width increments and offsets */
@@ -1724,22 +2209,21 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
 
   xdiv = (infoPtr->dwStyle & MCS_WEEKNUMBERS) ? 8 : 7;
 
-  infoPtr->width_increment = size.cx * 2 + 4;
+  infoPtr->width_increment  = size.cx * 2 + 4;
   infoPtr->height_increment = infoPtr->textHeight;
-  left_offset = (rcClient.right - rcClient.left) - (infoPtr->width_increment * xdiv);
 
   /* calculate title area */
-  title->top    = rcClient.top;
-  title->bottom = title->top + 3 * infoPtr->height_increment / 2;
-  title->left   = left_offset;
-  title->right  = rcClient.right;
+  title->top    = 0;
+  title->bottom = 3 * infoPtr->height_increment / 2;
+  title->left   = 0;
+  title->right  = infoPtr->width_increment * xdiv;
 
   /* set the dimensions of the next and previous buttons and center */
   /* the month text vertically */
   prev->top    = next->top    = title->top + 4;
   prev->bottom = next->bottom = title->bottom - 4;
   prev->left   = title->left + 4;
-  prev->right  = prev->left + (title->bottom - title->top) ;
+  prev->right  = prev->left + (title->bottom - title->top);
   next->right  = title->right - 4;
   next->left   = next->right - (title->bottom - title->top);
 
@@ -1751,24 +2235,47 @@ static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr)
 
   /* setup the dimensions of the rectangle we draw the names of the */
   /* days of the week in */
-  weeknumrect->left = left_offset;
+  weeknumrect->left = 0;
+
   if(infoPtr->dwStyle & MCS_WEEKNUMBERS)
-    weeknumrect->right=prev->right;
+    weeknumrect->right = prev->right;
   else
-    weeknumrect->right=weeknumrect->left;
+    weeknumrect->right = weeknumrect->left;
+
   wdays->left   = days->left   = weeknumrect->right;
   wdays->right  = days->right  = wdays->left + 7 * infoPtr->width_increment;
-  wdays->top    = title->bottom ;
+  wdays->top    = title->bottom;
   wdays->bottom = wdays->top + infoPtr->height_increment;
 
-  days->top    = weeknumrect->top = wdays->bottom ;
+  days->top    = weeknumrect->top = wdays->bottom;
   days->bottom = weeknumrect->bottom = days->top + 6 * infoPtr->height_increment;
 
-  todayrect->left   = rcClient.left;
-  todayrect->right  = rcClient.right;
+  todayrect->left   = 0;
+  todayrect->right  = title->right;
   todayrect->top    = days->bottom;
   todayrect->bottom = days->bottom + infoPtr->height_increment;
 
+  /* offset all rectangles to center in client area */
+  dx = (rcClient.right  - title->right) / 2;
+  dy = (rcClient.bottom - todayrect->bottom) / 2;
+
+  /* if calendar doesn't fit client area show it at left/top bounds */
+  if (title->left + dx < 0) dx = 0;
+  if (title->top  + dy < 0) dy = 0;
+
+  if (dx != 0 || dy != 0)
+  {
+    OffsetRect(title, dx, dy);
+    OffsetRect(prev,  dx, dy);
+    OffsetRect(next,  dx, dy);
+    OffsetRect(titlemonth, dx, dy);
+    OffsetRect(titleyear, dx, dy);
+    OffsetRect(wdays, dx, dy);
+    OffsetRect(weeknumrect, dx, dy);
+    OffsetRect(days, dx, dy);
+    OffsetRect(todayrect, dx, dy);
+  }
+
   TRACE("dx=%d dy=%d client[%s] title[%s] wdays[%s] days[%s] today[%s]\n",
        infoPtr->width_increment,infoPtr->height_increment,
         wine_dbgstr_rect(&rcClient),
@@ -1841,6 +2348,28 @@ static INT MONTHCAL_StyleChanged(MONTHCAL_INFO *infoPtr, WPARAM wStyleType,
 
     infoPtr->dwStyle = lpss->styleNew;
 
+    /* make room for week numbers */
+    if ((lpss->styleNew ^ lpss->styleOld) & MCS_WEEKNUMBERS)
+        MONTHCAL_UpdateSize(infoPtr);
+
+    return 0;
+}
+
+static INT MONTHCAL_StyleChanging(MONTHCAL_INFO *infoPtr, WPARAM wStyleType,
+                                  STYLESTRUCT *lpss)
+{
+    TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
+          wStyleType, lpss->styleOld, lpss->styleNew);
+
+    /* block MCS_MULTISELECT change */
+    if ((lpss->styleNew ^ lpss->styleOld) & MCS_MULTISELECT)
+    {
+        if (lpss->styleOld & MCS_MULTISELECT)
+            lpss->styleNew |= MCS_MULTISELECT;
+        else
+            lpss->styleNew &= ~MCS_MULTISELECT;
+    }
+
     return 0;
 }
 
@@ -1869,33 +2398,30 @@ MONTHCAL_Create(HWND hwnd, LPCREATESTRUCTW lpcs)
   /* FIXME: calculate systemtime ->> localtime(substract timezoneinfo) */
 
   GetLocalTime(&infoPtr->todaysDate);
-  infoPtr->firstDayHighWord = FALSE;
   MONTHCAL_SetFirstDayOfWeek(infoPtr, -1);
-  infoPtr->currentMonth = infoPtr->todaysDate.wMonth;
-  infoPtr->currentYear = infoPtr->todaysDate.wYear;
-  MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minDate);
-  MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate);
-  infoPtr->maxDate.wYear=2050;
-  infoPtr->minDate.wYear=1950;
-  infoPtr->maxSelCount  = 7;
-  infoPtr->monthRange = 3;
-  infoPtr->monthdayState = Alloc
-                         (infoPtr->monthRange * sizeof(MONTHDAYSTATE));
-  infoPtr->titlebk     = comctl32_color.clrActiveCaption;
-  infoPtr->titletxt    = comctl32_color.clrWindow;
-  infoPtr->monthbk     = comctl32_color.clrWindow;
-  infoPtr->trailingtxt = comctl32_color.clrGrayText;
-  infoPtr->bk          = comctl32_color.clrWindow;
-  infoPtr->txt        = comctl32_color.clrWindowText;
-
-  /* set the current day for highlighing */
-  infoPtr->minSel.wDay = infoPtr->todaysDate.wDay;
-  infoPtr->maxSel.wDay = infoPtr->todaysDate.wDay;
+
+  infoPtr->maxSelCount   = (infoPtr->dwStyle & MCS_MULTISELECT) ? 7 : 1;
+  infoPtr->monthRange    = 3;
+  infoPtr->monthdayState = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE));
+  infoPtr->titlebk       = comctl32_color.clrActiveCaption;
+  infoPtr->titletxt      = comctl32_color.clrWindow;
+  infoPtr->monthbk       = comctl32_color.clrWindow;
+  infoPtr->trailingtxt   = comctl32_color.clrGrayText;
+  infoPtr->bk            = comctl32_color.clrWindow;
+  infoPtr->txt          = comctl32_color.clrWindowText;
+
+  infoPtr->minSel = infoPtr->todaysDate;
+  infoPtr->maxSel = infoPtr->todaysDate;
+  infoPtr->curSel = infoPtr->todaysDate;
+  infoPtr->isUnicode = TRUE;
 
   /* call MONTHCAL_UpdateSize to set all of the dimensions */
   /* of the control */
   MONTHCAL_UpdateSize(infoPtr);
-  
+
+  /* today auto update timer, to be freed only on control destruction */
+  SetTimer(infoPtr->hwndSelf, MC_TODAYUPDATETIMER, MC_TODAYUPDATEDELAY, 0);
+
   OpenThemeData (infoPtr->hwndSelf, themeClass);
 
   return 0;
@@ -1915,6 +2441,45 @@ MONTHCAL_Destroy(MONTHCAL_INFO *infoPtr)
   return 0;
 }
 
+/*
+ * Handler for WM_NOTIFY messages
+ */
+static LRESULT
+MONTHCAL_Notify(MONTHCAL_INFO *infoPtr, NMHDR *hdr)
+{
+  /* notification from year edit updown */
+  if (hdr->code == UDN_DELTAPOS)
+  {
+    NMUPDOWN *nmud = (NMUPDOWN*)hdr;
+
+    if (hdr->hwndFrom == infoPtr->hWndYearUpDown)
+    {
+      /* year value limits are set up explicitly after updown creation */
+      if ((nmud->iDelta + nmud->iPos) != infoPtr->curSel.wYear)
+      {
+        SYSTEMTIME new_date = infoPtr->curSel;
+
+        new_date.wYear = nmud->iDelta + nmud->iPos;
+        MONTHCAL_SetCurSel(infoPtr, &new_date);
+      }
+    }
+  }
+  return 0;
+}
+
+static inline BOOL
+MONTHCAL_SetUnicodeFormat(MONTHCAL_INFO *infoPtr, BOOL isUnicode)
+{
+  BOOL prev = infoPtr->isUnicode;
+  infoPtr->isUnicode = isUnicode;
+  return prev;
+}
+
+static inline BOOL
+MONTHCAL_GetUnicodeFormat(const MONTHCAL_INFO *infoPtr)
+{
+  return infoPtr->isUnicode;
+}
 
 static LRESULT WINAPI
 MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
@@ -1947,7 +2512,7 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     return MONTHCAL_SetSelRange(infoPtr, (LPSYSTEMTIME)lParam);
 
   case MCM_GETMONTHRANGE:
-    return MONTHCAL_GetMonthRange(infoPtr);
+    return MONTHCAL_GetMonthRange(infoPtr, wParam, (SYSTEMTIME*)lParam);
 
   case MCM_SETDAYSTATE:
     return MONTHCAL_SetDayState(infoPtr, (INT)wParam, (LPMONTHDAYSTATE)lParam);
@@ -1991,14 +2556,17 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   case MCM_GETMAXTODAYWIDTH:
     return MONTHCAL_GetMaxTodayWidth(infoPtr);
 
+  case MCM_SETUNICODEFORMAT:
+    return MONTHCAL_SetUnicodeFormat(infoPtr, (BOOL)wParam);
+
+  case MCM_GETUNICODEFORMAT:
+    return MONTHCAL_GetUnicodeFormat(infoPtr);
+
   case WM_GETDLGCODE:
     return DLGC_WANTARROWS | DLGC_WANTCHARS;
 
-  case WM_KILLFOCUS:
-    return MONTHCAL_KillFocus(infoPtr, (HWND)wParam);
-
-  case WM_RBUTTONDOWN:
-    return MONTHCAL_RButtonDown(infoPtr, lParam);
+  case WM_RBUTTONUP:
+    return MONTHCAL_RButtonUp(infoPtr, lParam);
 
   case WM_LBUTTONDOWN:
     return MONTHCAL_LButtonDown(infoPtr, lParam);
@@ -2009,16 +2577,24 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   case WM_LBUTTONUP:
     return MONTHCAL_LButtonUp(infoPtr, lParam);
 
-  case WM_PRINTCLIENT:
   case WM_PAINT:
     return MONTHCAL_Paint(infoPtr, (HDC)wParam);
 
+  case WM_PRINTCLIENT:
+    return MONTHCAL_PrintClient(infoPtr, (HDC)wParam, (DWORD)lParam);
+
+  case WM_ERASEBKGND:
+    return MONTHCAL_EraseBkgnd(infoPtr, (HDC)wParam);
+
   case WM_SETFOCUS:
     return MONTHCAL_SetFocus(infoPtr);
 
   case WM_SIZE:
     return MONTHCAL_Size(infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
 
+  case WM_NOTIFY:
+    return MONTHCAL_Notify(infoPtr, (NMHDR*)lParam);
+
   case WM_CREATE:
     return MONTHCAL_Create(hwnd, (LPCREATESTRUCTW)lParam);
 
@@ -2044,6 +2620,9 @@ MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   case WM_STYLECHANGED:
     return MONTHCAL_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
 
+  case WM_STYLECHANGING:
+    return MONTHCAL_StyleChanging(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
+
   default:
     if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
       ERR( "unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);