[COMCTL32] Add NULL checks to SetWindowSubclass.
[reactos.git] / dll / win32 / comctl32 / commctrl.c
index 42c8009..a3bbd5f 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright 1997 Dimitrie O. Paun
  * Copyright 1998,2000 Eric Kohl
+ * Copyright 2014-2015 Michael Müller
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
 
-#define NAME       L"microsoft.windows.common-controls"
-#define VERSION    L"6.0.2600.2982"
-#define PUBLIC_KEY L"6595b64144ccf1df"
-
-#ifdef __i386__
-#define ARCH L"x86"
-#elif defined __x86_64__
-#define ARCH L"amd64"
-#else
-#define ARCH L"none"
-#endif
-
-static const WCHAR manifest_filename[] = ARCH L"_" NAME L"_" PUBLIC_KEY L"_" VERSION L"_none_deadbeef.manifest";
 
 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
@@ -105,67 +93,235 @@ static const WCHAR strCC32SubclassInfo[] = {
     'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0
 };
 
-static BOOL create_manifest(BOOL install)
-{
-    WCHAR *pwszBuf;
-    HRSRC hResInfo;
-    HGLOBAL hResData;
-    PVOID pManifest;
-    DWORD cchBuf, cbManifest, cbWritten;
-    HANDLE hFile;
-    BOOL bRet = FALSE;
-
-    hResInfo = FindResourceW(COMCTL32_hModule, L"WINE_MANIFEST", RT_MANIFEST);
-    if (!hResInfo)
-        return FALSE;
+#ifdef __REACTOS__
 
-    cbManifest = SizeofResource(COMCTL32_hModule, hResInfo);
-    if (!cbManifest)
-        return FALSE;
+#include <strsafe.h>
 
-    hResData = LoadResource(COMCTL32_hModule, hResInfo);
-    if (!hResData)
-        return FALSE;
+#define NAME       L"microsoft.windows.common-controls"
+#define VERSION_V5 L"5.82.2600.2982"
+#define VERSION    L"6.0.2600.2982"
+#define PUBLIC_KEY L"6595b64144ccf1df"
 
-    pManifest = LockResource(hResData);
-    if (!pManifest)
-        return FALSE;
+#ifdef __i386__
+#define ARCH L"x86"
+#elif defined __x86_64__
+#define ARCH L"amd64"
+#else
+#define ARCH L"none"
+#endif
+
+static const WCHAR manifest_filename[] = ARCH L"_" NAME L"_" PUBLIC_KEY L"_" VERSION L"_none_deadbeef.manifest";
+static const WCHAR manifest_filename_v5[] = ARCH L"_" NAME L"_" PUBLIC_KEY L"_" VERSION_V5 L"_none_deadbeef.manifest";
+
+static WCHAR* GetManifestPath(BOOL create, BOOL bV6)
+{
+    WCHAR *pwszBuf;
+    HRESULT hres;
 
-    cchBuf = GetWindowsDirectoryW(NULL, 0) * sizeof(WCHAR) + sizeof(L"\\winsxs\\manifests\\") + sizeof(manifest_filename);
-    pwszBuf = (WCHAR*)HeapAlloc(GetProcessHeap(), 0, cchBuf * sizeof(WCHAR));
+    pwszBuf = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
     if (!pwszBuf)
-        return FALSE;
+        return NULL;
+
+    GetWindowsDirectoryW(pwszBuf, MAX_PATH);
+    hres = StringCchCatW(pwszBuf, MAX_PATH, L"\\winsxs");
+    if (FAILED(hres))
+        return NULL;
+    if (create)
+        CreateDirectoryW(pwszBuf, NULL);
+    hres = StringCchCatW(pwszBuf, MAX_PATH, L"\\manifests\\");
+    if (FAILED(hres))
+        return NULL;
+    if (create)
+        CreateDirectoryW(pwszBuf, NULL);
+
+    hres = StringCchCatW(pwszBuf, MAX_PATH, bV6 ? manifest_filename : manifest_filename_v5);
+    if (FAILED(hres))
+        return NULL;
+
+    return pwszBuf;
+}
+
+static HANDLE CreateComctl32ActCtx(BOOL bV6)
+{
+    HANDLE ret;
+    WCHAR* pwstrSource;
+    ACTCTXW ActCtx = {sizeof(ACTCTX)};
 
-    GetWindowsDirectoryW(pwszBuf, cchBuf);
-    lstrcatW(pwszBuf, L"\\winsxs");
-    CreateDirectoryW(pwszBuf, NULL);
-    lstrcatW(pwszBuf, L"\\manifests\\");
-    CreateDirectoryW(pwszBuf, NULL);
-    lstrcatW(pwszBuf, manifest_filename);
-    if (install)
+    pwstrSource = GetManifestPath(FALSE, bV6);
+    if (!pwstrSource)
     {
-        hFile = CreateFileW(pwszBuf, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
-        if (hFile != INVALID_HANDLE_VALUE)
-        {
-            if (WriteFile(hFile, pManifest, cbManifest, &cbWritten, NULL) && cbWritten == cbManifest)
-                bRet = TRUE;
+        ERR("GetManifestPath failed! bV6=%d\n", bV6);
+        return INVALID_HANDLE_VALUE;
+    }
+    ActCtx.lpSource = pwstrSource;
+    ret = CreateActCtxW(&ActCtx);
+    HeapFree(GetProcessHeap(), 0, pwstrSource);
+    if (ret == INVALID_HANDLE_VALUE)
+        ERR("CreateActCtxW failed! bV6=%d\n", bV6);
+    return ret;
+}
 
-            CloseHandle(hFile);
+static void RegisterControls(BOOL bV6)
+{
+    ANIMATE_Register ();
+    COMBOEX_Register ();
+    DATETIME_Register ();
+    FLATSB_Register ();
+    HEADER_Register ();
+    HOTKEY_Register ();
+    IPADDRESS_Register ();
+    LISTVIEW_Register ();
+    MONTHCAL_Register ();
+    NATIVEFONT_Register ();
+    PAGER_Register ();
+    PROGRESS_Register ();
+    REBAR_Register ();
+    STATUS_Register ();
+    SYSLINK_Register ();
+    TAB_Register ();
+    TOOLTIPS_Register ();
+    TRACKBAR_Register ();
+    TREEVIEW_Register ();
+    UPDOWN_Register ();
+
+    if (!bV6)
+    {
+        TOOLBAR_Register ();
+    }
+    else
+    {
+        BUTTON_Register ();
+        COMBO_Register ();
+        COMBOLBOX_Register ();
+        EDIT_Register ();
+        LISTBOX_Register ();
+        STATIC_Register ();
+
+        TOOLBARv6_Register();
+    }
+}
 
-            if (!bRet)
-                DeleteFileW(pwszBuf);
-            else
-                TRACE("created %s\n", debugstr_w(pwszBuf));
-        }
+static void UnregisterControls(BOOL bV6)
+{
+    ANIMATE_Unregister ();
+    COMBOEX_Unregister ();
+    DATETIME_Unregister ();
+    FLATSB_Unregister ();
+    HEADER_Unregister ();
+    HOTKEY_Unregister ();
+    IPADDRESS_Unregister ();
+    LISTVIEW_Unregister ();
+    MONTHCAL_Unregister ();
+    NATIVEFONT_Unregister ();
+    PAGER_Unregister ();
+    PROGRESS_Unregister ();
+    REBAR_Unregister ();
+    STATUS_Unregister ();
+    SYSLINK_Unregister ();
+    TAB_Unregister ();
+    TOOLTIPS_Unregister ();
+    TRACKBAR_Unregister ();
+    TREEVIEW_Unregister ();
+    UPDOWN_Unregister ();
+
+    if (!bV6)
+    {
+        TOOLBAR_Unregister ();
     }
     else
-        bRet = DeleteFileW(pwszBuf);
+    {
+        BUTTON_Unregister();
+        COMBO_Unregister ();
+        COMBOLBOX_Unregister ();
+        EDIT_Unregister ();
+        LISTBOX_Unregister ();
+        STATIC_Unregister ();
+
+        TOOLBARv6_Unregister ();
+    }
 
-    HeapFree(GetProcessHeap(), 0, pwszBuf);
+}
+
+static void InitializeClasses()
+{
+    HANDLE hActCtx5, hActCtx6;
+    BOOL activated;
+    ULONG_PTR ulCookie;
+
+    /* like comctl32 5.82+ register all the common control classes */
+    /* Register the classes once no matter what */
+    hActCtx5 = CreateComctl32ActCtx(FALSE);
+    activated = (hActCtx5 != INVALID_HANDLE_VALUE ? ActivateActCtx(hActCtx5, &ulCookie) : FALSE);
+    RegisterControls(FALSE);      /* Register the classes pretending to be v5 */
+    if (activated) DeactivateActCtx(0, ulCookie);
+
+    hActCtx6 = CreateComctl32ActCtx(TRUE);
+    if (hActCtx6 != INVALID_HANDLE_VALUE)
+    {
+        activated = ActivateActCtx(hActCtx6, &ulCookie);
+        RegisterControls(TRUE);      /* Register the classes pretending to be v6 */
+        if (activated) DeactivateActCtx(0, ulCookie);
 
-    return bRet;
+        /* Initialize the themed controls only when the v6 manifest is present */
+        THEMING_Initialize (hActCtx5, hActCtx6);
+    }
 }
 
+static void UninitializeClasses()
+{
+    HANDLE hActCtx5, hActCtx6;
+    BOOL activated;
+    ULONG_PTR ulCookie;
+
+    hActCtx5 = CreateComctl32ActCtx(FALSE);
+    activated = (hActCtx5 != INVALID_HANDLE_VALUE ? ActivateActCtx(hActCtx5, &ulCookie) : FALSE);
+    UnregisterControls(FALSE);
+    if (activated) DeactivateActCtx(0, ulCookie);
+
+    hActCtx6 = CreateComctl32ActCtx(TRUE);
+    if (hActCtx6 != INVALID_HANDLE_VALUE)
+    {
+        activated = ActivateActCtx(hActCtx6, &ulCookie);
+        THEMING_Uninitialize();
+        UnregisterControls(TRUE);
+        if (activated) DeactivateActCtx(0, ulCookie);
+    }
+}
+
+/***********************************************************************
+ * RegisterClassNameW [COMCTL32.@]
+ *
+ * Register window class again while using as SxS module.
+ */
+BOOLEAN WINAPI RegisterClassNameW(LPCWSTR className)
+{
+    InitializeClasses();
+    return TRUE;
+}
+
+#endif /* __REACTOS__ */
+
+#ifndef __REACTOS__
+static void unregister_versioned_classes(void)
+{
+#define VERSION "6.0.2600.2982!"
+    static const char *classes[] =
+    {
+        VERSION WC_BUTTONA,
+        VERSION WC_COMBOBOXA,
+        VERSION "ComboLBox",
+        VERSION WC_EDITA,
+        VERSION WC_LISTBOXA,
+        VERSION WC_STATICA,
+    };
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(classes); i++)
+        UnregisterClassA(classes[i], NULL);
+
+#undef VERSION
+}
+#endif
 
 /***********************************************************************
  * DllMain [Internal]
@@ -203,6 +359,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
            /* Get all the colors at DLL load */
            COMCTL32_RefreshSysColors();
 
+#ifndef __REACTOS__
             /* like comctl32 5.82+ register all the common control classes */
             ANIMATE_Register ();
             COMBOEX_Register ();
@@ -226,12 +383,25 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
             TREEVIEW_Register ();
             UPDOWN_Register ();
 
+            BUTTON_Register ();
+            COMBO_Register ();
+            COMBOLBOX_Register ();
+            EDIT_Register ();
+            LISTBOX_Register ();
+            STATIC_Register ();
+
             /* subclass user32 controls */
             THEMING_Initialize ();
+#else
+            InitializeClasses();
+#endif
+
             break;
 
        case DLL_PROCESS_DETACH:
-            /* clean up subclassing */ 
+            if (lpvReserved) break;
+#ifndef __REACTOS__
+            /* clean up subclassing */
             THEMING_Uninitialize();
 
             /* unregister all common control classes */
@@ -257,16 +427,18 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
             TREEVIEW_Unregister ();
             UPDOWN_Unregister ();
 
+            unregister_versioned_classes ();
+
+#else
+            UninitializeClasses();
+#endif
             /* delete local pattern brush */
             DeleteObject (COMCTL32_hPattern55AABrush);
-            COMCTL32_hPattern55AABrush = NULL;
             DeleteObject (COMCTL32_hPattern55AABitmap);
-            COMCTL32_hPattern55AABitmap = NULL;
 
             /* delete global subclassing atom */
             GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass));
             TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass);
-            COMCTL32_wSubclass = NULL;
             break;
     }
 
@@ -334,7 +506,7 @@ MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu,
                if (uMenuID) {
                    WCHAR szText[256];
 
-                   if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0])))
+                   if (!LoadStringW (hInst, uMenuID, szText, ARRAY_SIZE(szText)))
                        szText[0] = '\0';
 
                    SendMessageW (hwndStatus, SB_SETTEXTW,
@@ -943,7 +1115,7 @@ CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
  *     Failure: 0
  *
  * NOTES
- *     Do not use this functions anymore. Use CreateToolbarEx instead.
+ *     Do not use this function anymore. Use CreateToolbarEx instead.
  */
 
 HWND WINAPI
@@ -1004,12 +1176,6 @@ HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
 {
     TRACE("(%u, %s): stub\n", bInstall, debugstr_w(cmdline));
-    if (!create_manifest(bInstall))
-    {
-        ERR("create_manifest failed!\n");
-        return HRESULT_FROM_WIN32(GetLastError());
-    }
-        
     return S_OK;
 }
 
@@ -1100,6 +1266,9 @@ BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
 
    TRACE ("(%p, %p, %lx, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef);
 
+    if (!hWnd || !pfnSubclass)
+        return FALSE;
+
    /* Since the window procedure that we set here has two additional arguments,
     * we can't simply set it as the new window procedure of the window. So we
     * set our own window procedure and then calculate the other two arguments
@@ -1166,7 +1335,7 @@ BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
  * Gets the Reference data from a subclass.
  *
  * PARAMS
- *     hWnd [in] Handle to window which were subclassing
+ *     hWnd [in] Handle to the window which we are subclassing
  *     pfnSubclass [in] Pointer to the subclass procedure
  *     uID [in] Unique identifier of the subclassing procedure
  *     pdwRef [out] Pointer to the reference data
@@ -1209,7 +1378,7 @@ BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass,
  * Removes a window subclass.
  *
  * PARAMS
- *     hWnd [in] Handle to the window were subclassing
+ *     hWnd [in] Handle to the window which we are subclassing
  *     pfnSubclass [in] Pointer to the subclass procedure
  *     uID [in] Unique identifier of this subclass
  *
@@ -1483,7 +1652,7 @@ void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark
         {lCentre + 1, l2 - 3},
     };
     hOldPen = SelectObject(hDC, hPen);
-    PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0]));
+    PolyPolyline(hDC, aptInsertMark, adwPolyPoints, ARRAY_SIZE(adwPolyPoints));
     SelectObject(hDC, hOldPen);
     DeleteObject(hPen);
 }
@@ -1574,7 +1743,7 @@ void COMCTL32_GetFontMetrics(HFONT hFont, TEXTMETRICW *ptm)
  * identifies them.
  *
  * Some of the codes are in the CCM_FIRST..CCM_LAST range, but there is no
- * colision with defined CCM_ codes.
+ * collision with defined CCM_ codes.
  */
 BOOL COMCTL32_IsReflectedMessage(UINT uMsg)
 {
@@ -1623,7 +1792,7 @@ BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
     return FALSE;
 }
 
-static inline int IsDelimiter(WCHAR c)
+static inline BOOL IsDelimiter(WCHAR c)
 {
     switch(c)
     {
@@ -1766,8 +1935,7 @@ int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD d
     bf.BlendFlags = 0;
     bf.SourceConstantAlpha = 255;
     bf.AlphaFormat = AC_SRC_ALPHA;
-    if (!GdiAlphaBlend(hdc, prc->left + ixOffset, prc->top + iyOffset, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, hdcMem, 0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, bf))
-        ERR("GdiAlphaBlend failed: %lu\n", GetLastError());
+    GdiAlphaBlend(hdc, prc->left + ixOffset, prc->top + iyOffset, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, hdcMem, 0, 0, bi.bmiHeader.biWidth, bi.bmiHeader.biHeight, bf);
 
     /* Delete the helper bitmap */
     SelectObject(hdcMem, hbmOld);
@@ -1784,52 +1952,49 @@ int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD d
 }
 
 /***********************************************************************
- * TaskDialogIndirect [COMCTL32.@]
+ * LoadIconWithScaleDown [COMCTL32.@]
  */
-HRESULT WINAPI TaskDialogIndirect(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton,
-                                  int *pnRadioButton, BOOL *pfVerificationFlagChecked)
+HRESULT WINAPI LoadIconWithScaleDown(HINSTANCE hinst, const WCHAR *name, int cx, int cy, HICON *icon)
 {
-    UINT uType = 0;
-    INT  ret;
-    FIXME("%p, %p, %p, %p\n", pTaskConfig, pnButton, pnRadioButton, pfVerificationFlagChecked);
-
-    if (pTaskConfig->dwCommonButtons & TDCBF_YES_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_NO_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
-        uType |= MB_YESNOCANCEL;
-    else
-    if (pTaskConfig->dwCommonButtons & TDCBF_YES_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_NO_BUTTON)
-        uType |= MB_YESNO;
-    else
-    if (pTaskConfig->dwCommonButtons & TDCBF_RETRY_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
-        uType |= MB_RETRYCANCEL;
-    else
-    if (pTaskConfig->dwCommonButtons & TDCBF_OK_BUTTON &&
-        pTaskConfig->dwCommonButtons & TDCBF_CANCEL_BUTTON)
-        uType |= MB_OKCANCEL;
-    else
-    if (pTaskConfig->dwCommonButtons & TDCBF_OK_BUTTON)
-        uType |= MB_OK;
-    ret = MessageBoxW(pTaskConfig->hwndParent, pTaskConfig->pszMainInstruction,
-                      pTaskConfig->pszWindowTitle, uType);
-    FIXME("dwCommonButtons=%x uType=%x ret=%x\n", pTaskConfig->dwCommonButtons, uType, ret);
-
-    if (pnButton) *pnButton = ret;
-    if (pnRadioButton) *pnRadioButton = pTaskConfig->nDefaultButton;
-    if (pfVerificationFlagChecked) *pfVerificationFlagChecked = TRUE;
+    TRACE("(%p, %s, %d, %d, %p)\n", hinst, debugstr_w(name), cx, cy, icon);
+
+    *icon = NULL;
+
+    if (!name)
+        return E_INVALIDARG;
+
+    *icon = LoadImageW(hinst, name, IMAGE_ICON, cx, cy,
+                       (hinst || IS_INTRESOURCE(name)) ? 0 : LR_LOADFROMFILE);
+    if (!*icon)
+        return HRESULT_FROM_WIN32(GetLastError());
+
     return S_OK;
 }
 
 /***********************************************************************
- * RegisterClassNameW [COMCTL32.@]
- *
- * Register window class again while using as SxS module.
+ * LoadIconMetric [COMCTL32.@]
  */
-BOOLEAN WINAPI RegisterClassNameW(LPCWSTR className)
+HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
 {
-    /* FIXME: actually register redirected user32 class,
-              comctl32 classes are registered by this module anyway */
-    return TRUE;
+    int cx, cy;
+
+    TRACE("(%p, %s, %d, %p)\n", hinst, debugstr_w(name), size, icon);
+
+    if (size == LIM_SMALL)
+    {
+        cx = GetSystemMetrics(SM_CXSMICON);
+        cy = GetSystemMetrics(SM_CYSMICON);
+    }
+    else if (size == LIM_LARGE)
+    {
+        cx = GetSystemMetrics(SM_CXICON);
+        cy = GetSystemMetrics(SM_CYICON);
+    }
+    else
+    {
+        *icon = NULL;
+        return E_INVALIDARG;
+    }
+
+    return LoadIconWithScaleDown(hinst, name, cx, cy, icon);
 }