[COMCTL32] Install comctl32 v6 and its manifest in first stage
[reactos.git] / dll / win32 / comctl32 / commctrl.c
index a82b233..df063c0 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
  *   -- ICC_WIN95_CLASSES
  */
 
-#include <stdarg.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "winnls.h"
-#include "commctrl.h"
-#include "winerror.h"
-#include "winreg.h"
-#define NO_SHLWAPI_STREAM
-#include "shlwapi.h"
 #include "comctl32.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
-
 
-#define NAME       "microsoft.windows.common-controls"
-#define FILE       "comctl32.dll"
-#define VERSION    "6.0.2600.2982"
-#define PUBLIC_KEY "6595b64144ccf1df"
+#define NO_SHLWAPI_STREAM
+#include <shlwapi.h>
 
-#ifdef __i386__
-#define ARCH "x86"
-#elif defined __x86_64__
-#define ARCH "amd64"
-#else
-#define ARCH "none"
-#endif
+WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
 
-static const char manifest[] =
-    "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
-    "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"
-    "  <assemblyIdentity type=\"win32\" name=\"" NAME "\" version=\"" VERSION "\" processorArchitecture=\"" ARCH "\" publicKeyToken=\"" PUBLIC_KEY "\"/>\n"
-    "  <file name=\"" FILE "\">\n"
-    "    <windowClass>Button</windowClass>\n"
-    "    <windowClass>ButtonListBox</windowClass>\n"
-    "    <windowClass>ComboBoxEx32</windowClass>\n"
-    "    <windowClass>ComboLBox</windowClass>\n"
-    "    <windowClass>Combobox</windowClass>\n"
-    "    <windowClass>Edit</windowClass>\n"
-    "    <windowClass>Listbox</windowClass>\n"
-    "    <windowClass>NativeFontCtl</windowClass>\n"
-    "    <windowClass>ReBarWindow32</windowClass>\n"
-    "    <windowClass>ScrollBar</windowClass>\n"
-    "    <windowClass>Static</windowClass>\n"
-    "    <windowClass>SysAnimate32</windowClass>\n"
-    "    <windowClass>SysDateTimePick32</windowClass>\n"
-    "    <windowClass>SysHeader32</windowClass>\n"
-    "    <windowClass>SysIPAddress32</windowClass>\n"
-    "    <windowClass>SysLink</windowClass>\n"
-    "    <windowClass>SysListView32</windowClass>\n"
-    "    <windowClass>SysMonthCal32</windowClass>\n"
-    "    <windowClass>SysPager</windowClass>\n"
-    "    <windowClass>SysTabControl32</windowClass>\n"
-    "    <windowClass>SysTreeView32</windowClass>\n"
-    "    <windowClass>ToolbarWindow32</windowClass>\n"
-    "    <windowClass>msctls_hotkey32</windowClass>\n"
-    "    <windowClass>msctls_progress32</windowClass>\n"
-    "    <windowClass>msctls_statusbar32</windowClass>\n"
-    "    <windowClass>msctls_trackbar32</windowClass>\n"
-    "    <windowClass>msctls_updown32</windowClass>\n"
-    "    <windowClass>tooltips_class32</windowClass>\n"
-    "  </file>\n"
-    "</assembly>\n";
-
-static const char manifest_filename[] = ARCH "_" NAME "_" PUBLIC_KEY "_" VERSION "_none_deadbeef.manifest";
 
 static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 
@@ -143,46 +81,201 @@ 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 )
+#ifdef __REACTOS__
+
+#include <strsafe.h>
+
+#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"
+
+#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)
 {
-    static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s',0};
-    static const WCHAR manifestsW[] = {'\\','m','a','n','i','f','e','s','t','s','\\',0};
-
-    DWORD len, written;
-    WCHAR *buffer;
-    HANDLE file;
-    BOOL ret = FALSE;
-
-    len = MultiByteToWideChar( CP_UTF8, 0, manifest_filename, sizeof(manifest_filename), NULL, 0 );
-    len += GetWindowsDirectoryW( NULL, 0 );
-    len += lstrlenW(winsxsW);
-    len += lstrlenW(manifestsW);
-    if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
-    GetWindowsDirectoryW( buffer, len );
-    lstrcatW( buffer, winsxsW );
-    CreateDirectoryW( buffer, NULL );
-    lstrcatW( buffer, manifestsW );
-    CreateDirectoryW( buffer, NULL );
-    MultiByteToWideChar( CP_UTF8, 0, manifest_filename, sizeof(manifest_filename),
-                         buffer + lstrlenW(buffer), len );
-    if (install)
+    WCHAR *pwszBuf;
+    HRESULT hres;
+
+    pwszBuf = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
+    if (!pwszBuf)
+        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)};
+
+    pwstrSource = GetManifestPath(FALSE, bV6);
+    if (!pwstrSource)
     {
-        file = CreateFileW( buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
-        if (file != INVALID_HANDLE_VALUE)
-        {
-            ret = (WriteFile( file, manifest, sizeof(manifest)-1, &written, NULL ) &&
-                   written == sizeof(manifest)-1);
-            CloseHandle( file );
-            if (!ret) DeleteFileW( buffer );
-            else TRACE("created %s\n", debugstr_w(buffer));
-        }
+        ERR("GetManifestPath failed! bV6=%d\n", bV6);
+        return INVALID_HANDLE_VALUE;
     }
-    else ret = DeleteFileW( buffer );
-
-    HeapFree( GetProcessHeap(), 0, buffer );
+    ActCtx.lpSource = pwstrSource;
+    ret = CreateActCtxW(&ActCtx);
+    HeapFree(GetProcessHeap(), 0, pwstrSource);
+    if (ret == INVALID_HANDLE_VALUE)
+        ERR("CreateActCtxW failed! bV6=%d\n", bV6);
     return ret;
 }
 
+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();
+        TOOLBARv6_Register();
+    }
+}
+
+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
+    {
+        BUTTON_Unregister();
+        TOOLBARv6_Unregister ();
+    }
+
+}
+
+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);
+
+        /* 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
 
 /***********************************************************************
  * DllMain [Internal]
@@ -192,7 +285,7 @@ static BOOL create_manifest( BOOL install )
  * PARAMS
  *     hinstDLL    [I] handle to the 'dlls' instance
  *     fdwReason   [I]
- *     lpvReserved [I] reserverd, must be NULL
+ *     lpvReserved [I] reserved, must be NULL
  *
  * RETURNS
  *     Success: TRUE
@@ -220,6 +313,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 ();
@@ -245,10 +339,16 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 
             /* 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 */
@@ -273,17 +373,16 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
             TRACKBAR_Unregister ();
             TREEVIEW_Unregister ();
             UPDOWN_Unregister ();
-
+#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;
     }
 
@@ -701,7 +800,7 @@ CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy,
  *
  * NOTES
  *     This function is just a dummy - all the controls are registered at
- *     the DLL's initialization. See InitCommonContolsEx for details.
+ *     the DLL initialization time. See InitCommonContolsEx for details.
  */
 
 VOID WINAPI
@@ -887,7 +986,10 @@ CreateMappedBitmap (HINSTANCE hInstance, INT_PTR idBitmap, UINT wFlags,
         nColorTableSize = (1 << lpBitmap->biBitCount);
     else
         nColorTableSize = 0;
-    nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
+    nSize = lpBitmap->biSize;
+    if (nSize == sizeof(BITMAPINFOHEADER) && lpBitmap->biCompression == BI_BITFIELDS)
+        nSize += 3 * sizeof(DWORD);
+    nSize += nColorTableSize * sizeof(RGBQUAD);
     lpBitmapInfo = GlobalAlloc (GMEM_FIXED, nSize);
     if (lpBitmapInfo == NULL)
        return 0;
@@ -957,7 +1059,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
@@ -1018,7 +1120,7 @@ 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 )) return HRESULT_FROM_WIN32(GetLastError());
+
     return S_OK;
 }
 
@@ -1088,7 +1190,7 @@ VOID WINAPI InitMUILanguage (LANGID uiLang)
  * PARAMS
  *     hWnd [in] handle to window subclass.
  *     pfnSubclass [in] Pointer to new window procedure.
- *     uIDSubclass [in] Unique identifier of sublass together with pfnSubclass.
+ *     uIDSubclass [in] Unique identifier of subclass together with pfnSubclass.
  *     dwRef [in] Reference data to pass to window procedure.
  *
  * RETURNS
@@ -1175,9 +1277,9 @@ 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 indentifier of the subclassing procedure
+ *     uID [in] Unique identifier of the subclassing procedure
  *     pdwRef [out] Pointer to the reference data
  *
  * RETURNS
@@ -1218,7 +1320,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
  *
@@ -1320,7 +1422,7 @@ static LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam
 /***********************************************************************
  * DefSubclassProc [COMCTL32.413]
  *
- * Calls the next window procedure (ie. the one before this subclass)
+ * Calls the next window procedure (i.e. the one before this subclass)
  *
  * PARAMS
  *     hWnd [in] The window that we're subclassing
@@ -1583,7 +1685,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)
 {
@@ -1632,7 +1734,7 @@ BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2)
     return FALSE;
 }
 
-static inline int IsDelimiter(WCHAR c)
+static inline BOOL IsDelimiter(WCHAR c)
 {
     switch(c)
     {
@@ -1682,24 +1784,159 @@ LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet)
  *
  * Draw text with shadow.
  */
-int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *rect, DWORD dwFlags,
+int WINAPI DrawShadowText(HDC hdc, LPCWSTR pszText, UINT cch, RECT *prc, DWORD dwFlags,
                           COLORREF crText, COLORREF crShadow, int ixOffset, int iyOffset)
 {
-    FIXME("(%p, %s, %d, %p, %d, 0x%08x, 0x%08x, %d, %d): stub\n", hdc, debugstr_w(pszText), cch, rect, dwFlags,
-                                                                  crText, crShadow, ixOffset, iyOffset);
-    return DrawTextW(hdc, pszText, cch, rect, DT_LEFT);
+    COLORREF crOldText;
+    RECT rcText;
+    INT iRet, x, y, x2, y2;
+    BYTE *pBits;
+    HBITMAP hbm, hbmOld;
+    BITMAPINFO bi;
+    HDC hdcMem;
+    HFONT hOldFont;
+    BLENDFUNCTION bf;
+
+    /* Create 32 bit DIB section for the shadow */
+    ZeroMemory(&bi, sizeof(bi));
+    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
+    bi.bmiHeader.biWidth = prc->right - prc->left + 4;
+    bi.bmiHeader.biHeight = prc->bottom - prc->top + 5; // bottom-up DIB
+    bi.bmiHeader.biPlanes = 1;
+    bi.bmiHeader.biBitCount = 32;
+    bi.bmiHeader.biCompression = BI_RGB;
+    hbm = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS, (PVOID*)&pBits, NULL, 0);
+    if(!hbm)
+    {
+        ERR("CreateDIBSection failed\n");
+        return 0;
+    }
+
+    /* Create memory device context for new DIB section and select it */
+    hdcMem = CreateCompatibleDC(hdc);
+    if(!hdcMem)
+    {
+        ERR("CreateCompatibleDC failed\n");
+        DeleteObject(hbm);
+        return 0;
+    }
+
+    hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
+
+    /* Draw text on our helper bitmap */
+    hOldFont = (HFONT)SelectObject(hdcMem, GetCurrentObject(hdc, OBJ_FONT));
+    SetTextColor(hdcMem, RGB(16, 16, 16));
+    SetBkColor(hdcMem, RGB(0, 0, 0));
+    SetBkMode(hdcMem, TRANSPARENT);
+    SetRect(&rcText, 0, 0, prc->right - prc->left, prc->bottom - prc->top);
+    DrawTextW(hdcMem, pszText, cch, &rcText, dwFlags);
+    SelectObject(hdcMem, hOldFont);
+
+    /* Flush GDI so data pointed by pBits is valid */
+    GdiFlush();
+
+    /* Set alpha of pixels (forget about colors for now. They will be changed in next loop).
+       We copy text image 4*5 times and each time alpha is added */
+    for (x = 0; x < bi.bmiHeader.biWidth; ++x)
+        for (y = 0; y < bi.bmiHeader.biHeight; ++y)
+        {
+            BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4];
+            UINT Alpha = 0;
+
+            for (x2 = x - 4 + 1; x2 <= x; ++x2)
+                for (y2 = y; y2 < y + 5; ++y2)
+                {
+                    if (x2 >= 0 && x2 < bi.bmiHeader.biWidth && y2 >= 0 && y2 < bi.bmiHeader.biHeight)
+                    {
+                        BYTE *pSrc = &pBits[(y2 * bi.bmiHeader.biWidth + x2) * 4];
+                        Alpha += pSrc[0];
+                    }
+                }
+
+            if (Alpha > 255)
+                Alpha = 255;
+            pDest[3] = Alpha;
+        }
+
+    /* Now set the color of each pixel to shadow color * alpha (see GdiAlphaBlend) */
+    for (x = 0; x < bi.bmiHeader.biWidth; ++x)
+        for (y = 0; y < bi.bmiHeader.biHeight; ++y)
+        {
+            BYTE *pDest = &pBits[(y * bi.bmiHeader.biWidth + x) * 4];
+            pDest[0] = GetBValue(crShadow) * pDest[3] / 255;
+            pDest[1] = GetGValue(crShadow) * pDest[3] / 255;
+            pDest[2] = GetRValue(crShadow) * pDest[3] / 255;
+        }
+
+    /* Fix ixOffset of the shadow (tested on Win) */
+    ixOffset -= 3;
+    iyOffset -= 3;
+
+    /* Alpha blend helper image to destination DC */
+    bf.BlendOp = AC_SRC_OVER;
+    bf.BlendFlags = 0;
+    bf.SourceConstantAlpha = 255;
+    bf.AlphaFormat = AC_SRC_ALPHA;
+    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);
+    DeleteObject(hbm);
+    DeleteDC(hdcMem);
+
+    /* Finally draw the text over shadow */
+    crOldText = SetTextColor(hdc, crText);
+    SetBkMode(hdc, TRANSPARENT);
+    iRet = DrawTextW(hdc, pszText, cch, prc, dwFlags);
+    SetTextColor(hdc, crOldText);
+
+    return iRet;
 }
 
 /***********************************************************************
- * 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)
 {
-    FIXME("%p, %p, %p, %p\n", pTaskConfig, pnButton, pnRadioButton, pfVerificationFlagChecked);
+    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());
 
-    if (pnButton) *pnButton = IDYES;
-    if (pnRadioButton) *pnRadioButton = pTaskConfig->nDefaultButton;
-    if (pfVerificationFlagChecked) *pfVerificationFlagChecked = TRUE;
     return S_OK;
 }
+
+/***********************************************************************
+ * LoadIconMetric [COMCTL32.@]
+ */
+HRESULT WINAPI LoadIconMetric(HINSTANCE hinst, const WCHAR *name, int size, HICON *icon)
+{
+    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);
+}