Sync with trunk r63430.
authorDavid Quintana <gigaherz@gmail.com>
Sat, 24 May 2014 20:29:19 +0000 (20:29 +0000)
committerDavid Quintana <gigaherz@gmail.com>
Sat, 24 May 2014 20:29:19 +0000 (20:29 +0000)
svn path=/branches/shell-experiments/; revision=63433

136 files changed:
1  2 
base/applications/cacls/lang/ru-RU.rc
base/applications/dxdiag/lang/ru-RU.rc
base/applications/fontview/lang/ru-RU.rc
base/applications/magnify/magnifier.c
base/applications/mplay32/lang/ru-RU.rc
base/applications/regedit/lang/ru-RU.rc
base/applications/shutdown/lang/ru-RU.rc
base/applications/sndrec32/lang/ru-RU.rc
base/applications/sndrec32/rsrc.rc
base/applications/sndvol32/lang/ru-RU.rc
base/setup/reactos/lang/ru-RU.rc
base/setup/usetup/bootsup.c
base/setup/usetup/errorcode.h
base/setup/usetup/interface/usetup.c
base/setup/usetup/lang/bg-BG.h
base/setup/usetup/lang/cs-CZ.h
base/setup/usetup/lang/de-DE.h
base/setup/usetup/lang/el-GR.h
base/setup/usetup/lang/en-US.h
base/setup/usetup/lang/es-ES.h
base/setup/usetup/lang/et-EE.h
base/setup/usetup/lang/fr-FR.h
base/setup/usetup/lang/he-IL.h
base/setup/usetup/lang/it-IT.h
base/setup/usetup/lang/ja-JP.h
base/setup/usetup/lang/lt-LT.h
base/setup/usetup/lang/nl-NL.h
base/setup/usetup/lang/pl-PL.h
base/setup/usetup/lang/pt-BR.h
base/setup/usetup/lang/ro-RO.h
base/setup/usetup/lang/ru-RU.h
base/setup/usetup/lang/sk-SK.h
base/setup/usetup/lang/sq-AL.h
base/setup/usetup/lang/sv-SE.h
base/setup/usetup/lang/tr-TR.h
base/setup/usetup/lang/uk-UA.h
base/setup/usetup/mui.h
base/setup/usetup/partlist.c
base/setup/usetup/partlist.h
base/setup/usetup/usetup.h
base/shell/explorer-new/lang/ru-RU.rc
boot/bootdata/hivesys.inf
boot/bootdata/packages/reactos.dff.in
boot/bootdata/txtsetup.sif
dll/cpl/desk/lang/ru-RU.rc
dll/cpl/mmsys/lang/ru-RU.rc
dll/cpl/wined3dcfg/general.c
dll/cpl/wined3dcfg/lang/cs-CZ.rc
dll/cpl/wined3dcfg/lang/de-DE.rc
dll/cpl/wined3dcfg/lang/en-US.rc
dll/cpl/wined3dcfg/lang/he-IL.rc
dll/cpl/wined3dcfg/lang/pl-PL.rc
dll/cpl/wined3dcfg/lang/ro-RO.rc
dll/cpl/wined3dcfg/lang/sq-AL.rc
dll/cpl/wined3dcfg/lang/tr-TR.rc
dll/cpl/wined3dcfg/resource.h
dll/cpl/wined3dcfg/wined3dcfg.h
dll/directx/ddraw/Ddraw/GetCaps.c
dll/win32/aclui/lang/ru-RU.rc
dll/win32/browseui/browseui.rc
dll/win32/browseui/lang/ru-RU.rc
dll/win32/kernel32/client/proc.c
dll/win32/kernel32/client/vdm.c
dll/win32/msvcrt/msvcrt.spec
dll/win32/shell32/classes.cpp
dll/win32/shell32/defcontextmenu.cpp
dll/win32/shell32/shell32_main.cpp
dll/win32/shell32/shell32_main.h
dll/win32/shell32/shellpath.cpp
dll/win32/shell32/shlexec.cpp
drivers/bus/acpi/busmgr/bus.c
drivers/bus/acpi/buspdo.c
drivers/bus/acpi/include/acpi_bus.h
drivers/bus/acpi/include/acpisys.h
drivers/input/i8042prt/pnp.c
drivers/input/kbdclass/kbdclass.c
drivers/input/mouclass/mouclass.c
drivers/network/ndis/ndis/miniport.c
include/asm/ks386.template.h
lib/sdk/crt/stdio/file.c
lib/sdk/crt/stdlib/mbtowc.c
lib/sdk/crt/string/ctype.c
ntoskrnl/ex/init.c
ntoskrnl/include/internal/amd64/mm.h
ntoskrnl/include/internal/i386/asmmacro.S
ntoskrnl/io/iomgr/driver.c
ntoskrnl/io/pnpmgr/pnpinit.c
ntoskrnl/io/pnpmgr/pnpmgr.c
ntoskrnl/kd64/kdinit.c
ntoskrnl/ke/i386/trap.s
ntoskrnl/ke/i386/traphdlr.c
ntoskrnl/mm/ARM3/miarm.h
ntoskrnl/mm/ARM3/pagfault.c
ntoskrnl/mm/ARM3/section.c
ntoskrnl/mm/ARM3/sysldr.c
ntoskrnl/mm/ARM3/virtual.c
ntoskrnl/mm/marea.c
subsystems/ntvdm/bios/bios.c
subsystems/ntvdm/bios/bios.h
subsystems/ntvdm/bios/bios32/bios32.c
subsystems/ntvdm/bios/bios32/bios32p.h
subsystems/ntvdm/bop.c
subsystems/ntvdm/callback.c
subsystems/ntvdm/callback.h
subsystems/ntvdm/dos/dem.c
subsystems/ntvdm/dos/dos32krnl/dos.c
subsystems/ntvdm/hardware/vga.c
subsystems/ntvdm/ntvdm.c
win32ss/drivers/font/bmfd/glyph.c
win32ss/gdi/dib/stretchblt.c
win32ss/gdi/eng/driverobj.c
win32ss/gdi/eng/driverobj.h
win32ss/gdi/eng/surface.c
win32ss/gdi/eng/surface.h
win32ss/gdi/ntgdi/brush.c
win32ss/gdi/ntgdi/brush.h
win32ss/gdi/ntgdi/dc.h
win32ss/gdi/ntgdi/dclife.c
win32ss/gdi/ntgdi/gdiobj.c
win32ss/gdi/ntgdi/gdiobj.h
win32ss/gdi/ntgdi/palette.c
win32ss/gdi/ntgdi/palette.h
win32ss/gdi/ntgdi/region.c
win32ss/gdi/ntgdi/region.h
win32ss/include/callback.h
win32ss/user/ntuser/callback.c
win32ss/user/ntuser/desktop.c
win32ss/user/ntuser/desktop.h
win32ss/user/ntuser/window.c
win32ss/user/ntuser/winsta.c
win32ss/user/user32/misc/dde.c
win32ss/user/user32/misc/ddeclient.c
win32ss/user/user32/misc/ddeserver.c
win32ss/user/user32/windows/mdi.c
win32ss/user/user32/windows/menu.c
win32ss/user/user32/windows/message.c

Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0c1b221,0000000..94a6597
mode 100644,000000..100644
--- /dev/null
@@@ -1,107 -1,0 +1,110 @@@
 +/*
 + * Top level resource file for browseui stuff
 + *
 + * Copyright 2009 Andrew Hill
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 + */
 +
 +#define WIN32_NO_STATUS
 +#define _INC_WINDOWS
 +#define COM_NO_WINDOWS_H
 +#include <shlobj.h>
 +
 +#include "resource.h"
 +
 +#include "version.rc"
 +
 +LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 +
 +/* REGISTRY */
 +IDR_ADDRESSBAND REGISTRY "res/addressband.rgs"
 +IDR_ADDRESSEDITBOX REGISTRY "res/addresseditbox.rgs"
 +IDR_ACLMULTI REGISTRY "res/autocompletecontainer.rgs"
 +IDR_BANDPROXY REGISTRY "res/bandproxy.rgs"
 +IDR_BANDSITE REGISTRY "res/rebarbandsite.rgs"
 +IDR_BANDSITEMENU REGISTRY "res/bandsitemenu.rgs"
 +IDR_BRANDBAND REGISTRY "res/brandband.rgs"
 +IDR_COMMONBROWSER REGISTRY "res/commonbrowser.rgs"
 +IDR_GLOBALFOLDERSETTINGS REGISTRY "res/globalfoldersettings.rgs"
 +IDR_INTERNETTOOLBAR REGISTRY "res/internettoolbar.rgs"
 +IDR_REGTREEOPTIONS REGISTRY "res/regtreeoptions.rgs"
 +
 +/*
 + * Everything specific to any language goes
 + * in one of the specific files.
 + */
 +//#include "lang/ca-ES.rc"
 +//#include "lang/cs-CZ.rc"
 +//#include "lang/da-DK.rc"
 +//#include "lang/el-GR.rc"
 +//#include "lang/en-GB.rc"
 +//#include "lang/fi-FI.rc"
 +//#include "lang/fr-FR.rc"
 +//#include "lang/he-IL.rc"
 +//#include "lang/hu-HU.rc"
 +//#include "lang/it-IT.rc"
 +//#include "lang/ja-JP.rc"
 +//#include "lang/ko-KR.rc"
 +//#include "lang/nl-NL.rc"
 +//#include "lang/no-NO.rc"
 +//#include "lang/pt-BR.rc"
 +//#include "lang/pt-PT.rc"
 +//#include "lang/ru-RU.rc"
 +//#include "lang/sl-SI.rc"
 +//#include "lang/sk-SK.rc"
 +//#include "lang/sv-SE.rc"
 +//#include "lang/zh-CN.rc"
 +//#include "lang/zh-TW.rc"
 +
 +/* UTF-8 */
 +#pragma code_page(65001)
 +
 +#ifdef LANGUAGE_BG_BG
 +    #include "lang/bg-BG.rc"
 +#endif
 +#ifdef LANGUAGE_DE_DE
 +    #include "lang/de-DE.rc"
 +#endif
 +#ifdef LANGUAGE_EN_US
 +    #include "lang/en-US.rc"
 +#endif
 +#ifdef LANGUAGE_ES_ES
 +    #include "lang/es-ES.rc"
 +#endif
 +#ifdef LANGUAGE_HE_IL
 +    #include "lang/he-IL.rc"
 +#endif
 +#ifdef LANGUAGE_IT_IT
 +    #include "lang/it-IT.rc"
 +#endif
 +#ifdef LANGUAGE_PL_PL
 +    #include "lang/pl-PL.rc"
 +#endif
 +#ifdef LANGUAGE_RO_RO
 +    #include "lang/ro-RO.rc"
 +#endif
++#ifdef LANGUAGE_RU_RU
++    #include "lang/ru-RU.rc"
++#endif
 +#ifdef LANGUAGE_TR_TR
 +    #include "lang/tr-TR.rc"
 +#endif
 +#ifdef LANGUAGE_SQ_AL
 +    #include "lang/sq-AL.rc"
 +#endif
 +#ifdef LANGUAGE_UK_UA
 +    #include "lang/uk-UA.rc"
 +#endif
index 0000000,a798508..a798508
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
index 5d96eb1,0000000..be2e8eb
mode 100644,000000..100644
--- /dev/null
@@@ -1,1684 -1,0 +1,1689 @@@
 +/*
 + * PROJECT:     shell32
 + * LICENSE:     GPL - See COPYING in the top level directory
 + * FILE:        dll/win32/shell32/shv_item_new.c
 + * PURPOSE:     provides default context menu implementation
 + * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
 + */
 +
 +/*
 +TODO:
 +    The code in NotifyShellViewWindow to deliver commands to the view is broken. It is an excellent
 +    example of the wrong way to do it.
 +*/
 +
 +#include "precomp.h"
 +
 +WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
 +
 +typedef struct _DynamicShellEntry_
 +{
 +    UINT iIdCmdFirst;
 +    UINT NumIds;
 +    CLSID ClassID;
 +    IContextMenu *pCM;
 +    struct _DynamicShellEntry_ *pNext;
 +} DynamicShellEntry, *PDynamicShellEntry;
 +
 +typedef struct _StaticShellEntry_
 +{
 +    LPWSTR szVerb;
 +    LPWSTR szClass;
 +    struct _StaticShellEntry_ *pNext;
 +} StaticShellEntry, *PStaticShellEntry;
 +
 +class CDefaultContextMenu :
 +    public CComObjectRootEx<CComMultiThreadModelNoCS>,
 +    public IContextMenu2
 +{
 +    private:
 +        DEFCONTEXTMENU m_Dcm;
 +        IDataObject *m_pDataObj;
 +        LPCITEMIDLIST m_pidlFolder;
 +        DWORD m_bGroupPolicyActive;
 +        PDynamicShellEntry m_pDynamicEntries; /* first dynamic shell extension entry */
 +        UINT m_iIdSHEFirst; /* first used id */
 +        UINT m_iIdSHELast; /* last used id */
 +        PStaticShellEntry m_pStaticEntries; /* first static shell extension entry */
 +        UINT m_iIdSCMFirst; /* first static used id */
 +        UINT m_iIdSCMLast; /* last static used id */
 +
 +        void AddStaticEntry(LPCWSTR pwszVerb, LPCWSTR pwszClass);
 +        void AddStaticEntryForKey(HKEY hKey, LPCWSTR pwszClass);
 +        void AddStaticEntryForFileClass(LPCWSTR pwszExt);
 +        BOOL IsShellExtensionAlreadyLoaded(const CLSID *pclsid);
 +        HRESULT LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid);
 +        BOOL EnumerateDynamicContextHandlerForKey(HKEY hRootKey);
 +        UINT InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT IndexMenu, UINT idCmdFirst, UINT idCmdLast);
 +        UINT BuildBackgroundContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
 +        UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT IndexMenu);
 +        UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
 +        HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink);
 +        HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi);
 +        HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi);
 +        HRESULT DoRefresh(LPCMINVOKECOMMANDINFO lpcmi);
 +        HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi);
 +        HRESULT DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi, BOOL bCopy);
 +        HRESULT DoRename(LPCMINVOKECOMMANDINFO lpcmi);
 +        HRESULT DoProperties(LPCMINVOKECOMMANDINFO lpcmi);
 +        HRESULT DoFormat(LPCMINVOKECOMMANDINFO lpcmi);
 +        HRESULT DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
 +        HRESULT DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
 +        DWORD BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry);
 +        HRESULT TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags);
 +        HRESULT InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry);
 +
 +    public:
 +        CDefaultContextMenu();
 +        ~CDefaultContextMenu();
 +        HRESULT WINAPI Initialize(const DEFCONTEXTMENU *pdcm);
 +
 +        // IContextMenu
 +        virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
 +        virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
 +        virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen);
 +
 +        // IContextMenu2
 +        virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
 +
 +        BEGIN_COM_MAP(CDefaultContextMenu)
 +        COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
 +        COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
 +        END_COM_MAP()
 +};
 +
 +CDefaultContextMenu::CDefaultContextMenu()
 +{
 +    memset(&m_Dcm, 0, sizeof(m_Dcm));
 +    m_pDataObj = NULL;
 +    m_pidlFolder = NULL;
 +    m_bGroupPolicyActive = 0;
 +    m_pDynamicEntries = NULL;
 +    m_iIdSHEFirst = 0;
 +    m_iIdSHELast = 0;
 +    m_pStaticEntries = NULL;
 +    m_iIdSCMFirst = 0;
 +    m_iIdSCMLast = 0;
 +}
 +
 +CDefaultContextMenu::~CDefaultContextMenu()
 +{
 +    /* Free dynamic shell extension entries */
 +    PDynamicShellEntry pDynamicEntry = m_pDynamicEntries, pNextDynamic;
 +    while (pDynamicEntry)
 +    {
 +        pNextDynamic = pDynamicEntry->pNext;
 +        pDynamicEntry->pCM->Release();
 +        HeapFree(GetProcessHeap(), 0, pDynamicEntry);
 +        pDynamicEntry = pNextDynamic;
 +    }
 +
 +    /* Free static shell extension entries */
 +    PStaticShellEntry pStaticEntry = m_pStaticEntries, pNextStatic;
 +    while (pStaticEntry)
 +    {
 +        pNextStatic = pStaticEntry->pNext;
 +        HeapFree(GetProcessHeap(), 0, pStaticEntry->szClass);
 +        HeapFree(GetProcessHeap(), 0, pStaticEntry->szVerb);
 +        HeapFree(GetProcessHeap(), 0, pStaticEntry);
 +        pStaticEntry = pNextStatic;
 +    }
 +
 +    if (m_pidlFolder)
 +        ILFree((_ITEMIDLIST*)m_pidlFolder);
 +    if (m_pDataObj)
 +        m_pDataObj->Release();
 +}
 +
 +HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm)
 +{
 +    IDataObject *pDataObj;
 +
 +    TRACE("cidl %u\n", pdcm->cidl);
 +    if (SUCCEEDED(SHCreateDataObject(pdcm->pidlFolder, pdcm->cidl, pdcm->apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
 +        m_pDataObj = pDataObj;
 +
 +    if (!pdcm->cidl)
 +    {
 +        /* Init pidlFolder only if it is background context menu. See IShellExtInit::Initialize */
 +        if (pdcm->pidlFolder)
 +            m_pidlFolder = ILClone(pdcm->pidlFolder);
 +        else
 +        {
 +            IPersistFolder2 *pf = NULL;
 +            if (SUCCEEDED(pdcm->psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pf))))
 +            {
 +                if (FAILED(pf->GetCurFolder((_ITEMIDLIST**)&m_pidlFolder)))
 +                    ERR("GetCurFolder failed\n");
 +                pf->Release();
 +            }
 +        }
 +        TRACE("pidlFolder %p\n", m_pidlFolder);
 +    }
 +
 +    CopyMemory(&m_Dcm, pdcm, sizeof(DEFCONTEXTMENU));
 +    return S_OK;
 +}
 +
 +void
 +CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass)
 +{
 +    PStaticShellEntry pEntry = m_pStaticEntries, pLastEntry = NULL;
 +    while(pEntry)
 +    {
 +        if (!wcsicmp(pEntry->szVerb, szVerb))
 +        {
 +            /* entry already exists */
 +            return;
 +        }
 +        pLastEntry = pEntry;
 +        pEntry = pEntry->pNext;
 +    }
 +
 +    TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb), debugstr_w(szClass));
 +
 +    pEntry = (StaticShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry));
 +    if (pEntry)
 +    {
 +        pEntry->pNext = NULL;
 +        pEntry->szVerb = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb) + 1) * sizeof(WCHAR));
 +        if (pEntry->szVerb)
 +            wcscpy(pEntry->szVerb, szVerb);
 +        pEntry->szClass = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass) + 1) * sizeof(WCHAR));
 +        if (pEntry->szClass)
 +            wcscpy(pEntry->szClass, szClass);
 +    }
 +
 +    if (!wcsicmp(szVerb, L"open"))
 +    {
 +        /* open verb is always inserted in front */
 +        pEntry->pNext = m_pStaticEntries;
 +        m_pStaticEntries = pEntry;
 +    }
 +    else if (pLastEntry)
 +        pLastEntry->pNext = pEntry;
 +    else
 +        m_pStaticEntries = pEntry;
 +}
 +
 +void
 +CDefaultContextMenu::AddStaticEntryForKey(HKEY hKey, const WCHAR *pwszClass)
 +{
 +    WCHAR wszName[40];
 +    DWORD cchName, dwIndex = 0;
 +
 +    TRACE("AddStaticEntryForKey %x %ls\n", hKey, pwszClass);
 +
 +    while(TRUE)
 +    {
 +        cchName = _countof(wszName);
 +        if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
 +            break;
 +
 +        AddStaticEntry(wszName, pwszClass);
 +    }
 +}
 +
 +void
 +CDefaultContextMenu::AddStaticEntryForFileClass(const WCHAR * szExt)
 +{
 +    WCHAR szBuffer[100];
 +    HKEY hKey;
 +    LONG result;
 +    DWORD dwBuffer;
 +    UINT Length;
 +    static WCHAR szShell[] = L"\\shell";
 +    static WCHAR szShellAssoc[] = L"SystemFileAssociations\\";
 +
 +    TRACE("AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt));
 +
 +    Length = wcslen(szExt);
 +    if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
 +    {
 +        wcscpy(szBuffer, szExt);
 +        wcscpy(&szBuffer[Length], szShell);
 +        result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
 +        if (result == ERROR_SUCCESS)
 +        {
 +            szBuffer[Length] = 0;
 +            AddStaticEntryForKey(hKey, szExt);
 +            RegCloseKey(hKey);
 +        }
 +    }
 +
 +    dwBuffer = sizeof(szBuffer);
 +    result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, (LPBYTE)szBuffer, &dwBuffer);
 +    if (result == ERROR_SUCCESS)
 +    {
 +        Length = wcslen(szBuffer);
 +        if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
 +        {
 +            wcscpy(&szBuffer[Length], szShell);
 +            TRACE("szBuffer %s\n", debugstr_w(szBuffer));
 +
 +            result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
 +            if (result == ERROR_SUCCESS)
 +            {
 +                szBuffer[Length] = 0;
 +                AddStaticEntryForKey(hKey, szBuffer);
 +                RegCloseKey(hKey);
 +            }
 +        }
 +    }
 +
 +    wcscpy(szBuffer, szShellAssoc);
 +    dwBuffer = sizeof(szBuffer) - sizeof(szShellAssoc) - sizeof(WCHAR);
 +    result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, L"PerceivedType", RRF_RT_REG_SZ, NULL, (LPBYTE)&szBuffer[_countof(szShellAssoc) - 1], &dwBuffer);
 +    if (result == ERROR_SUCCESS)
 +    {
 +        Length = wcslen(&szBuffer[_countof(szShellAssoc)]) + _countof(szShellAssoc);
 +        wcscat(szBuffer, L"\\shell");
 +        TRACE("szBuffer %s\n", debugstr_w(szBuffer));
 +
 +        result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
 +        if (result == ERROR_SUCCESS)
 +        {
 +            szBuffer[Length] = 0;
 +            AddStaticEntryForKey(hKey, szBuffer);
 +            RegCloseKey(hKey);
 +        }
 +    }
 +}
 +
 +static
 +BOOL
 +HasClipboardData()
 +{
 +    BOOL bRet = FALSE;
 +    IDataObject *pDataObj;
 +
 +    if(SUCCEEDED(OleGetClipboard(&pDataObj)))
 +    {
 +        STGMEDIUM medium;
 +        FORMATETC formatetc;
 +
 +        TRACE("pDataObj=%p\n", pDataObj);
 +
 +        /* Set the FORMATETC structure*/
 +        InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
 +        if(SUCCEEDED(pDataObj->GetData(&formatetc, &medium)))
 +        {
 +            bRet = TRUE;
 +            ReleaseStgMedium(&medium);
 +        }
 +
 +        pDataObj->Release();
 +    }
 +
 +    return bRet;
 +}
 +
 +static
 +VOID
 +DisablePasteOptions(HMENU hMenu)
 +{
 +    MENUITEMINFOW mii;
 +
 +    mii.cbSize = sizeof(mii);
 +    mii.fMask = MIIM_STATE;
 +    mii.fState = MFS_DISABLED;
 +
 +    TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERT, FALSE, &mii));
 +    TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERTLINK, FALSE, &mii));
 +}
 +
 +BOOL
 +CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID *pclsid)
 +{
 +    PDynamicShellEntry pEntry = m_pDynamicEntries;
 +
 +    while (pEntry)
 +    {
 +        if (!memcmp(&pEntry->ClassID, pclsid, sizeof(CLSID)))
 +            return TRUE;
 +        pEntry = pEntry->pNext;
 +    }
 +
 +    return FALSE;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid)
 +{
 +    HRESULT hr;
 +
 +    TRACE("LoadDynamicContextMenuHandler entered with This %p hKey %p pclsid %s\n", this, hKey, wine_dbgstr_guid(pclsid));
 +
 +    if (IsShellExtensionAlreadyLoaded(pclsid))
 +        return S_OK;
 +
 +    IContextMenu *pcm;
 +    hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IContextMenu, &pcm));
 +    if (hr != S_OK)
 +    {
 +        ERR("SHCoCreateInstance failed %x\n", GetLastError());
 +        return hr;
 +    }
 +
 +    IShellExtInit *pExtInit;
 +    hr = pcm->QueryInterface(IID_PPV_ARG(IShellExtInit, &pExtInit));
 +    if (hr != S_OK)
 +    {
 +        ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
 +        pcm->Release();
 +        return hr;
 +    }
 +
 +    hr = pExtInit->Initialize(m_pidlFolder, m_pDataObj, hKey);
 +    pExtInit->Release();
 +    if (hr != S_OK)
 +    {
 +        TRACE("Failed to initialize shell extension error %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
 +        pcm->Release();
 +        return hr;
 +    }
 +
 +    PDynamicShellEntry pEntry = (DynamicShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry));
 +    if (!pEntry)
 +    {
 +        pcm->Release();
 +        return E_OUTOFMEMORY;
 +    }
 +
 +    pEntry->iIdCmdFirst = 0;
 +    pEntry->pNext = NULL;
 +    pEntry->NumIds = 0;
 +    pEntry->pCM = pcm;
 +    memcpy(&pEntry->ClassID, pclsid, sizeof(CLSID));
 +
 +    if (m_pDynamicEntries)
 +    {
 +        PDynamicShellEntry pLastEntry = m_pDynamicEntries;
 +
 +        while (pLastEntry->pNext)
 +            pLastEntry = pLastEntry->pNext;
 +
 +        pLastEntry->pNext = pEntry;
 +    }
 +    else
 +        m_pDynamicEntries = pEntry;
 +
 +    return S_OK;
 +}
 +
 +BOOL
 +CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey)
 +{
 +
 +    WCHAR wszName[MAX_PATH], wszBuf[MAX_PATH], *pwszClsid;
 +    DWORD cchName;
 +    HRESULT hr;
 +    HKEY hKey;
 +
 +    if (RegOpenKeyExW(hRootKey, L"shellex\\ContextMenuHandlers", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
 +    {
 +        TRACE("RegOpenKeyExW failed\n");
 +        return FALSE;
 +    }
 +
 +    DWORD dwIndex = 0;
 +    while (TRUE)
 +    {
 +        cchName = _countof(wszName);
 +        if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
 +            break;
 +
 +        /* Key name or key value is CLSID */
 +        CLSID clsid;
 +        hr = CLSIDFromString(wszName, &clsid);
 +        if (hr == S_OK)
 +            pwszClsid = wszName;
 +        else
 +        {
 +            DWORD cchBuf = _countof(wszBuf);
 +            if (RegGetValueW(hKey, wszName, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &cchBuf) == ERROR_SUCCESS)
 +                hr = CLSIDFromString(wszBuf, &clsid);
 +            pwszClsid = wszBuf;
 +        }
 +        if (SUCCEEDED(hr))
 +        {
 +            if (m_bGroupPolicyActive)
 +            {
 +                if (RegGetValueW(HKEY_LOCAL_MACHINE,
 +                                L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
 +                                pwszClsid,
 +                                RRF_RT_REG_SZ,
 +                                NULL,
 +                                NULL,
 +                                NULL) == ERROR_SUCCESS)
 +                {
 +                    LoadDynamicContextMenuHandler(hKey, &clsid);
 +                }
 +            }
 +            else
 +                LoadDynamicContextMenuHandler(hKey, &clsid);
 +        }
 +    }
 +
 +    RegCloseKey(hKey);
 +    return TRUE;
 +}
 +
 +UINT
 +CDefaultContextMenu::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT IndexMenu, UINT idCmdFirst, UINT idCmdLast)
 +{
 +    if (!m_pDynamicEntries)
 +    {
 +        m_iIdSHEFirst = 0;
 +        m_iIdSHELast = 0;
 +        return IndexMenu;
 +    }
 +
 +    PDynamicShellEntry pEntry = m_pDynamicEntries;
 +    idCmdFirst = 0x5000;
 +    idCmdLast =  0x6000;
 +    m_iIdSHEFirst = idCmdFirst;
 +    do
 +    {
 +        HRESULT hr = pEntry->pCM->QueryContextMenu(hMenu, IndexMenu++, idCmdFirst, idCmdLast, CMF_NORMAL);
 +        if (SUCCEEDED(hr))
 +        {
 +            pEntry->iIdCmdFirst = idCmdFirst;
 +            pEntry->NumIds = LOWORD(hr);
 +            IndexMenu += pEntry->NumIds;
 +            idCmdFirst += pEntry->NumIds + 0x10;
 +        }
 +        TRACE("pEntry %p hr %x contextmenu %p cmdfirst %x num ids %x\n", pEntry, hr, pEntry->pCM, pEntry->iIdCmdFirst, pEntry->NumIds);
 +        pEntry = pEntry->pNext;
 +    } while (pEntry);
 +
 +    m_iIdSHELast = idCmdFirst;
 +    TRACE("SH_LoadContextMenuHandlers first %x last %x\n", m_iIdSHEFirst, m_iIdSHELast);
 +    return IndexMenu;
 +}
 +
 +UINT
 +CDefaultContextMenu::BuildBackgroundContextMenu(
 +    HMENU hMenu,
 +    UINT iIdCmdFirst,
 +    UINT iIdCmdLast,
 +    UINT uFlags)
 +{
 +    UINT IndexMenu = 0;
 +    HMENU hSubMenu;
 +
 +    TRACE("BuildBackgroundContextMenu entered\n");
 +
 +    if (!_ILIsDesktop(m_pidlFolder))
 +    {
 +        WCHAR wszBuf[MAX_PATH];
 +
 +        /* view option is only available in browsing mode */
 +        hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
 +        if (hSubMenu && LoadStringW(shell32_hInstance, FCIDM_SHVIEW_VIEW, wszBuf, _countof(wszBuf)))
 +        {
 +            TRACE("wszBuf %s\n", debugstr_w(wszBuf));
 +
 +            MENUITEMINFOW mii;
 +            ZeroMemory(&mii, sizeof(mii));
 +            mii.cbSize = sizeof(mii);
 +            mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID;
 +            mii.fType = MFT_STRING;
 +            mii.wID = iIdCmdFirst++;
 +            mii.dwTypeData = wszBuf;
 +            mii.cch = wcslen(mii.dwTypeData);
 +            mii.fState = MFS_ENABLED;
 +            mii.hSubMenu = hSubMenu;
 +            InsertMenuItemW(hMenu, IndexMenu++, TRUE, &mii);
 +            DestroyMenu(hSubMenu);
 +        }
 +    }
 +
 +    hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_002");
 +    if (hSubMenu)
 +    {
 +        /* merge general background context menu in */
 +        iIdCmdFirst = Shell_MergeMenus(hMenu, GetSubMenu(hSubMenu, 0), IndexMenu, 0, 0xFFFF, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS) + 1;
 +        DestroyMenu(hSubMenu);
 +    }
 +
 +    if (!HasClipboardData())
 +    {
 +        TRACE("disabling paste options\n");
 +        DisablePasteOptions(hMenu);
 +    }
 +
 +    /* Directory is progid of filesystem folders only */
 +    LPITEMIDLIST pidlFolderLast = ILFindLastID(m_pidlFolder);
 +    if (_ILIsDesktop(pidlFolderLast) || _ILIsDrive(pidlFolderLast) || _ILIsFolder(pidlFolderLast))
 +    {
 +        /* Load context menu handlers */
 +        TRACE("Add background handlers: %p\n", m_pidlFolder);
 +        HKEY hKey;
 +        if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory\\Background", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
 +        {
 +            EnumerateDynamicContextHandlerForKey(hKey);
 +            RegCloseKey(hKey);
 +        }
 +
 +        if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu, GetMenuItemCount(hMenu) - 1, iIdCmdFirst, iIdCmdLast))
 +        {
 +            /* seperate dynamic context menu items */
 +            _InsertMenuItemW(hMenu, GetMenuItemCount(hMenu) - 1, TRUE, -1, MFT_SEPARATOR, NULL, MFS_ENABLED);
 +        }
 +    }
 +
 +    return iIdCmdLast;
 +}
 +
 +UINT
 +CDefaultContextMenu::AddStaticContextMenusToMenu(
 +    HMENU hMenu,
 +    UINT IndexMenu)
 +{
 +    MENUITEMINFOW mii;
 +    UINT idResource;
 +    WCHAR wszVerb[40];
 +    UINT fState;
 +
 +    mii.cbSize = sizeof(mii);
 +    mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
 +    mii.fType = MFT_STRING;
 +    mii.wID = 0x4000;
 +    mii.dwTypeData = NULL;
 +    m_iIdSCMFirst = mii.wID;
 +
 +    PStaticShellEntry pEntry = m_pStaticEntries;
 +
 +    while (pEntry)
 +    {
 +        fState = MFS_ENABLED;
 +        mii.dwTypeData = NULL;
 +
++        /* set first entry as default */
++        if (pEntry == m_pStaticEntries)
++            fState |= MFS_DEFAULT;
++        
 +        if (!wcsicmp(pEntry->szVerb, L"open"))
 +        {
++            /* override default when open verb is found */
 +            fState |= MFS_DEFAULT;
 +            idResource = IDS_OPEN_VERB;
 +        }
 +        else if (!wcsicmp(pEntry->szVerb, L"explore"))
 +            idResource = IDS_EXPLORE_VERB;
 +        else if (!wcsicmp(pEntry->szVerb, L"runas"))
 +            idResource = IDS_RUNAS_VERB;
 +        else if (!wcsicmp(pEntry->szVerb, L"edit"))
 +            idResource = IDS_EDIT_VERB;
 +        else if (!wcsicmp(pEntry->szVerb, L"find"))
 +            idResource = IDS_FIND_VERB;
 +        else if (!wcsicmp(pEntry->szVerb, L"print"))
 +            idResource = IDS_PRINT_VERB;
 +        else if (!wcsicmp(pEntry->szVerb, L"printto"))
 +        {
 +            pEntry = pEntry->pNext;
 +            continue;
 +        }
 +        else
 +            idResource = 0;
 +
 +        /* By default use verb for menu item name */
 +        mii.dwTypeData = pEntry->szVerb;
 +
 +        if (idResource > 0)
 +        {
 +            if (LoadStringW(shell32_hInstance, idResource, wszVerb, _countof(wszVerb)))
 +                mii.dwTypeData = wszVerb; /* use translated verb */
 +            else
 +                ERR("Failed to load string\n");
 +        }
 +        else
 +        {
 +            WCHAR wszKey[256];
 +            HRESULT hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb);
 +
 +            if (SUCCEEDED(hr))
 +            {
 +                DWORD cbVerb = sizeof(wszVerb);
 +
 +                if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, NULL, RRF_RT_REG_SZ, NULL, wszVerb, &cbVerb) == ERROR_SUCCESS)
 +                    mii.dwTypeData = wszVerb; /* use description for the menu entry */
 +            }
 +        }
 +
 +        mii.cch = wcslen(mii.dwTypeData);
 +        mii.fState = fState;
 +        InsertMenuItemW(hMenu, IndexMenu++, TRUE, &mii);
 +
 +        mii.wID++;
 +        pEntry = pEntry->pNext;
 +    }
 +
 +    m_iIdSCMLast = mii.wID - 1;
 +    return IndexMenu;
 +}
 +
 +void WINAPI _InsertMenuItemW(
 +    HMENU hMenu,
 +    UINT indexMenu,
 +    BOOL fByPosition,
 +    UINT wID,
 +    UINT fType,
 +    LPCWSTR dwTypeData,
 +    UINT fState)
 +{
 +    MENUITEMINFOW mii;
 +    WCHAR wszText[100];
 +
 +    ZeroMemory(&mii, sizeof(mii));
 +    mii.cbSize = sizeof(mii);
 +    if (fType == MFT_SEPARATOR)
 +        mii.fMask = MIIM_ID | MIIM_TYPE;
 +    else if (fType == MFT_STRING)
 +    {
 +        mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
 +        if ((ULONG_PTR)HIWORD((ULONG_PTR)dwTypeData) == 0)
 +        {
 +            if (LoadStringW(shell32_hInstance, LOWORD((ULONG_PTR)dwTypeData), wszText, _countof(wszText)))
 +                mii.dwTypeData = wszText;
 +            else
 +            {
 +                ERR("failed to load string %p\n", dwTypeData);
 +                return;
 +            }
 +        }
 +        else
 +            mii.dwTypeData = (LPWSTR)dwTypeData;
 +        mii.fState = fState;
 +    }
 +
 +    mii.wID = wID;
 +    mii.fType = fType;
 +    InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
 +}
 +
 +UINT
 +CDefaultContextMenu::BuildShellItemContextMenu(
 +    HMENU hMenu,
 +    UINT iIdCmdFirst,
 +    UINT iIdCmdLast,
 +    UINT uFlags)
 +{
 +    HKEY hKey;
 +    HRESULT hr;
 +
 +    TRACE("BuildShellItemContextMenu entered\n");
 +    ASSERT(m_Dcm.cidl >= 1);
 +
 +    STRRET strFile;
 +    hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strFile);
 +    if (hr == S_OK)
 +    {
 +        WCHAR wszPath[MAX_PATH];
 +        hr = StrRetToBufW(&strFile, m_Dcm.apidl[0], wszPath, _countof(wszPath));
 +        if (hr == S_OK)
 +        {
 +            LPCWSTR pwszExt = PathFindExtensionW(wszPath);
 +            if (pwszExt[0])
 +            {
 +                /* enumerate dynamic/static for a given file class */
 +                if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
 +                {
 +                    /* add static verbs */
 +                    AddStaticEntryForFileClass(pwszExt);
 +
 +                    /* load dynamic extensions from file extension key */
 +                    EnumerateDynamicContextHandlerForKey(hKey);
 +                    RegCloseKey(hKey);
 +                }
 +
 +                WCHAR wszTemp[40];
 +                DWORD dwSize = sizeof(wszTemp);
 +                if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszTemp, &dwSize) == ERROR_SUCCESS)
 +                {
 +                    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
 +                    {
 +                        /* add static verbs from progid key */
 +                        AddStaticEntryForFileClass(wszTemp);
 +
 +                        /* load dynamic extensions from progid key */
 +                        EnumerateDynamicContextHandlerForKey(hKey);
 +                        RegCloseKey(hKey);
 +                    }
 +                }
 +            }
 +
 +            if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"*", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
 +            {
 +                /* load default extensions */
 +                EnumerateDynamicContextHandlerForKey(hKey);
 +                RegCloseKey(hKey);
 +            }
 +        }
 +    }
 +    else
 +        ERR("GetDisplayNameOf failed: %x\n", hr);
 +
 +    GUID *pGuid = _ILGetGUIDPointer(m_Dcm.apidl[0]);
 +    if (pGuid)
 +    {
 +        LPOLESTR pwszCLSID;
 +        WCHAR buffer[60];
 +
 +        wcscpy(buffer, L"CLSID\\");
 +        hr = StringFromCLSID(*pGuid, &pwszCLSID);
 +        if (hr == S_OK)
 +        {
 +            wcscpy(&buffer[6], pwszCLSID);
 +            TRACE("buffer %s\n", debugstr_w(buffer));
 +            if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
 +            {
 +                EnumerateDynamicContextHandlerForKey(hKey);
 +                AddStaticEntryForFileClass(buffer);
 +                RegCloseKey(hKey);
 +            }
 +            CoTaskMemFree(pwszCLSID);
 +        }
 +    }
 +
 +    if (_ILIsDrive(m_Dcm.apidl[0]))
 +    {
 +        AddStaticEntryForFileClass(L"Drive");
 +        if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
 +        {
 +            EnumerateDynamicContextHandlerForKey(hKey);
 +            RegCloseKey(hKey);
 +        }
 +
 +    }
 +
 +    /* add static actions */
 +    SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
 +    hr = m_Dcm.psf->GetAttributesOf(m_Dcm.cidl, m_Dcm.apidl, &rfg);
 +    if (FAILED(hr))
 +    {
 +        ERR("GetAttributesOf failed: %x\n", hr);
 +        rfg = 0;
 +    }
 +
 +    if (rfg & SFGAO_FOLDER)
 +    {
 +        /* add the default verbs open / explore */
 +        AddStaticEntryForFileClass(L"Folder");
 +        if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
 +        {
 +            EnumerateDynamicContextHandlerForKey(hKey);
 +            RegCloseKey(hKey);
 +        }
 +
 +        /* Directory is only loaded for real filesystem directories */
 +        if (_ILIsFolder(m_Dcm.apidl[0]))
 +        {
 +            AddStaticEntryForFileClass(L"Directory");
 +            if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
 +            {
 +                EnumerateDynamicContextHandlerForKey(hKey);
 +                RegCloseKey(hKey);
 +            }
 +        }
 +    }
 +
 +    /* AllFilesystemObjects class is loaded only for files and directories */
 +    if (_ILIsFolder(m_Dcm.apidl[0]) || _ILIsValue(m_Dcm.apidl[0]))
 +    {
 +        if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
 +        {
 +            /* sendto service is registered here */
 +            EnumerateDynamicContextHandlerForKey(hKey);
 +            RegCloseKey(hKey);
 +        }
 +    }
 +
 +    /* add static context menu handlers */
 +    UINT IndexMenu = AddStaticContextMenusToMenu(hMenu, 0);
 +
 +    /* now process dynamic context menu handlers */
 +    BOOL bAddSep = FALSE;
 +    IndexMenu = InsertMenuItemsOfDynamicContextMenuExtension(hMenu, IndexMenu, iIdCmdFirst, iIdCmdLast);
 +    TRACE("IndexMenu %d\n", IndexMenu);
 +
 +    if (_ILIsDrive(m_Dcm.apidl[0]))
 +    {
 +        /* The 'Format' option must be always available,
 +         * thus it is not registered as a static shell extension */
 +        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
 +        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0x7ABC, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
 +        bAddSep = TRUE;
 +    }
 +
 +    BOOL bClipboardData = (HasClipboardData() && (rfg & SFGAO_FILESYSTEM));
 +    if (rfg & (SFGAO_CANCOPY | SFGAO_CANMOVE) || bClipboardData)
 +    {
 +        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
 +        if (rfg & SFGAO_CANMOVE)
 +            _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_CUT, MFT_STRING, MAKEINTRESOURCEW(IDS_CUT), MFS_ENABLED);
 +        if (rfg & SFGAO_CANCOPY)
 +            _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_COPY, MFT_STRING, MAKEINTRESOURCEW(IDS_COPY), MFS_ENABLED);
 +        if (bClipboardData)
 +            _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_INSERT, MFT_STRING, MAKEINTRESOURCEW(IDS_INSERT), MFS_ENABLED);
 +
 +        bAddSep = TRUE;
 +    }
 +
 +    if (rfg & SFGAO_CANLINK)
 +    {
 +        bAddSep = FALSE;
 +        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
 +        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED);
 +    }
 +
 +    if (rfg & SFGAO_CANDELETE)
 +    {
 +        if (bAddSep)
 +        {
 +            bAddSep = FALSE;
 +            _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
 +        }
 +        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_DELETE, MFT_STRING, MAKEINTRESOURCEW(IDS_DELETE), MFS_ENABLED);
 +    }
 +
 +    if (rfg & SFGAO_CANRENAME)
 +    {
 +        if (bAddSep)
 +        {
 +            _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
 +        }
 +        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_RENAME, MFT_STRING, MAKEINTRESOURCEW(IDS_RENAME), MFS_ENABLED);
 +        bAddSep = TRUE;
 +    }
 +
 +    if (rfg & SFGAO_HASPROPSHEET)
 +    {
 +        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
 +        _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
 +    }
 +
 +    return iIdCmdLast;
 +}
 +
 +HRESULT
 +WINAPI
 +CDefaultContextMenu::QueryContextMenu(
 +    HMENU hMenu,
 +    UINT IndexMenu,
 +    UINT idCmdFirst,
 +    UINT idCmdLast,
 +    UINT uFlags)
 +{
 +    if (m_Dcm.cidl)
 +        idCmdFirst = BuildShellItemContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
 +    else
 +        idCmdFirst = BuildBackgroundContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
 +
 +    return S_OK;
 +}
 +
 +static
 +HRESULT
 +NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi, BOOL bRefresh)
 +{
 +    /* Note: CWM_GETISHELLBROWSER returns not referenced object */
 +    LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
 +    if (!lpSB)
 +        return E_FAIL;
 +
 +    LPSHELLVIEW lpSV = NULL;
 +    if (FAILED(lpSB->QueryActiveShellView(&lpSV)))
 +        return E_FAIL;
 +
 +    HWND hwndSV = NULL;
 +    if (SUCCEEDED(lpSV->GetWindow(&hwndSV)))
 +        SendMessageW(hwndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
 +
 +    lpSV->Release();
 +    return S_OK;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoRefresh(
 +    LPCMINVOKECOMMANDINFO lpcmi)
 +{
 +    CComPtr<IPersistFolder2> ppf2 = NULL;
 +    LPITEMIDLIST pidl;
 +    HRESULT hr = m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
 +    if (SUCCEEDED(hr))
 +    {
 +        hr = ppf2->GetCurFolder(&pidl);
 +        if (SUCCEEDED(hr))
 +        {
 +            SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, NULL);
 +            ILFree(pidl);
 +        }
 +        ppf2->Release();
 +    }
 +    return hr;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoPaste(
 +    LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink)
 +{
 +    HRESULT hr;
 +
 +    CComPtr<IDataObject> pda;
 +    hr = OleGetClipboard(&pda);
 +    if (FAILED(hr))
 +        return hr;
 +
 +    CComPtr<IShellFolder> psfDesktop;
 +    CComPtr<IShellFolder> psfTarget = NULL;
 +
 +    hr = SHGetDesktopFolder(&psfDesktop);
 +    if (FAILED(hr))
 +        return hr;
 +
 +    /* Find target folder */
 +    if (m_Dcm.cidl)
 +    {
 +        hr = m_Dcm.psf->BindToObject(m_Dcm.apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
 +    }
 +    else
 +    {
 +        CComPtr<IPersistFolder2> ppf2 = NULL;
 +        LPITEMIDLIST pidl;
 +
 +        /* cidl is zero due to explorer view */
 +        hr = m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
 +        if (SUCCEEDED(hr))
 +        {
 +            hr = ppf2->GetCurFolder(&pidl);
 +            if (SUCCEEDED(hr))
 +            {
 +                if (_ILIsDesktop(pidl))
 +                {
 +                    /* use desktop shellfolder */
 +                    psfTarget = psfDesktop;
 +                }
 +                else
 +                {
 +                    /* retrieve target desktop folder */
 +                    hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
 +                }
 +                TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget.p, _ILIsDesktop(pidl));
 +                ILFree(pidl);
 +            }
 +        }
 +    }
 +
 +    if (FAILED(hr))
 +    {
 +        ERR("no IShellFolder\n");
 +        return hr;
 +    }
 +
 +    FORMATETC formatetc2;
 +    STGMEDIUM medium2;
 +    InitFormatEtc(formatetc2, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT), TYMED_HGLOBAL);
 +
 +    DWORD dwKey= 0;
 +
 +    if (SUCCEEDED(pda->GetData(&formatetc2, &medium2)))
 +    {
 +        DWORD * pdwFlag = (DWORD*)GlobalLock(medium2.hGlobal);
 +        if (pdwFlag)
 +        {
 +            if (*pdwFlag == DROPEFFECT_COPY)
 +                dwKey = MK_CONTROL;
 +            else
 +                dwKey = MK_SHIFT;
 +        }
 +        else {
 +            ERR("No drop effect obtained");
 +        }
 +        GlobalUnlock(medium2.hGlobal);
 +    }
 +
 +    if (bLink)
 +    {
 +        dwKey = MK_CONTROL|MK_SHIFT;
 +    }
 +
 +    IDropTarget *pdrop;
 +    hr = psfTarget->QueryInterface(IID_PPV_ARG(IDropTarget, &pdrop));
 +    if (FAILED(hr))
 +    {
 +        ERR("Error getting IDropTarget interface\n");
 +        return hr;
 +    }
 +
 +    SHSimulateDrop(pdrop, pda, dwKey, NULL, NULL);
 +
 +    TRACE("CP result %x\n", hr);
 +    return S_OK;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoOpenOrExplore(
 +    LPCMINVOKECOMMANDINFO lpcmi)
 +{
 +    UNIMPLEMENTED;
 +    return E_FAIL;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoCreateLink(
 +    LPCMINVOKECOMMANDINFO lpcmi)
 +{
 +    LPDATAOBJECT pDataObj;
 +    IDropTarget *pDT;
 +    HRESULT hr;
 +    CComPtr<IPersistFolder2> ppf2 = NULL;
 +    LPITEMIDLIST pidl;
 +    CComPtr<IShellFolder> psfDesktop;
 +    CComPtr<IShellFolder> psfTarget = NULL;
 +
 +    hr = SHGetDesktopFolder(&psfDesktop);
 +    if (FAILED(hr))
 +        return hr;
 +
 +    if (SUCCEEDED(hr = SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
 +    {
 +        hr = m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
 +        if (SUCCEEDED(hr))
 +        {
 +            hr = ppf2->GetCurFolder(&pidl);
 +            if (SUCCEEDED(hr))
 +            {
 +                if (_ILIsDesktop(pidl))
 +                {
 +                    /* use desktop shellfolder */
 +                    psfTarget = psfDesktop;
 +                }
 +                else
 +                {
 +                    /* retrieve target desktop folder */
 +                    hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
 +                }
 +                TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget.p, _ILIsDesktop(pidl));
 +                ILFree(pidl);
 +            }
 +        }
 +
 +    }
 +
 +    if (FAILED(hr))
 +    {
 +        ERR("no IShellFolder\n");
 +        return hr;
 +    }
 +
 +    psfTarget->QueryInterface(IID_PPV_ARG(IDropTarget, &pDT));
 +    if (FAILED(hr))
 +    {
 +        ERR("no IDropTarget Interface\n");
 +        return hr;
 +    }
 +    SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
 +
 +    return S_OK;
 +}
 +
 +HRESULT CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi) {
 +    TRACE("(%p) Deleting\n", this);
 +
 +    LPDATAOBJECT pDataObj;
 +
 +    if (SUCCEEDED(SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
 +    {
 +        pDataObj->AddRef();
 +        SHCreateThread(DoDeleteThreadProc, pDataObj, NULL, NULL);
 +        pDataObj->Release();
 +    } 
 +    else 
 +        return E_FAIL;
 +    return S_OK;
 +
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoCopyOrCut(
 +    LPCMINVOKECOMMANDINFO lpcmi,
 +    BOOL bCopy)
 +{
 +    LPDATAOBJECT pDataObj;
 +    HRESULT hr;
 +
 +    if (SUCCEEDED(SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
 +    {
 +        if (!bCopy)
 +        {
 +            FORMATETC formatetc;
 +            STGMEDIUM medium;
 +            InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT), TYMED_HGLOBAL);
 +            pDataObj->GetData(&formatetc, &medium);
 +            DWORD * pdwFlag = (DWORD*)GlobalLock(medium.hGlobal);
 +            if (pdwFlag)
 +                *pdwFlag = DROPEFFECT_MOVE;
 +            GlobalUnlock(medium.hGlobal);
 +            pDataObj->SetData(&formatetc, &medium, TRUE);
 +        }
 +
 +        hr = OleSetClipboard(pDataObj);
 +        pDataObj->Release();
 +        return hr;
 +    }
 +
 +    /* Note: CWM_GETISHELLBROWSER returns not referenced object */
 +    LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
 +    if (!lpSB)
 +    {
 +        ERR("failed to get shellbrowser\n");
 +        return E_FAIL;
 +    }
 +
 +    LPSHELLVIEW lpSV;
 +    hr = lpSB->QueryActiveShellView(&lpSV);
 +    if (FAILED(hr))
 +    {
 +        ERR("failed to query the active shellview\n");
 +        return hr;
 +    }
 +
 +    hr = lpSV->GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IDataObject, &pDataObj));
 +    if (SUCCEEDED(hr))
 +    {
 +        hr = OleSetClipboard(pDataObj);
 +        if (FAILED(hr))
 +            ERR("OleSetClipboard failed");
 +        pDataObj->Release();
 +    } else
 +        ERR("failed to get item object\n");
 +
 +    lpSV->Release();
 +    return hr;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoRename(
 +    LPCMINVOKECOMMANDINFO lpcmi)
 +{
 +    /* get the active IShellView. Note: CWM_GETISHELLBROWSER returns not referenced object */
 +    LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
 +    if (!lpSB)
 +    {
 +        ERR("CWM_GETISHELLBROWSER failed\n");
 +        return E_FAIL;
 +    }
 +
 +    /* is the treeview focused */
 +    HWND hwnd;
 +    if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd)))
 +    {
 +        HTREEITEM hItem = TreeView_GetSelection(hwnd);
 +        if (hItem)
 +            (void)TreeView_EditLabel(hwnd, hItem);
 +    }
 +
 +    LPSHELLVIEW lpSV;
 +    HRESULT hr = lpSB->QueryActiveShellView(&lpSV);
 +    if (FAILED(hr))
 +    {
 +        ERR("CWM_GETISHELLBROWSER failed\n");
 +        return hr;
 +    }
 +
 +    lpSV->SelectItem(m_Dcm.apidl[0],
 +                     SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT);
 +    lpSV->Release();
 +    return S_OK;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoProperties(
 +    LPCMINVOKECOMMANDINFO lpcmi)
 +{
 +    HRESULT hr = S_OK;
 +    const ITEMIDLIST *pidlParent = m_Dcm.pidlFolder, *pidlChild;
 +
 +    if (!pidlParent)
 +    {
 +        IPersistFolder2 *pf;
 +
 +        /* pidlFolder is optional */
 +        if (SUCCEEDED(m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pf))))
 +        {
 +            pf->GetCurFolder((_ITEMIDLIST**)&pidlParent);
 +            pf->Release();
 +        }
 +    }
 +
 +    if (m_Dcm.cidl > 0)
 +        pidlChild = m_Dcm.apidl[0];
 +    else
 +    {
 +        /* Set pidlChild to last pidl of current folder */
 +        if (pidlParent == m_Dcm.pidlFolder)
 +            pidlParent = (ITEMIDLIST*)ILClone(pidlParent);
 +
 +        pidlChild = (ITEMIDLIST*)ILClone(ILFindLastID(pidlParent));
 +        ILRemoveLastID((ITEMIDLIST*)pidlParent);
 +    }
 +
 +    if (_ILIsMyComputer(pidlChild))
 +    {
 +        if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL, NULL, SW_SHOWNORMAL))
 +            hr = E_FAIL;
 +    }
 +    else if (_ILIsDesktop(pidlChild))
 +    {
 +        if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL))
 +            hr = E_FAIL;
 +    }
 +    else if (_ILIsDrive(pidlChild))
 +    {
 +        WCHAR wszBuf[MAX_PATH];
 +        ILGetDisplayName(pidlChild, wszBuf);
 +        if (!SH_ShowDriveProperties(wszBuf, pidlParent, &pidlChild))
 +            hr = E_FAIL;
 +    }
 +    else if (_ILIsNetHood(pidlChild))
 +    {
 +        // FIXME path!
 +        if (32 >= (UINT)ShellExecuteW(NULL, L"open", L"explorer.exe",
 +                                      L"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
 +                                      NULL, SW_SHOWDEFAULT))
 +            hr = E_FAIL;
 +    }
 +    else if (_ILIsBitBucket(pidlChild))
 +    {
 +        /* FIXME: detect the drive path of bitbucket if appropiate */
 +        if(!SH_ShowRecycleBinProperties(L'C'))
 +            hr = E_FAIL;
 +    }
 +    else
 +    {
 +        if (m_Dcm.cidl > 1)
 +            WARN("SHMultiFileProperties is not yet implemented\n");
 +
 +        STRRET strFile;
 +        hr = m_Dcm.psf->GetDisplayNameOf(pidlChild, SHGDN_FORPARSING, &strFile);
 +        if (SUCCEEDED(hr))
 +        {
 +            WCHAR wszBuf[MAX_PATH];
 +            hr = StrRetToBufW(&strFile, pidlChild, wszBuf, _countof(wszBuf));
 +            if (SUCCEEDED(hr))
 +                hr = SH_ShowPropertiesDialog(wszBuf, pidlParent, &pidlChild);
 +            else
 +                ERR("StrRetToBufW failed\n");
 +        }
 +        else
 +            ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
 +    }
 +
 +    /* Free allocated PIDLs */
 +    if (pidlParent != m_Dcm.pidlFolder)
 +        ILFree((ITEMIDLIST*)pidlParent);
 +    if (m_Dcm.cidl < 1 || pidlChild != m_Dcm.apidl[0])
 +        ILFree((ITEMIDLIST*)pidlChild);
 +
 +    return hr;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoFormat(
 +    LPCMINVOKECOMMANDINFO lpcmi)
 +{
 +    char szDrive[8] = {0};
 +
 +    if (!_ILGetDrive(m_Dcm.apidl[0], szDrive, sizeof(szDrive)))
 +    {
 +        ERR("pidl is not a drive\n");
 +        return E_FAIL;
 +    }
 +
 +    SHFormatDrive(lpcmi->hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
 +    return S_OK;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoDynamicShellExtensions(
 +    LPCMINVOKECOMMANDINFO lpcmi)
 +{
 +    UINT idCmd = LOWORD(lpcmi->lpVerb);
 +    PDynamicShellEntry pEntry = m_pDynamicEntries;
 +
 +    TRACE("verb %p first %x last %x", lpcmi->lpVerb, m_iIdSHEFirst, m_iIdSHELast);
 +
 +    while(pEntry && idCmd > pEntry->iIdCmdFirst + pEntry->NumIds)
 +        pEntry = pEntry->pNext;
 +
 +    if (!pEntry)
 +        return E_FAIL;
 +
 +    if (idCmd >= pEntry->iIdCmdFirst && idCmd <= pEntry->iIdCmdFirst + pEntry->NumIds)
 +    {
 +        /* invoke the dynamic context menu */
 +        lpcmi->lpVerb = MAKEINTRESOURCEA(idCmd - pEntry->iIdCmdFirst);
 +        return pEntry->pCM->InvokeCommand(lpcmi);
 +    }
 +
 +    return E_FAIL;
 +}
 +
 +DWORD
 +CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry)
 +{
 +    LPSHELLBROWSER lpSB;
 +    HWND hwndTree;
 +    LPCWSTR FlagsName;
 +    WCHAR wszKey[256];
 +    HRESULT hr;
 +    DWORD wFlags;
 +    DWORD cbVerb;
 +
 +    /* Get a pointer to the shell browser */
 +    lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
 +    if (lpSB == NULL)
 +        return 0;
 +
 +    /* See if we are in Explore or Browse mode. If the browser's tree is present, we are in Explore mode.*/
 +    if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree)
 +        FlagsName = L"ExplorerFlags";
 +    else
 +        FlagsName = L"BrowserFlags";
 +
 +    /* Try to get the flag from the verb */
 +    hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb);
 +    if (!SUCCEEDED(hr))
 +        return 0;
 +
 +    cbVerb = sizeof(wFlags);
 +    if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, FlagsName, RRF_RT_REG_DWORD, NULL, &wFlags, &cbVerb) == ERROR_SUCCESS)
 +    {
 +        return wFlags;
 +    }
 +
 +    return 0;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::TryToBrowse(
 +    LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags)
 +{
 +    LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageW(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
 +    HRESULT hr;
 +
 +    if (lpSB == NULL)
 +        return E_FAIL;
 +
 +    hr = lpSB->BrowseObject(ILCombine(m_Dcm.pidlFolder, pidl), wFlags);
 +
 +    return hr;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry)
 +{
 +    LPITEMIDLIST pidlFull = ILCombine(m_Dcm.pidlFolder, pidl);
 +    if (pidlFull == NULL)
 +    {
 +        return E_FAIL;
 +    }
 +
 +    WCHAR wszPath[MAX_PATH];
 +    BOOL bHasPath = SHGetPathFromIDListW(pidlFull, wszPath);
 +
 +    WCHAR wszDir[MAX_PATH];
 +    if(bHasPath)
 +    {
 +        wcscpy(wszDir, wszPath);
 +        PathRemoveFileSpec(wszDir);
 +    }
 +    else
 +    {
 +        SHGetPathFromIDListW(m_Dcm.pidlFolder, wszDir);
 +    }
 +
 +    HKEY hkeyClass;
 +    RegOpenKeyExW(HKEY_CLASSES_ROOT, pEntry->szClass, 0, KEY_READ, &hkeyClass);
 +
 +    SHELLEXECUTEINFOW sei;
 +    ZeroMemory(&sei, sizeof(sei));
 +    sei.cbSize = sizeof(sei);
 +    sei.hwnd = lpcmi->hwnd;
 +    sei.nShow = SW_SHOWNORMAL;
 +    sei.lpVerb = pEntry->szVerb;
 +    sei.lpDirectory = wszDir;
 +    sei.lpIDList = pidlFull;
 +    sei.hkeyClass = hkeyClass;
 +    sei.fMask = SEE_MASK_CLASSKEY | SEE_MASK_IDLIST;
 +    if (bHasPath)
 +    {
 +        sei.lpFile = wszPath;
 +    }
 +
 +    ShellExecuteExW(&sei);
 +
 +    RegCloseKey(hkeyClass);
 +
 +    ILFree(pidlFull);
 +
 +    return S_OK;
 +}
 +
 +HRESULT
 +CDefaultContextMenu::DoStaticShellExtensions(
 +    LPCMINVOKECOMMANDINFO lpcmi)
 +{
 +    PStaticShellEntry pEntry = m_pStaticEntries;
 +    INT iCmd = LOWORD(lpcmi->lpVerb) - m_iIdSCMFirst;
 +    HRESULT hr;
 +    UINT i;
 +
 +    while (pEntry && (iCmd--) > 0)
 +        pEntry = pEntry->pNext;
 +
 +    if (iCmd > 0)
 +        return E_FAIL;
 +
 +    /* Get the browse flags to see if we need to browse */
 +    DWORD wFlags = BrowserFlagsFromVerb(lpcmi, pEntry);
 +    BOOL bBrowsed = FALSE;
 +
 +    for (i=0; i < m_Dcm.cidl; i++)
 +    {
 +        /* Check if we need to browse */
 +        if (wFlags > 0)
 +        {
 +            /* In xp if we have browsed, we don't open any more folders .
 +             * In win7 we browse to the first folder we find and
 +             * open new windows fo for each of the rest of the folders */
 +            if (bBrowsed)
 +                continue;
 +
 +            hr = TryToBrowse(lpcmi, m_Dcm.apidl[i], wFlags);
 +            if (SUCCEEDED(hr))
 +            {
 +                bBrowsed = TRUE;
 +                continue;
 +            }
 +        }
 +
 +        InvokePidl(lpcmi, m_Dcm.apidl[i], pEntry);
 +    }
 +
 +    return S_OK;
 +}
 +
 +HRESULT
 +WINAPI
 +CDefaultContextMenu::InvokeCommand(
 +    LPCMINVOKECOMMANDINFO lpcmi)
 +{
 +    switch(LOWORD(lpcmi->lpVerb))
 +    {
 +        case FCIDM_SHVIEW_BIGICON:
 +        case FCIDM_SHVIEW_SMALLICON:
 +        case FCIDM_SHVIEW_LISTVIEW:
 +        case FCIDM_SHVIEW_REPORTVIEW:
 +        case 0x30: /* FIX IDS in resource files */
 +        case 0x31:
 +        case 0x32:
 +        case 0x33:
 +        case FCIDM_SHVIEW_AUTOARRANGE:
 +        case FCIDM_SHVIEW_SNAPTOGRID:
 +            return NotifyShellViewWindow(lpcmi, FALSE);
 +        case FCIDM_SHVIEW_REFRESH:
 +            return DoRefresh(lpcmi);
 +        case FCIDM_SHVIEW_INSERT:
 +            return DoPaste(lpcmi, FALSE);
 +        case FCIDM_SHVIEW_INSERTLINK:
 +            return DoPaste(lpcmi, TRUE);
 +        case FCIDM_SHVIEW_OPEN:
 +        case FCIDM_SHVIEW_EXPLORE:
 +            return DoOpenOrExplore(lpcmi);
 +        case FCIDM_SHVIEW_COPY:
 +        case FCIDM_SHVIEW_CUT:
 +            return DoCopyOrCut(lpcmi, LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_COPY);
 +        case FCIDM_SHVIEW_CREATELINK:
 +            return DoCreateLink(lpcmi);
 +        case FCIDM_SHVIEW_DELETE:
 +            return DoDelete(lpcmi);
 +        case FCIDM_SHVIEW_RENAME:
 +            return DoRename(lpcmi);
 +        case FCIDM_SHVIEW_PROPERTIES:
 +            return DoProperties(lpcmi);
 +        case 0x7ABC:
 +            return DoFormat(lpcmi);
 +    }
 +
 +    if (m_iIdSHEFirst && m_iIdSHELast)
 +    {
 +        if (LOWORD(lpcmi->lpVerb) >= m_iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSHELast)
 +            return DoDynamicShellExtensions(lpcmi);
 +    }
 +
 +    if (m_iIdSCMFirst && m_iIdSCMLast)
 +    {
 +        if (LOWORD(lpcmi->lpVerb) >= m_iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSCMLast)
 +            return DoStaticShellExtensions(lpcmi);
 +    }
 +
 +    FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi->lpVerb));
 +    return E_UNEXPECTED;
 +}
 +
 +HRESULT
 +WINAPI
 +CDefaultContextMenu::GetCommandString(
 +    UINT_PTR idCommand,
 +    UINT uFlags,
 +    UINT* lpReserved,
 +    LPSTR lpszName,
 +    UINT uMaxNameLen)
 +{
 +    return S_OK;
 +}
 +
 +HRESULT
 +WINAPI
 +CDefaultContextMenu::HandleMenuMsg(
 +    UINT uMsg,
 +    WPARAM wParam,
 +    LPARAM lParam)
 +{
 +    return S_OK;
 +}
 +
 +static
 +HRESULT
 +IDefaultContextMenu_Constructor(
 +    const DEFCONTEXTMENU *pdcm,
 +    REFIID riid,
 +    void **ppv)
 +{
 +    if (ppv == NULL)
 +        return E_POINTER;
 +    *ppv = NULL;
 +
 +    CComObject<CDefaultContextMenu> *pCM;
 +    HRESULT hr = CComObject<CDefaultContextMenu>::CreateInstance(&pCM);
 +    if (FAILED(hr))
 +        return hr;
 +    pCM->AddRef(); // CreateInstance returns object with 0 ref count */
 +
 +    CComPtr<IUnknown> pResult;
 +    hr = pCM->QueryInterface(riid, (void **)&pResult);
 +    if (FAILED(hr))
 +    {
 +        pCM->Release();
 +        return hr;
 +    }
 +
 +    hr = pCM->Initialize(pdcm);
 +    if (FAILED(hr))
 +    {
 +        pCM->Release();
 +        return hr;
 +    }
 +
 +    *ppv = pResult.Detach();
 +    pCM->Release();
 +    TRACE("This(%p) cidl %u\n", *ppv, pdcm->cidl);
 +    return S_OK;
 +}
 +
 +/*************************************************************************
 + * SHCreateDefaultContextMenu            [SHELL32.325] Vista API
 + *
 + */
 +
 +HRESULT
 +WINAPI
 +SHCreateDefaultContextMenu(
 +    const DEFCONTEXTMENU *pdcm,
 +    REFIID riid,
 +    void **ppv)
 +{
 +    *ppv = NULL;
 +    HRESULT hr = IDefaultContextMenu_Constructor(pdcm, riid, ppv);
 +    if (FAILED(hr))
 +        ERR("IDefaultContextMenu_Constructor failed: %x\n", hr);
 +    TRACE("pcm %p hr %x\n", pdcm, hr);
 +    return hr;
 +}
 +
 +/*************************************************************************
 + * CDefFolderMenu_Create2            [SHELL32.701]
 + *
 + */
 +
 +HRESULT
 +WINAPI
 +CDefFolderMenu_Create2(
 +    LPCITEMIDLIST pidlFolder,
 +    HWND hwnd,
 +    UINT cidl,
 +    LPCITEMIDLIST *apidl,
 +    IShellFolder *psf,
 +    LPFNDFMCALLBACK lpfn,
 +    UINT nKeys,
 +    const HKEY *ahkeyClsKeys,
 +    IContextMenu **ppcm)
 +{
 +    DEFCONTEXTMENU pdcm;
 +    pdcm.hwnd = hwnd;
 +    pdcm.pcmcb = NULL;
 +    pdcm.pidlFolder = pidlFolder;
 +    pdcm.psf = psf;
 +    pdcm.cidl = cidl;
 +    pdcm.apidl = apidl;
 +    pdcm.punkAssociationInfo = NULL;
 +    pdcm.cKeys = nKeys;
 +    pdcm.aKeys = ahkeyClsKeys;
 +
 +    HRESULT hr = SHCreateDefaultContextMenu(&pdcm, IID_PPV_ARG(IContextMenu, ppcm));
 +    return hr;
 +}
 +
index bcdd151,0000000..5b914d4
mode 100644,000000..100644
--- /dev/null
@@@ -1,1563 -1,0 +1,1563 @@@
- INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
 +/*
 + *                 Shell basics
 + *
 + * Copyright 1998 Marcus Meissner
 + * Copyright 1998 Juergen Schmied (jsch)  *  <juergen.schmied@metronet.de>
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 + */
 +
 +#include "precomp.h"
 +
 +#include "shell32_version.h"
 +#include <reactos/version.h>
 +
 +WINE_DEFAULT_DEBUG_CHANNEL(shell);
 +
 +const char * const SHELL_Authors[] = { "Copyright 1993-"COPYRIGHT_YEAR" WINE team", "Copyright 1998-"COPYRIGHT_YEAR" ReactOS Team", 0 };
 +
 +#define MORE_DEBUG 1
 +/*************************************************************************
 + * CommandLineToArgvW            [SHELL32.@]
 + *
 + * We must interpret the quotes in the command line to rebuild the argv
 + * array correctly:
 + * - arguments are separated by spaces or tabs
 + * - quotes serve as optional argument delimiters
 + *   '"a b"'   -> 'a b'
 + * - escaped quotes must be converted back to '"'
 + *   '\"'      -> '"'
 + * - consecutive backslashes preceding a quote see their number halved with
 + *   the remainder escaping the quote:
 + *   2n   backslashes + quote -> n backslashes + quote as an argument delimiter
 + *   2n+1 backslashes + quote -> n backslashes + literal quote
 + * - backslashes that are not followed by a quote are copied literally:
 + *   'a\b'     -> 'a\b'
 + *   'a\\b'    -> 'a\\b'
 + * - in quoted strings, consecutive quotes see their number divided by three
 + *   with the remainder modulo 3 deciding whether to close the string or not.
 + *   Note that the opening quote must be counted in the consecutive quotes,
 + *   that's the (1+) below:
 + *   (1+) 3n   quotes -> n quotes
 + *   (1+) 3n+1 quotes -> n quotes plus closes the quoted string
 + *   (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
 + * - in unquoted strings, the first quote opens the quoted string and the
 + *   remaining consecutive quotes follow the above rule.
 + */
 +LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
 +{
 +    DWORD argc;
 +    LPWSTR  *argv;
 +    LPCWSTR s;
 +    LPWSTR d;
 +    LPWSTR cmdline;
 +    int qcount,bcount;
 +
 +    if(!numargs)
 +    {
 +        SetLastError(ERROR_INVALID_PARAMETER);
 +        return NULL;
 +    }
 +
 +    if (*lpCmdline==0)
 +    {
 +        /* Return the path to the executable */
 +        DWORD len, deslen=MAX_PATH, size;
 +
 +        size = sizeof(LPWSTR) + deslen*sizeof(WCHAR) + sizeof(LPWSTR);
 +        for (;;)
 +        {
 +            if (!(argv = (LPWSTR *)LocalAlloc(LMEM_FIXED, size))) return NULL;
 +            len = GetModuleFileNameW(0, (LPWSTR)(argv+1), deslen);
 +            if (!len)
 +            {
 +                LocalFree(argv);
 +                return NULL;
 +            }
 +            if (len < deslen) break;
 +            deslen*=2;
 +            size = sizeof(LPWSTR) + deslen*sizeof(WCHAR) + sizeof(LPWSTR);
 +            LocalFree( argv );
 +        }
 +        argv[0]=(LPWSTR)(argv+1);
 +        *numargs=1;
 +
 +        return argv;
 +    }
 +
 +    /* --- First count the arguments */
 +    argc=1;
 +    s=lpCmdline;
 +    /* The first argument, the executable path, follows special rules */
 +    if (*s=='"')
 +    {
 +        /* The executable path ends at the next quote, no matter what */
 +        s++;
 +        while (*s)
 +            if (*s++=='"')
 +                break;
 +    }
 +    else
 +    {
 +        /* The executable path ends at the next space, no matter what */
 +        while (*s && *s!=' ' && *s!='\t')
 +            s++;
 +    }
 +    /* skip to the first argument, if any */
 +    while (*s==' ' || *s=='\t')
 +        s++;
 +    if (*s)
 +        argc++;
 +
 +    /* Analyze the remaining arguments */
 +    qcount=bcount=0;
 +    while (*s)
 +    {
 +        if ((*s==' ' || *s=='\t') && qcount==0)
 +        {
 +            /* skip to the next argument and count it if any */
 +            while (*s==' ' || *s=='\t')
 +                s++;
 +            if (*s)
 +                argc++;
 +            bcount=0;
 +        }
 +        else if (*s=='\\')
 +        {
 +            /* '\', count them */
 +            bcount++;
 +            s++;
 +        }
 +        else if (*s=='"')
 +        {
 +            /* '"' */
 +            if ((bcount & 1)==0)
 +                qcount++; /* unescaped '"' */
 +            s++;
 +            bcount=0;
 +            /* consecutive quotes, see comment in copying code below */
 +            while (*s=='"')
 +            {
 +                qcount++;
 +                s++;
 +            }
 +            qcount=qcount % 3;
 +            if (qcount==2)
 +                qcount=0;
 +        }
 +        else
 +        {
 +            /* a regular character */
 +            bcount=0;
 +            s++;
 +        }
 +    }
 +
 +    /* Allocate in a single lump, the string array, and the strings that go
 +     * with it. This way the caller can make a single LocalFree() call to free
 +     * both, as per MSDN.
 +     */
 +    argv=(LPWSTR *)LocalAlloc(LMEM_FIXED, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
 +    if (!argv)
 +        return NULL;
 +    cmdline=(LPWSTR)(argv+argc);
 +    strcpyW(cmdline, lpCmdline);
 +
 +    /* --- Then split and copy the arguments */
 +    argv[0]=d=cmdline;
 +    argc=1;
 +    /* The first argument, the executable path, follows special rules */
 +    if (*d=='"')
 +    {
 +        /* The executable path ends at the next quote, no matter what */
 +        s=d+1;
 +        while (*s)
 +        {
 +            if (*s=='"')
 +            {
 +                s++;
 +                break;
 +            }
 +            *d++=*s++;
 +        }
 +    }
 +    else
 +    {
 +        /* The executable path ends at the next space, no matter what */
 +        while (*d && *d!=' ' && *d!='\t')
 +            d++;
 +        s=d;
 +        if (*s)
 +            s++;
 +    }
 +    /* close the executable path */
 +    *d++=0;
 +    /* skip to the first argument and initialize it if any */
 +    while (*s==' ' || *s=='\t')
 +        s++;
 +    if (!*s)
 +    {
 +        /* There are no parameters so we are all done */
 +        *numargs=argc;
 +        return argv;
 +    }
 +
 +    /* Split and copy the remaining arguments */
 +    argv[argc++]=d;
 +    qcount=bcount=0;
 +    while (*s)
 +    {
 +        if ((*s==' ' || *s=='\t') && qcount==0)
 +        {
 +            /* close the argument */
 +            *d++=0;
 +            bcount=0;
 +
 +            /* skip to the next one and initialize it if any */
 +            do {
 +                s++;
 +            } while (*s==' ' || *s=='\t');
 +            if (*s)
 +                argv[argc++]=d;
 +        }
 +        else if (*s=='\\')
 +        {
 +            *d++=*s++;
 +            bcount++;
 +        }
 +        else if (*s=='"')
 +        {
 +            if ((bcount & 1)==0)
 +            {
 +                /* Preceded by an even number of '\', this is half that
 +                 * number of '\', plus a quote which we erase.
 +                 */
 +                d-=bcount/2;
 +                qcount++;
 +            }
 +            else
 +            {
 +                /* Preceded by an odd number of '\', this is half that
 +                 * number of '\' followed by a '"'
 +                 */
 +                d=d-bcount/2-1;
 +                *d++='"';
 +            }
 +            s++;
 +            bcount=0;
 +            /* Now count the number of consecutive quotes. Note that qcount
 +             * already takes into account the opening quote if any, as well as
 +             * the quote that lead us here.
 +             */
 +            while (*s=='"')
 +            {
 +                if (++qcount==3)
 +                {
 +                    *d++='"';
 +                    qcount=0;
 +                }
 +                s++;
 +            }
 +            if (qcount==2)
 +                qcount=0;
 +        }
 +        else
 +        {
 +            /* a regular character */
 +            *d++=*s++;
 +            bcount=0;
 +        }
 +    }
 +    *d='\0';
 +    *numargs=argc;
 +
 +    return argv;
 +}
 +
 +static DWORD shgfi_get_exe_type(LPCWSTR szFullPath)
 +{
 +    BOOL status = FALSE;
 +    HANDLE hfile;
 +    DWORD BinaryType;
 +    IMAGE_DOS_HEADER mz_header;
 +    IMAGE_NT_HEADERS nt;
 +    DWORD len;
 +    char magic[4];
 +
 +    status = GetBinaryTypeW (szFullPath, &BinaryType);
 +    if (!status)
 +        return 0;
 +    if (BinaryType == SCS_DOS_BINARY || BinaryType == SCS_PIF_BINARY)
 +        return 0x4d5a;
 +
 +    hfile = CreateFileW( szFullPath, GENERIC_READ, FILE_SHARE_READ,
 +                         NULL, OPEN_EXISTING, 0, 0 );
 +    if ( hfile == INVALID_HANDLE_VALUE )
 +        return 0;
 +
 +    /*
 +     * The next section is adapted from MODULE_GetBinaryType, as we need
 +     * to examine the image header to get OS and version information. We
 +     * know from calling GetBinaryTypeA that the image is valid and either
 +     * an NE or PE, so much error handling can be omitted.
 +     * Seek to the start of the file and read the header information.
 +     */
 +
 +    SetFilePointer( hfile, 0, NULL, SEEK_SET );
 +    ReadFile( hfile, &mz_header, sizeof(mz_header), &len, NULL );
 +
 +    SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
 +    ReadFile( hfile, magic, sizeof(magic), &len, NULL );
 +
 +    if ( *(DWORD*)magic == IMAGE_NT_SIGNATURE )
 +    {
 +        SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
 +        ReadFile( hfile, &nt, sizeof(nt), &len, NULL );
 +        CloseHandle( hfile );
 +
 +        /* DLL files are not executable and should return 0 */
 +        if (nt.FileHeader.Characteristics & IMAGE_FILE_DLL)
 +            return 0;
 +
 +        if (nt.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
 +        {
 +             return IMAGE_NT_SIGNATURE |
 +                   (nt.OptionalHeader.MajorSubsystemVersion << 24) |
 +                   (nt.OptionalHeader.MinorSubsystemVersion << 16);
 +        }
 +        return IMAGE_NT_SIGNATURE;
 +    }
 +    else if ( *(WORD*)magic == IMAGE_OS2_SIGNATURE )
 +    {
 +        IMAGE_OS2_HEADER ne;
 +        SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
 +        ReadFile( hfile, &ne, sizeof(ne), &len, NULL );
 +        CloseHandle( hfile );
 +
 +        if (ne.ne_exetyp == 2)
 +            return IMAGE_OS2_SIGNATURE | (ne.ne_expver << 16);
 +        return 0;
 +    }
 +    CloseHandle( hfile );
 +    return 0;
 +}
 +
 +/*************************************************************************
 + * SHELL_IsShortcut        [internal]
 + *
 + * Decide if an item id list points to a shell shortcut
 + */
 +BOOL SHELL_IsShortcut(LPCITEMIDLIST pidlLast)
 +{
 +    char szTemp[MAX_PATH];
 +    HKEY keyCls;
 +    BOOL ret = FALSE;
 +
 +    if (_ILGetExtension(pidlLast, szTemp, MAX_PATH) &&
 +          HCR_MapTypeToValueA(szTemp, szTemp, MAX_PATH, TRUE))
 +    {
 +        if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_QUERY_VALUE, &keyCls))
 +        {
 +          if (ERROR_SUCCESS == RegQueryValueExA(keyCls, "IsShortcut", NULL, NULL, NULL, NULL))
 +            ret = TRUE;
 +
 +          RegCloseKey(keyCls);
 +        }
 +    }
 +
 +    return ret;
 +}
 +
 +#define SHGFI_KNOWN_FLAGS \
 +    (SHGFI_SMALLICON | SHGFI_OPENICON | SHGFI_SHELLICONSIZE | SHGFI_PIDL | \
 +     SHGFI_USEFILEATTRIBUTES | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX | \
 +     SHGFI_ICON | SHGFI_DISPLAYNAME | SHGFI_TYPENAME | SHGFI_ATTRIBUTES | \
 +     SHGFI_ICONLOCATION | SHGFI_EXETYPE | SHGFI_SYSICONINDEX | \
 +     SHGFI_LINKOVERLAY | SHGFI_SELECTED | SHGFI_ATTR_SPECIFIED)
 +
 +/*************************************************************************
 + * SHGetFileInfoW            [SHELL32.@]
 + *
 + */
 +DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
 +                                SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags )
 +{
 +    WCHAR szLocation[MAX_PATH], szFullPath[MAX_PATH];
 +    int iIndex;
 +    DWORD_PTR ret = TRUE;
 +    DWORD dwAttributes = 0;
 +    CComPtr<IShellFolder>        psfParent;
 +    CComPtr<IExtractIconW>        pei;
 +    LPITEMIDLIST    pidlLast = NULL, pidl = NULL;
 +    HRESULT hr = S_OK;
 +    BOOL IconNotYetLoaded=TRUE;
 +    UINT uGilFlags = 0;
 +
 +    TRACE("%s fattr=0x%x sfi=%p(attr=0x%08x) size=0x%x flags=0x%x\n",
 +          (flags & SHGFI_PIDL)? "pidl" : debugstr_w(path), dwFileAttributes,
 +          psfi, psfi->dwAttributes, sizeofpsfi, flags);
 +
 +    if (!path)
 +         return FALSE;
 +
 +    /* windows initializes these values regardless of the flags */
 +    if (psfi != NULL)
 +    {
 +        psfi->szDisplayName[0] = '\0';
 +        psfi->szTypeName[0] = '\0';
 +        psfi->iIcon = 0;
 +    }
 +
 +    if (!(flags & SHGFI_PIDL))
 +    {
 +        /* SHGetFileInfo should work with absolute and relative paths */
 +        if (PathIsRelativeW(path))
 +        {
 +            GetCurrentDirectoryW(MAX_PATH, szLocation);
 +            PathCombineW(szFullPath, szLocation, path);
 +        }
 +        else
 +        {
 +            lstrcpynW(szFullPath, path, MAX_PATH);
 +        }
 +    }
 +
 +    if (flags & SHGFI_EXETYPE)
 +    {
 +        if (flags != SHGFI_EXETYPE)
 +            return 0;
 +        return shgfi_get_exe_type(szFullPath);
 +    }
 +
 +    /*
 +     * psfi is NULL normally to query EXE type. If it is NULL, none of the
 +     * below makes sense anyway. Windows allows this and just returns FALSE
 +     */
 +    if (psfi == NULL)
 +        return FALSE;
 +
 +    /*
 +     * translate the path into a pidl only when SHGFI_USEFILEATTRIBUTES
 +     * is not specified.
 +     * The pidl functions fail on not existing file names
 +     */
 +
 +    if (flags & SHGFI_PIDL)
 +    {
 +        pidl = ILClone((LPCITEMIDLIST)path);
 +    }
 +    else if (!(flags & SHGFI_USEFILEATTRIBUTES))
 +    {
 +        hr = SHILCreateFromPathW(szFullPath, &pidl, &dwAttributes);
 +    }
 +
 +    if ((flags & SHGFI_PIDL) || !(flags & SHGFI_USEFILEATTRIBUTES))
 +    {
 +        /* get the parent shellfolder */
 +        if (pidl)
 +        {
 +            hr = SHBindToParent( pidl, IID_PPV_ARG(IShellFolder, &psfParent),
 +                                (LPCITEMIDLIST*)&pidlLast );
 +            if (SUCCEEDED(hr))
 +                pidlLast = ILClone(pidlLast);
 +            ILFree(pidl);
 +        }
 +        else
 +        {
 +            ERR("pidl is null!\n");
 +            return FALSE;
 +        }
 +    }
 +
 +    /* get the attributes of the child */
 +    if (SUCCEEDED(hr) && (flags & SHGFI_ATTRIBUTES))
 +    {
 +        if (!(flags & SHGFI_ATTR_SPECIFIED))
 +        {
 +            psfi->dwAttributes = 0xffffffff;
 +        }
 +        if (psfParent != NULL)
 +            psfParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlLast,
 +                                      &(psfi->dwAttributes) );
 +    }
 +
 +    /* get the displayname */
 +    if (SUCCEEDED(hr) && (flags & SHGFI_DISPLAYNAME))
 +    {
 +        if (flags & SHGFI_USEFILEATTRIBUTES)
 +        {
 +            wcscpy (psfi->szDisplayName, PathFindFileNameW(szFullPath));
 +        }
 +        else
 +        {
 +            STRRET str;
 +            hr = psfParent->GetDisplayNameOf(pidlLast,
 +                                                SHGDN_INFOLDER, &str);
 +            StrRetToStrNW (psfi->szDisplayName, MAX_PATH, &str, pidlLast);
 +        }
 +    }
 +
 +    /* get the type name */
 +    if (SUCCEEDED(hr) && (flags & SHGFI_TYPENAME))
 +    {
 +        static const WCHAR szFile[] = { 'F','i','l','e',0 };
 +        static const WCHAR szDashFile[] = { '-','f','i','l','e',0 };
 +
 +        if (!(flags & SHGFI_USEFILEATTRIBUTES))
 +        {
 +            char ftype[80];
 +
 +            _ILGetFileType(pidlLast, ftype, 80);
 +            MultiByteToWideChar(CP_ACP, 0, ftype, -1, psfi->szTypeName, 80 );
 +        }
 +        else
 +        {
 +            if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 +                wcscat (psfi->szTypeName, szFile);
 +            else
 +            {
 +                WCHAR sTemp[64];
 +
 +                wcscpy(sTemp,PathFindExtensionW(szFullPath));
 +                if (!( HCR_MapTypeToValueW(sTemp, sTemp, 64, TRUE) &&
 +                    HCR_MapTypeToValueW(sTemp, psfi->szTypeName, 80, FALSE )))
 +                {
 +                    lstrcpynW (psfi->szTypeName, sTemp, 64);
 +                    wcscat (psfi->szTypeName, szDashFile);
 +                }
 +            }
 +        }
 +    }
 +
 +    /* ### icons ###*/
 +    if (flags & SHGFI_OPENICON)
 +        uGilFlags |= GIL_OPENICON;
 +
 +    if (flags & SHGFI_LINKOVERLAY)
 +        uGilFlags |= GIL_FORSHORTCUT;
 +    else if ((flags&SHGFI_ADDOVERLAYS) ||
 +             (flags&(SHGFI_ICON|SHGFI_SMALLICON))==SHGFI_ICON)
 +    {
 +        if (SHELL_IsShortcut(pidlLast))
 +            uGilFlags |= GIL_FORSHORTCUT;
 +    }
 +
 +    if (flags & SHGFI_OVERLAYINDEX)
 +        FIXME("SHGFI_OVERLAYINDEX unhandled\n");
 +
 +    if (flags & SHGFI_SELECTED)
 +        FIXME("set icon to selected, stub\n");
 +
 +    if (flags & SHGFI_SHELLICONSIZE)
 +        FIXME("set icon to shell size, stub\n");
 +
 +    /* get the iconlocation */
 +    if (SUCCEEDED(hr) && (flags & SHGFI_ICONLOCATION ))
 +    {
 +        UINT uFlags;
 +
 +        if (flags & SHGFI_USEFILEATTRIBUTES)
 +        {
 +            if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 +            {
 +                wcscpy(psfi->szDisplayName, swShell32Name);
 +                psfi->iIcon = -IDI_SHELL_FOLDER;
 +            }
 +            else
 +            {
 +                WCHAR* szExt;
 +                static const WCHAR p1W[] = {'%','1',0};
 +                WCHAR sTemp [MAX_PATH];
 +
 +                szExt = PathFindExtensionW(szFullPath);
 +                TRACE("szExt=%s\n", debugstr_w(szExt));
 +                if ( szExt &&
 +                     HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) &&
 +                     HCR_GetIconW(sTemp, sTemp, NULL, MAX_PATH, &psfi->iIcon))
 +                {
 +                    if (lstrcmpW(p1W, sTemp))
 +                        wcscpy(psfi->szDisplayName, sTemp);
 +                    else
 +                    {
 +                        /* the icon is in the file */
 +                        wcscpy(psfi->szDisplayName, szFullPath);
 +                    }
 +                }
 +                else
 +                    ret = FALSE;
 +            }
 +        }
 +        else
 +        {
 +            hr = psfParent->GetUIObjectOf(0, 1,
 +                (LPCITEMIDLIST*)&pidlLast, IID_NULL_PPV_ARG(IExtractIconW, &pei));
 +            if (SUCCEEDED(hr))
 +            {
 +                hr = pei->GetIconLocation(uGilFlags,
 +                    szLocation, MAX_PATH, &iIndex, &uFlags);
 +
 +                if (uFlags & GIL_NOTFILENAME)
 +                    ret = FALSE;
 +                else
 +                {
 +                    wcscpy (psfi->szDisplayName, szLocation);
 +                    psfi->iIcon = iIndex;
 +                }
 +            }
 +        }
 +    }
 +
 +    /* get icon index (or load icon)*/
 +    if (SUCCEEDED(hr) && (flags & (SHGFI_ICON | SHGFI_SYSICONINDEX)))
 +    {
 +        if (flags & SHGFI_USEFILEATTRIBUTES && !(flags & SHGFI_PIDL))
 +        {
 +            WCHAR sTemp [MAX_PATH];
 +            WCHAR * szExt;
 +            int icon_idx=0;
 +
 +            lstrcpynW(sTemp, szFullPath, MAX_PATH);
 +
 +            if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 +                psfi->iIcon = SIC_GetIconIndex(swShell32Name, -IDI_SHELL_FOLDER, 0);
 +            else
 +            {
 +                static const WCHAR p1W[] = {'%','1',0};
 +
 +                psfi->iIcon = 0;
 +                szExt = PathFindExtensionW(sTemp);
 +                if ( szExt &&
 +                     HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) &&
 +                     HCR_GetIconW(sTemp, sTemp, NULL, MAX_PATH, &icon_idx))
 +                {
 +                    if (!lstrcmpW(p1W,sTemp))            /* icon is in the file */
 +                        wcscpy(sTemp, szFullPath);
 +
 +                    if (flags & SHGFI_SYSICONINDEX)
 +                    {
 +                        psfi->iIcon = SIC_GetIconIndex(sTemp,icon_idx,0);
 +                        if (psfi->iIcon == -1)
 +                            psfi->iIcon = 0;
 +                    }
 +                    else
 +                    {
 +                        UINT ret;
 +                        if (flags & SHGFI_SMALLICON)
 +                            ret = PrivateExtractIconsW( sTemp,icon_idx,
 +                                GetSystemMetrics( SM_CXSMICON ),
 +                                GetSystemMetrics( SM_CYSMICON ),
 +                                &psfi->hIcon, 0, 1, 0);
 +                        else
 +                            ret = PrivateExtractIconsW( sTemp, icon_idx,
 +                                GetSystemMetrics( SM_CXICON),
 +                                GetSystemMetrics( SM_CYICON),
 +                                &psfi->hIcon, 0, 1, 0);
 +
 +                        if (ret != 0 && ret != 0xFFFFFFFF)
 +                        {
 +                            IconNotYetLoaded=FALSE;
 +                            psfi->iIcon = icon_idx;
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +        else
 +        {
 +            if (!(PidlToSicIndex(psfParent, pidlLast, !(flags & SHGFI_SMALLICON),
 +                uGilFlags, &(psfi->iIcon))))
 +            {
 +                ret = FALSE;
 +            }
 +        }
 +        if (ret && (flags & SHGFI_SYSICONINDEX))
 +        {
 +            if (flags & SHGFI_SMALLICON)
 +                ret = (DWORD_PTR) ShellSmallIconList;
 +            else
 +                ret = (DWORD_PTR) ShellBigIconList;
 +        }
 +    }
 +
 +    /* icon handle */
 +    if (SUCCEEDED(hr) && (flags & SHGFI_ICON) && IconNotYetLoaded)
 +    {
 +        if (flags & SHGFI_SMALLICON)
 +            psfi->hIcon = ImageList_GetIcon( ShellSmallIconList, psfi->iIcon, ILD_NORMAL);
 +        else
 +            psfi->hIcon = ImageList_GetIcon( ShellBigIconList, psfi->iIcon, ILD_NORMAL);
 +    }
 +
 +    if (flags & ~SHGFI_KNOWN_FLAGS)
 +        FIXME("unknown flags %08x\n", flags & ~SHGFI_KNOWN_FLAGS);
 +
 +    if (hr != S_OK)
 +        ret = FALSE;
 +
 +    SHFree(pidlLast);
 +
 +#ifdef MORE_DEBUG
 +    TRACE ("icon=%p index=0x%08x attr=0x%08x name=%s type=%s ret=0x%08lx\n",
 +           psfi->hIcon, psfi->iIcon, psfi->dwAttributes,
 +           debugstr_w(psfi->szDisplayName), debugstr_w(psfi->szTypeName), ret);
 +#endif
 +
 +    return ret;
 +}
 +
 +/*************************************************************************
 + * SHGetFileInfoA            [SHELL32.@]
 + *
 + * Note:
 + *    MSVBVM60.__vbaNew2 expects this function to return a value in range
 + *    1 .. 0x7fff when the function succeeds and flags does not contain
 + *    SHGFI_EXETYPE or SHGFI_SYSICONINDEX (see bug 7701)
 + */
 +DWORD_PTR WINAPI SHGetFileInfoA(LPCSTR path,DWORD dwFileAttributes,
 +                                SHFILEINFOA *psfi, UINT sizeofpsfi,
 +                                UINT flags )
 +{
 +    INT len;
 +    LPWSTR temppath = NULL;
 +    LPCWSTR pathW;
 +    DWORD ret;
 +    SHFILEINFOW temppsfi;
 +
 +    if (flags & SHGFI_PIDL)
 +    {
 +        /* path contains a pidl */
 +        pathW = (LPCWSTR)path;
 +    }
 +    else
 +    {
 +        len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
 +        temppath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
 +        MultiByteToWideChar(CP_ACP, 0, path, -1, temppath, len);
 +        pathW = temppath;
 +    }
 +
 +    if (psfi && (flags & SHGFI_ATTR_SPECIFIED))
 +        temppsfi.dwAttributes=psfi->dwAttributes;
 +
 +    if (psfi == NULL)
 +        ret = SHGetFileInfoW(pathW, dwFileAttributes, NULL, sizeof(temppsfi), flags);
 +    else
 +        ret = SHGetFileInfoW(pathW, dwFileAttributes, &temppsfi, sizeof(temppsfi), flags);
 +
 +    if (psfi)
 +    {
 +        if(flags & SHGFI_ICON)
 +            psfi->hIcon=temppsfi.hIcon;
 +        if(flags & (SHGFI_SYSICONINDEX|SHGFI_ICON|SHGFI_ICONLOCATION))
 +            psfi->iIcon=temppsfi.iIcon;
 +        if(flags & SHGFI_ATTRIBUTES)
 +            psfi->dwAttributes=temppsfi.dwAttributes;
 +        if(flags & (SHGFI_DISPLAYNAME|SHGFI_ICONLOCATION))
 +        {
 +            WideCharToMultiByte(CP_ACP, 0, temppsfi.szDisplayName, -1,
 +                  psfi->szDisplayName, sizeof(psfi->szDisplayName), NULL, NULL);
 +        }
 +        if(flags & SHGFI_TYPENAME)
 +        {
 +            WideCharToMultiByte(CP_ACP, 0, temppsfi.szTypeName, -1,
 +                  psfi->szTypeName, sizeof(psfi->szTypeName), NULL, NULL);
 +        }
 +    }
 +
 +    HeapFree(GetProcessHeap(), 0, temppath);
 +
 +    return ret;
 +}
 +
 +/*************************************************************************
 + * DuplicateIcon            [SHELL32.@]
 + */
 +EXTERN_C HICON WINAPI DuplicateIcon( HINSTANCE hInstance, HICON hIcon)
 +{
 +    ICONINFO IconInfo;
 +    HICON hDupIcon = 0;
 +
 +    TRACE("%p %p\n", hInstance, hIcon);
 +
 +    if (GetIconInfo(hIcon, &IconInfo))
 +    {
 +        hDupIcon = CreateIconIndirect(&IconInfo);
 +
 +        /* clean up hbmMask and hbmColor */
 +        DeleteObject(IconInfo.hbmMask);
 +        DeleteObject(IconInfo.hbmColor);
 +    }
 +
 +    return hDupIcon;
 +}
 +
 +/*************************************************************************
 + * ExtractIconA                [SHELL32.@]
 + */
 +HICON WINAPI ExtractIconA(HINSTANCE hInstance, LPCSTR lpszFile, UINT nIconIndex)
 +{
 +    HICON ret;
 +    INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
 +    LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +
 +    TRACE("%p %s %d\n", hInstance, lpszFile, nIconIndex);
 +
 +    MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
 +    ret = ExtractIconW(hInstance, lpwstrFile, nIconIndex);
 +    HeapFree(GetProcessHeap(), 0, lpwstrFile);
 +
 +    return ret;
 +}
 +
 +/*************************************************************************
 + * ExtractIconW                [SHELL32.@]
 + */
 +HICON WINAPI ExtractIconW(HINSTANCE hInstance, LPCWSTR lpszFile, UINT nIconIndex)
 +{
 +    HICON  hIcon = NULL;
 +    UINT ret;
 +    UINT cx = GetSystemMetrics(SM_CXICON), cy = GetSystemMetrics(SM_CYICON);
 +
 +    TRACE("%p %s %d\n", hInstance, debugstr_w(lpszFile), nIconIndex);
 +
 +    if (nIconIndex == 0xFFFFFFFF)
 +    {
 +        ret = PrivateExtractIconsW(lpszFile, 0, cx, cy, NULL, NULL, 0, LR_DEFAULTCOLOR);
 +        if (ret != 0xFFFFFFFF && ret)
 +            return (HICON)(UINT_PTR)ret;
 +        return NULL;
 +    }
 +    else
 +        ret = PrivateExtractIconsW(lpszFile, nIconIndex, cx, cy, &hIcon, NULL, 1, LR_DEFAULTCOLOR);
 +
 +    if (ret == 0xFFFFFFFF)
 +        return (HICON)1;
 +    else if (ret > 0 && hIcon)
 +        return hIcon;
 +
 +    return NULL;
 +}
 +
 +/*************************************************************************
 + * Printer_LoadIconsW        [SHELL32.205]
 + */
 +EXTERN_C VOID WINAPI Printer_LoadIconsW(LPCWSTR wsPrinterName, HICON * pLargeIcon, HICON * pSmallIcon)
 +{
 +    INT iconindex=IDI_SHELL_PRINTERS_FOLDER;
 +
 +    TRACE("(%s, %p, %p)\n", debugstr_w(wsPrinterName), pLargeIcon, pSmallIcon);
 +
 +    /* We should check if wsPrinterName is
 +       1. the Default Printer or not
 +       2. connected or not
 +       3. a Local Printer or a Network-Printer
 +       and use different Icons
 +    */
 +    if((wsPrinterName != NULL) && (wsPrinterName[0] != 0))
 +    {
 +        FIXME("(select Icon by PrinterName %s not implemented)\n", debugstr_w(wsPrinterName));
 +    }
 +
 +    if(pLargeIcon != NULL)
 +        *pLargeIcon = (HICON)LoadImageW(shell32_hInstance,
 +                                 (LPCWSTR) MAKEINTRESOURCE(iconindex), IMAGE_ICON,
 +                                 0, 0, LR_DEFAULTCOLOR|LR_DEFAULTSIZE);
 +
 +    if(pSmallIcon != NULL)
 +        *pSmallIcon = (HICON)LoadImageW(shell32_hInstance,
 +                                 (LPCWSTR) MAKEINTRESOURCE(iconindex), IMAGE_ICON,
 +                                 16, 16, LR_DEFAULTCOLOR);
 +}
 +
 +/*************************************************************************
 + * Printers_RegisterWindowW        [SHELL32.213]
 + * used by "printui.dll":
 + * find the Window of the given Type for the specific Printer and
 + * return the already existent hwnd or open a new window
 + */
 +EXTERN_C BOOL WINAPI Printers_RegisterWindowW(LPCWSTR wsPrinter, DWORD dwType,
 +            HANDLE * phClassPidl, HWND * phwnd)
 +{
 +    FIXME("(%s, %x, %p (%p), %p (%p)) stub!\n", debugstr_w(wsPrinter), dwType,
 +                phClassPidl, (phClassPidl != NULL) ? *(phClassPidl) : NULL,
 +                phwnd, (phwnd != NULL) ? *(phwnd) : NULL);
 +
 +    return FALSE;
 +}
 +
 +/*************************************************************************
 + * Printers_UnregisterWindow      [SHELL32.214]
 + */
 +EXTERN_C VOID WINAPI Printers_UnregisterWindow(HANDLE hClassPidl, HWND hwnd)
 +{
 +    FIXME("(%p, %p) stub!\n", hClassPidl, hwnd);
 +}
 +
 +/*************************************************************************/
 +
 +typedef struct
 +{
 +    LPCWSTR  szApp;
 +    LPCWSTR  szOtherStuff;
 +    HICON hIcon;
 +} ABOUT_INFO;
 +
 +#define DROP_FIELD_TOP    (-15)
 +#define DROP_FIELD_HEIGHT  15
 +
 +/*************************************************************************
 + * SHAppBarMessage            [SHELL32.@]
 + */
 +UINT_PTR WINAPI SHAppBarMessage(DWORD msg, PAPPBARDATA data)
 +{
 +    int width=data->rc.right - data->rc.left;
 +    int height=data->rc.bottom - data->rc.top;
 +    RECT rec=data->rc;
 +
 +    TRACE("msg=%d, data={cb=%d, hwnd=%p, callback=%x, edge=%d, rc=%s, lparam=%lx}\n",
 +          msg, data->cbSize, data->hWnd, data->uCallbackMessage, data->uEdge,
 +          wine_dbgstr_rect(&data->rc), data->lParam);
 +
 +    switch (msg)
 +    {
 +        case ABM_GETSTATE:
 +            return ABS_ALWAYSONTOP | ABS_AUTOHIDE;
 +
 +        case ABM_GETTASKBARPOS:
 +            GetWindowRect(data->hWnd, &rec);
 +            data->rc=rec;
 +            return TRUE;
 +
 +        case ABM_ACTIVATE:
 +            SetActiveWindow(data->hWnd);
 +            return TRUE;
 +
 +        case ABM_GETAUTOHIDEBAR:
 +            return 0; /* pretend there is no autohide bar */
 +
 +        case ABM_NEW:
 +            /* cbSize, hWnd, and uCallbackMessage are used. All other ignored */
 +            SetWindowPos(data->hWnd,HWND_TOP,0,0,0,0,SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE);
 +            return TRUE;
 +
 +        case ABM_QUERYPOS:
 +            GetWindowRect(data->hWnd, &(data->rc));
 +            return TRUE;
 +
 +        case ABM_REMOVE:
 +            FIXME("ABM_REMOVE broken\n");
 +            /* FIXME: this is wrong; should it be DestroyWindow instead? */
 +            /*CloseHandle(data->hWnd);*/
 +            return TRUE;
 +
 +        case ABM_SETAUTOHIDEBAR:
 +            SetWindowPos(data->hWnd,HWND_TOP,rec.left+1000,rec.top,
 +                             width,height,SWP_SHOWWINDOW);
 +            return TRUE;
 +
 +        case ABM_SETPOS:
 +            data->uEdge=(ABE_RIGHT | ABE_LEFT);
 +            SetWindowPos(data->hWnd,HWND_TOP,data->rc.left,data->rc.top,
 +                         width,height,SWP_SHOWWINDOW);
 +            return TRUE;
 +
 +        case ABM_WINDOWPOSCHANGED:
 +            return TRUE;
 +    }
 +
 +    return FALSE;
 +}
 +
 +/*************************************************************************
 + * SHHelpShortcuts_RunDLLA        [SHELL32.@]
 + *
 + */
 +EXTERN_C DWORD WINAPI SHHelpShortcuts_RunDLLA(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
 +{
 +    FIXME("(%x, %x, %x, %x) stub!\n", dwArg1, dwArg2, dwArg3, dwArg4);
 +    return 0;
 +}
 +
 +/*************************************************************************
 + * SHHelpShortcuts_RunDLLA        [SHELL32.@]
 + *
 + */
 +EXTERN_C DWORD WINAPI SHHelpShortcuts_RunDLLW(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
 +{
 +    FIXME("(%x, %x, %x, %x) stub!\n", dwArg1, dwArg2, dwArg3, dwArg4);
 +    return 0;
 +}
 +
 +/*************************************************************************
 + * SHLoadInProc                [SHELL32.@]
 + * Create an instance of specified object class from within
 + * the shell process and release it immediately
 + */
 +EXTERN_C HRESULT WINAPI SHLoadInProc (REFCLSID rclsid)
 +{
 +    CComPtr<IUnknown>            ptr;
 +
 +    TRACE("%s\n", debugstr_guid(&rclsid));
 +
 +    CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&ptr);
 +    if (ptr)
 +        return S_OK;
 +    return DISP_E_MEMBERNOTFOUND;
 +}
 +
 +static VOID SetRegTextData(HWND hWnd, HKEY hKey, LPCWSTR Value, UINT uID)
 +{
 +    DWORD dwBufferSize;
 +    DWORD dwType;
 +    LPWSTR lpBuffer;
 +
 +    if( RegQueryValueExW(hKey, Value, NULL, &dwType, NULL, &dwBufferSize) == ERROR_SUCCESS )
 +    {
 +        if(dwType == REG_SZ)
 +        {
 +            lpBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
 +
 +            if(lpBuffer)
 +            {
 +                if( RegQueryValueExW(hKey, Value, NULL, &dwType, (LPBYTE)lpBuffer, &dwBufferSize) == ERROR_SUCCESS )
 +                {
 +                    SetDlgItemTextW(hWnd, uID, lpBuffer);
 +                }
 +
 +                HeapFree(GetProcessHeap(), 0, lpBuffer);
 +            }
 +        }
 +    }
 +}
 +
 +INT_PTR CALLBACK AboutAuthorsDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
 +{
 +    switch(msg)
 +    {
 +        case WM_INITDIALOG:
 +        {
 +            const char* const *pstr = SHELL_Authors;
 +
 +            // Add the authors to the list
 +            SendDlgItemMessageW( hWnd, IDC_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, FALSE, 0 );
 +
 +            while (*pstr)
 +            {
 +                WCHAR name[64];
 +
 +                /* authors list is in utf-8 format */
 +                MultiByteToWideChar( CP_UTF8, 0, *pstr, -1, name, sizeof(name)/sizeof(WCHAR) );
 +                SendDlgItemMessageW( hWnd, IDC_ABOUT_AUTHORS_LISTBOX, LB_ADDSTRING, (WPARAM)-1, (LPARAM)name );
 +                pstr++;
 +            }
 +
 +            SendDlgItemMessageW( hWnd, IDC_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, TRUE, 0 );
 +
 +            return TRUE;
 +        }
 +    }
 +
 +    return FALSE;
 +}
 +/*************************************************************************
 + * AboutDlgProc            (internal)
 + */
++static INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
 +{
 +    static DWORD   cxLogoBmp;
 +    static DWORD   cyLogoBmp;
 +    static HBITMAP hLogoBmp;
 +    static HWND    hWndAuthors;
 +
 +    switch(msg)
 +    {
 +        case WM_INITDIALOG:
 +        {
 +            ABOUT_INFO *info = (ABOUT_INFO *)lParam;
 +
 +            if (info)
 +            {
 +                const WCHAR szRegKey[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
 +                HKEY hRegKey;
 +                MEMORYSTATUSEX MemStat;
 +                WCHAR szAppTitle[512];
 +                WCHAR szAppTitleTemplate[512];
 +                WCHAR szAuthorsText[20];
 +
 +                // Preload the ROS bitmap
 +                hLogoBmp = (HBITMAP)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDB_REACTOS), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
 +
 +                if(hLogoBmp)
 +                {
 +                    BITMAP bmpLogo;
 +
 +                    GetObject( hLogoBmp, sizeof(BITMAP), &bmpLogo );
 +
 +                    cxLogoBmp = bmpLogo.bmWidth;
 +                    cyLogoBmp = bmpLogo.bmHeight;
 +                }
 +
 +                // Set App-specific stuff (icon, app name, szOtherStuff string)
 +                SendDlgItemMessageW(hWnd, IDC_ABOUT_ICON, STM_SETICON, (WPARAM)info->hIcon, 0);
 +
 +                GetWindowTextW( hWnd, szAppTitleTemplate, sizeof(szAppTitleTemplate) / sizeof(WCHAR) );
 +                swprintf( szAppTitle, szAppTitleTemplate, info->szApp );
 +                SetWindowTextW( hWnd, szAppTitle );
 +
 +                SetDlgItemTextW( hWnd, IDC_ABOUT_APPNAME, info->szApp );
 +                SetDlgItemTextW( hWnd, IDC_ABOUT_OTHERSTUFF, info->szOtherStuff );
 +
 +                // Set the registered user and organization name
 +                if(RegOpenKeyExW( HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_QUERY_VALUE, &hRegKey ) == ERROR_SUCCESS)
 +                {
 +                    SetRegTextData( hWnd, hRegKey, L"RegisteredOwner", IDC_ABOUT_REG_USERNAME );
 +                    SetRegTextData( hWnd, hRegKey, L"RegisteredOrganization", IDC_ABOUT_REG_ORGNAME );
 +
 +                    RegCloseKey( hRegKey );
 +                }
 +
 +                // Set the value for the installed physical memory
 +                MemStat.dwLength = sizeof(MemStat);
 +                if( GlobalMemoryStatusEx(&MemStat) )
 +                {
 +                    WCHAR szBuf[12];
 +
 +                    if (MemStat.ullTotalPhys > 1024 * 1024 * 1024)
 +                    {
 +                        double dTotalPhys;
 +                        WCHAR szDecimalSeparator[4];
 +                        WCHAR szUnits[3];
 +
 +                        // We're dealing with GBs or more
 +                        MemStat.ullTotalPhys /= 1024 * 1024;
 +
 +                        if (MemStat.ullTotalPhys > 1024 * 1024)
 +                        {
 +                            // We're dealing with TBs or more
 +                            MemStat.ullTotalPhys /= 1024;
 +
 +                            if (MemStat.ullTotalPhys > 1024 * 1024)
 +                            {
 +                                // We're dealing with PBs or more
 +                                MemStat.ullTotalPhys /= 1024;
 +
 +                                dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
 +                                wcscpy( szUnits, L"PB" );
 +                            }
 +                            else
 +                            {
 +                                dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
 +                                wcscpy( szUnits, L"TB" );
 +                            }
 +                        }
 +                        else
 +                        {
 +                            dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
 +                            wcscpy( szUnits, L"GB" );
 +                        }
 +
 +                        // We need the decimal point of the current locale to display the RAM size correctly
 +                        if (GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
 +                            szDecimalSeparator,
 +                            sizeof(szDecimalSeparator) / sizeof(WCHAR)) > 0)
 +                        {
 +                            UCHAR uDecimals;
 +                            UINT uIntegral;
 +
 +                            uIntegral = (UINT)dTotalPhys;
 +                            uDecimals = (UCHAR)((UINT)(dTotalPhys * 100) - uIntegral * 100);
 +
 +                            // Display the RAM size with 2 decimals
 +                            swprintf(szBuf, L"%u%s%02u %s", uIntegral, szDecimalSeparator, uDecimals, szUnits);
 +                        }
 +                    }
 +                    else
 +                    {
 +                        // We're dealing with MBs, don't show any decimals
 +                        swprintf( szBuf, L"%u MB", (UINT)MemStat.ullTotalPhys / 1024 / 1024 );
 +                    }
 +
 +                    SetDlgItemTextW( hWnd, IDC_ABOUT_PHYSMEM, szBuf);
 +                }
 +
 +                // Add the Authors dialog
 +                hWndAuthors = CreateDialogW( shell32_hInstance, MAKEINTRESOURCEW(IDD_ABOUT_AUTHORS), hWnd, AboutAuthorsDlgProc );
 +                LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_AUTHORS, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) );
 +                SetDlgItemTextW( hWnd, IDC_ABOUT_AUTHORS, szAuthorsText );
 +            }
 +
 +            return TRUE;
 +        }
 +
 +        case WM_PAINT:
 +        {
 +            if(hLogoBmp)
 +            {
 +                PAINTSTRUCT ps;
 +                HDC hdc;
 +                HDC hdcMem;
 +
 +                hdc = BeginPaint(hWnd, &ps);
 +                hdcMem = CreateCompatibleDC(hdc);
 +
 +                if(hdcMem)
 +                {
 +                    SelectObject(hdcMem, hLogoBmp);
 +                    BitBlt(hdc, 0, 0, cxLogoBmp, cyLogoBmp, hdcMem, 0, 0, SRCCOPY);
 +
 +                    DeleteDC(hdcMem);
 +                }
 +
 +                EndPaint(hWnd, &ps);
 +            }
 +        }; break;
 +
 +        case WM_COMMAND:
 +        {
 +            switch(wParam)
 +            {
 +                case IDOK:
 +                case IDCANCEL:
 +                    EndDialog(hWnd, TRUE);
 +                    return TRUE;
 +
 +                case IDC_ABOUT_AUTHORS:
 +                {
 +                    static BOOL bShowingAuthors = FALSE;
 +                    WCHAR szAuthorsText[20];
 +
 +                    if(bShowingAuthors)
 +                    {
 +                        LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_AUTHORS, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) );
 +                        ShowWindow( hWndAuthors, SW_HIDE );
 +                    }
 +                    else
 +                    {
 +                        LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_BACK, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) );
 +                        ShowWindow( hWndAuthors, SW_SHOW );
 +                    }
 +
 +                    SetDlgItemTextW( hWnd, IDC_ABOUT_AUTHORS, szAuthorsText );
 +                    bShowingAuthors = !bShowingAuthors;
 +                    return TRUE;
 +                }
 +            }
 +        }; break;
 +
 +        case WM_CLOSE:
 +            EndDialog(hWnd, TRUE);
 +            break;
 +    }
 +
 +    return FALSE;
 +}
 +
 +
 +/*************************************************************************
 + * ShellAboutA                [SHELL32.288]
 + */
 +BOOL WINAPI ShellAboutA( HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon )
 +{
 +    BOOL ret;
 +    LPWSTR appW = NULL, otherW = NULL;
 +    int len;
 +
 +    if (szApp)
 +    {
 +        len = MultiByteToWideChar(CP_ACP, 0, szApp, -1, NULL, 0);
 +        appW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +        MultiByteToWideChar(CP_ACP, 0, szApp, -1, appW, len);
 +    }
 +    if (szOtherStuff)
 +    {
 +        len = MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, NULL, 0);
 +        otherW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +        MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, otherW, len);
 +    }
 +
 +    ret = ShellAboutW(hWnd, appW, otherW, hIcon);
 +
 +    HeapFree(GetProcessHeap(), 0, otherW);
 +    HeapFree(GetProcessHeap(), 0, appW);
 +    return ret;
 +}
 +
 +
 +/*************************************************************************
 + * ShellAboutW                [SHELL32.289]
 + */
 +BOOL WINAPI ShellAboutW( HWND hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
 +                         HICON hIcon )
 +{
 +    ABOUT_INFO info;
 +    HRSRC hRes;
 +    DLGTEMPLATE *DlgTemplate;
 +    BOOL bRet;
 +
 +    TRACE("\n");
 +
 +    // DialogBoxIndirectParamW will be called with the hInstance of the calling application, so we have to preload the dialog template
 +    hRes = FindResourceW(shell32_hInstance, MAKEINTRESOURCEW(IDD_ABOUT), (LPWSTR)RT_DIALOG);
 +    if(!hRes)
 +        return FALSE;
 +
 +    DlgTemplate = (DLGTEMPLATE *)LoadResource(shell32_hInstance, hRes);
 +    if(!DlgTemplate)
 +        return FALSE;
 +
 +    info.szApp        = szApp;
 +    info.szOtherStuff = szOtherStuff;
 +    info.hIcon        = hIcon ? hIcon : LoadIconW( 0, (LPWSTR)IDI_WINLOGO );
 +
 +    bRet = DialogBoxIndirectParamW((HINSTANCE)GetWindowLongPtrW( hWnd, GWLP_HINSTANCE ),
 +                                   DlgTemplate, hWnd, AboutDlgProc, (LPARAM)&info );
 +    return bRet;
 +}
 +
 +/*************************************************************************
 + * FreeIconList (SHELL32.@)
 + */
 +EXTERN_C void WINAPI FreeIconList( DWORD dw )
 +{
 +    FIXME("%x: stub\n",dw);
 +}
 +
 +/*************************************************************************
 + * SHLoadNonloadedIconOverlayIdentifiers (SHELL32.@)
 + */
 +EXTERN_C HRESULT WINAPI SHLoadNonloadedIconOverlayIdentifiers(VOID)
 +{
 +    FIXME("stub\n");
 +    return S_OK;
 +}
 +
 +class CShell32Module : public CComModule
 +{
 +public:
 +};
 +
 +
 +BEGIN_OBJECT_MAP(ObjectMap)
 +    OBJECT_ENTRY(CLSID_ShellFSFolder, CFSFolder)
 +    OBJECT_ENTRY(CLSID_MyComputer, CDrivesFolder)
 +    OBJECT_ENTRY(CLSID_ShellDesktop, CDesktopFolder)
 +    OBJECT_ENTRY(CLSID_ShellItem, CShellItem)
 +    OBJECT_ENTRY(CLSID_ShellLink, CShellLink)
 +    OBJECT_ENTRY(CLSID_DragDropHelper, CDropTargetHelper)
 +    OBJECT_ENTRY(CLSID_ControlPanel, CControlPanelFolder)
 +    OBJECT_ENTRY(CLSID_AutoComplete, CAutoComplete)
 +    OBJECT_ENTRY(CLSID_MyDocuments, CMyDocsFolder)
 +    OBJECT_ENTRY(CLSID_NetworkPlaces, CNetFolder)
 +    OBJECT_ENTRY(CLSID_FontsFolderShortcut, CFontsFolder)
 +    OBJECT_ENTRY(CLSID_Printers, CPrinterFolder)
 +    OBJECT_ENTRY(CLSID_AdminFolderShortcut, CAdminToolsFolder)
 +    OBJECT_ENTRY(CLSID_RecycleBin, CRecycleBin)
 +    OBJECT_ENTRY(CLSID_OpenWithMenu, COpenWithMenu)
 +    OBJECT_ENTRY(CLSID_NewMenu, CNewMenu)
 +    OBJECT_ENTRY(CLSID_StartMenu, CStartMenu)
 +    OBJECT_ENTRY(CLSID_MenuBandSite, CMenuBandSite)
 +    OBJECT_ENTRY(CLSID_MenuBand, CMenuBand)
 +    OBJECT_ENTRY(CLSID_MenuDeskBar, CMenuDeskBar)
 +    OBJECT_ENTRY(CLSID_ExeDropHandler, CExeDropHandler)
 +END_OBJECT_MAP()
 +
 +CShell32Module                                gModule;
 +
 +
 +/***********************************************************************
 + * DllGetVersion [SHELL32.@]
 + *
 + * Retrieves version information of the 'SHELL32.DLL'
 + *
 + * PARAMS
 + *     pdvi [O] pointer to version information structure.
 + *
 + * RETURNS
 + *     Success: S_OK
 + *     Failure: E_INVALIDARG
 + *
 + * NOTES
 + *     Returns version of a shell32.dll from IE4.01 SP1.
 + */
 +
 +STDAPI DllGetVersion(DLLVERSIONINFO *pdvi)
 +{
 +    /* FIXME: shouldn't these values come from the version resource? */
 +    if (pdvi->cbSize == sizeof(DLLVERSIONINFO) ||
 +        pdvi->cbSize == sizeof(DLLVERSIONINFO2))
 +    {
 +        pdvi->dwMajorVersion = WINE_FILEVERSION_MAJOR;
 +        pdvi->dwMinorVersion = WINE_FILEVERSION_MINOR;
 +        pdvi->dwBuildNumber = WINE_FILEVERSION_BUILD;
 +        pdvi->dwPlatformID = WINE_FILEVERSION_PLATFORMID;
 +        if (pdvi->cbSize == sizeof(DLLVERSIONINFO2))
 +        {
 +            DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2 *)pdvi;
 +
 +            pdvi2->dwFlags = 0;
 +            pdvi2->ullVersion = MAKEDLLVERULL(WINE_FILEVERSION_MAJOR,
 +                                              WINE_FILEVERSION_MINOR,
 +                                              WINE_FILEVERSION_BUILD,
 +                                              WINE_FILEVERSION_PLATFORMID);
 +        }
 +        TRACE("%u.%u.%u.%u\n",
 +              pdvi->dwMajorVersion, pdvi->dwMinorVersion,
 +              pdvi->dwBuildNumber, pdvi->dwPlatformID);
 +        return S_OK;
 +    }
 +    else
 +    {
 +        WARN("wrong DLLVERSIONINFO size from app\n");
 +        return E_INVALIDARG;
 +    }
 +}
 +
 +/*************************************************************************
 + * global variables of the shell32.dll
 + * all are once per process
 + *
 + */
 +HINSTANCE    shell32_hInstance;
 +HIMAGELIST   ShellSmallIconList = 0;
 +HIMAGELIST   ShellBigIconList = 0;
 +
 +void *operator new (size_t, void *buf)
 +{
 +    return buf;
 +}
 +
 +/*************************************************************************
 + * SHELL32 DllMain
 + *
 + * NOTES
 + *  calling oleinitialize here breaks sone apps.
 + */
 +STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad)
 +{
 +    TRACE("%p 0x%x %p\n", hInstance, dwReason, fImpLoad);
 +    if (dwReason == DLL_PROCESS_ATTACH)
 +    {
 +        /* HACK - the global constructors don't run, so I placement new them here */
 +        new (&gModule) CShell32Module;
 +        new (&_AtlWinModule) CAtlWinModule;
 +        new (&_AtlBaseModule) CAtlBaseModule;
 +        new (&_AtlComModule) CAtlComModule;
 +
 +        shell32_hInstance = hInstance;
 +        gModule.Init(ObjectMap, hInstance, NULL);
 +
 +        DisableThreadLibraryCalls (hInstance);
 +
 +        /* get full path to this DLL for IExtractIconW_fnGetIconLocation() */
 +        GetModuleFileNameW(hInstance, swShell32Name, MAX_PATH);
 +        swShell32Name[MAX_PATH - 1] = '\0';
 +
 +        /* Initialize comctl32 */
 +        INITCOMMONCONTROLSEX InitCtrls;
 +        InitCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
 +        InitCtrls.dwICC = ICC_WIN95_CLASSES | ICC_DATE_CLASSES | ICC_USEREX_CLASSES;
 +        InitCommonControlsEx(&InitCtrls);
 +
 +        SIC_Initialize();
 +        InitChangeNotifications();
 +        InitIconOverlays();
 +    }
 +    else if (dwReason == DLL_PROCESS_DETACH)
 +    {
 +        shell32_hInstance = NULL;
 +        SIC_Destroy();
 +        FreeChangeNotifications();
 +        gModule.Term();
 +    }
 +    return TRUE;
 +}
 +
 +/***********************************************************************
 + *              DllCanUnloadNow (SHELL32.@)
 + */
 +STDAPI DllCanUnloadNow()
 +{
 +    return gModule.DllCanUnloadNow();
 +}
 +
 +/*************************************************************************
 + *              DllGetClassObject     [SHELL32.@]
 + *              SHDllGetClassObject   [SHELL32.128]
 + */
 +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
 +{
 +    HRESULT                                hResult;
 +
 +    TRACE("CLSID:%s,IID:%s\n", shdebugstr_guid(&rclsid), shdebugstr_guid(&riid));
 +
 +    hResult = gModule.DllGetClassObject(rclsid, riid, ppv);
 +    TRACE("-- pointer to class factory: %p\n", *ppv);
 +    return hResult;
 +}
 +
 +/***********************************************************************
 + *              DllRegisterServer (SHELL32.@)
 + */
 +STDAPI DllRegisterServer()
 +{
 +    HRESULT hr;
 +
 +    hr = gModule.DllRegisterServer(FALSE);
 +    if (FAILED(hr))
 +        return hr;
 +
 +    hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, TRUE, NULL);
 +    if (FAILED(hr))
 +        return hr;
 +
 +    hr = SHELL_RegisterShellFolders();
 +    if (FAILED(hr))
 +        return hr;
 +
 +    return S_OK;
 +}
 +
 +/***********************************************************************
 + *              DllUnregisterServer (SHELL32.@)
 + */
 +STDAPI DllUnregisterServer()
 +{
 +    HRESULT hr;
 +
 +    hr = gModule.DllUnregisterServer(FALSE);
 +    if (FAILED(hr))
 +        return hr;
 +
 +    hr = gModule.UpdateRegistryFromResource(IDR_FOLDEROPTIONS, FALSE, NULL);
 +    if (FAILED(hr))
 +        return hr;
 +
 +    return S_OK;
 +}
 +
 +/*************************************************************************
 + * DllInstall         [SHELL32.@]
 + *
 + * PARAMETERS
 + *
 + *    BOOL bInstall - TRUE for install, FALSE for uninstall
 + *    LPCWSTR pszCmdLine - command line (unused by shell32?)
 + */
 +
 +HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
 +{
 +    FIXME("%s %s: stub\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline));
 +    return S_OK;        /* indicate success */
 +}
Simple merge
Simple merge
index b1614e3,0000000..fe0b7ab
mode 100644,000000..100644
--- /dev/null
@@@ -1,2169 -1,0 +1,2260 @@@
-     *res = '\0';
 +/*
 + *          Shell Library Functions
 + *
 + * Copyright 1998 Marcus Meissner
 + * Copyright 2002 Eric Pouech
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2.1 of the License, or (at your option) any later version.
 + *
 + * This library is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public
 + * License along with this library; if not, write to the Free Software
 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 + */
 +
 +#include "precomp.h"
 +
 +WINE_DEFAULT_DEBUG_CHANNEL(exec);
 +
 +static const WCHAR wszOpen[] = L"open";
 +static const WCHAR wszExe[] = L".exe";
 +
 +#define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)
 +
++typedef UINT_PTR (*SHELL_ExecuteW32)(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
++                const SHELLEXECUTEINFOW *sei, LPSHELLEXECUTEINFOW sei_out);
++
 +static void ParseNoTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
 +{
 +    bool firstCharQuote = false;
 +    bool quotes_opened = false;
 +    bool backslash_encountered = false;
 +
 +    for (int curArg = 0; curArg <= argNum && *args; ++curArg)
 +    {
 +        firstCharQuote = false;
 +        if (*args == '"')
 +        {
 +            quotes_opened = true;
 +            firstCharQuote = true;
 +            args++;
 +        }
 +
 +        while(*args)
 +        {
 +            if (*args == '\\')
 +            {
 +                // if we found a backslash then flip the variable
 +                backslash_encountered = !backslash_encountered;
 +            }
 +            else if (*args == '"')
 +            {
 +                if (quotes_opened)
 +                {
 +                    if (*(args + 1) != '"')
 +                    {
 +                        quotes_opened = false;
 +                        args++;
 +                        break;
 +                    }
 +                    else
 +                    {
 +                        args++;
 +                    }
 +                }
 +                else
 +                {
 +                    quotes_opened = true;
 +                }
 +
 +                backslash_encountered = false;
 +            }
 +            else
 +            {
 +                backslash_encountered = false;
 +                if (*args == ' ' && !firstCharQuote)
 +                    break;
 +            }
 +
 +            if (curArg == argNum)
 +            {
 +                used++;
 +                if (used < len)
 +                    *res++ = *args;
 +            }
 +
 +            args++;
 +        }
 +
 +        while(*args == ' ')
 +            ++args;
 +    }
 +}
 +
 +static void ParseTildeEffect(PWSTR &res, LPCWSTR &args, DWORD &len, DWORD &used, int argNum)
 +{
 +    bool quotes_opened = false;
 +    bool backslash_encountered = false;
 +
 +    for (int curArg = 0; curArg <= argNum && *args; ++curArg)
 +    {
 +        while(*args)
 +        {
 +            if (*args == '\\')
 +            {
 +                // if we found a backslash then flip the variable
 +                backslash_encountered = !backslash_encountered;
 +            }
 +            else if (*args == '"')
 +            {
 +                if (quotes_opened)
 +                {
 +                    if (*(args + 1) != '"')
 +                    {
 +                        quotes_opened = false;
 +                    }
 +                    else
 +                    {
 +                        args++;
 +                    }
 +                }
 +                else
 +                {
 +                    quotes_opened = true;
 +                }
 +
 +                backslash_encountered = false;
 +            }
 +            else
 +            {
 +                backslash_encountered = false;
 +                if (*args == ' ' && !quotes_opened && curArg != argNum)
 +                    break;
 +            }
 +
 +            if (curArg == argNum)
 +            {
 +                used++;
 +                if (used < len)
 +                    *res++ = *args;
 +            }
 +
 +            args++;
 +        }
 +    }
 +}
 +
 +/***********************************************************************
 + * SHELL_ArgifyW [Internal]
 + *
 + * this function is supposed to expand the escape sequences found in the registry
 + * some diving reported that the following were used:
 + * + %1, %2...  seem to report to parameter of index N in ShellExecute pmts
 + * %1 file
 + * %2 printer
 + * %3 driver
 + * %4 port
 + * %I address of a global item ID (explorer switch /idlist)
 + * %L seems to be %1 as long filename followed by the 8+3 variation
 + * %S ???
 + * %* all following parameters (see batfile)
 + *
 + * The way we parse the command line arguments was determined through extensive
 + * testing and can be summed up by the following rules"
 + *
 + * - %2
 + *     - if first letter is " break on first non literal " and include any white spaces
 + *     - if first letter is NOT " break on first " or white space
 + *     - if " is opened any pair of consecutive " results in ONE literal "
 + *
 + * - %~2
 + *     - use rules from here http://www.autohotkey.net/~deleyd/parameters/parameters.htm
 + */
 +
 +static BOOL SHELL_ArgifyW(WCHAR* out, DWORD len, const WCHAR* fmt, const WCHAR* lpFile, LPITEMIDLIST pidl, LPCWSTR args, DWORD* out_len)
 +{
 +    WCHAR   xlpFile[1024];
 +    BOOL    done = FALSE;
 +    BOOL    found_p1 = FALSE;
 +    PWSTR   res = out;
 +    PCWSTR  cmd;
 +    DWORD   used = 0;
 +    bool    tildeEffect = false;
 +
 +    TRACE("Before parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
 +          debugstr_w(lpFile), pidl, args);
 +
 +    while (*fmt)
 +    {
 +        if (*fmt == '%')
 +        {
 +            switch (*++fmt)
 +            {
 +                case '\0':
 +                case '%':
 +                {
 +                    used++;
 +                    if (used < len)
 +                        *res++ = '%';
 +                };
 +                break;
 +
 +                case '*':
 +                {
 +                    if (args)
 +                    {
 +                        if (*fmt == '*')
 +                        {
 +                            used++;
 +                            while(*args)
 +                            {
 +                                used++;
 +                                if (used < len)
 +                                    *res++ = *args++;
 +                                else
 +                                    args++;
 +                            }
 +                            used++;
 +                            break;
 +                        }
 +                    }
 +                };
 +                break;
 +
 +                case '~':
 +
 +                case '2':
 +                case '3':
 +                case '4':
 +                case '5':
 +                case '6':
 +                case '7':
 +                case '8':
 +                case '9':
 +                    //case '0':
 +                {
 +                    if (*fmt == '~')
 +                    {
 +                        fmt++;
 +                        tildeEffect = true;
 +                    }
 +
 +                    if (args)
 +                    {
 +                        if (tildeEffect)
 +                        {
 +                            ParseTildeEffect(res, args, len, used, *fmt - '2');
 +                            tildeEffect = false;
 +                        }
 +                        else
 +                        {
 +                            ParseNoTildeEffect(res, args, len, used, *fmt - '2');
 +                        }
 +                    }
 +                };
 +                break;
 +
 +                case '1':
 +                    if (!done || (*fmt == '1'))
 +                    {
 +                        /*FIXME Is the call to SearchPathW() really needed? We already have separated out the parameter string in args. */
 +                        if (SearchPathW(NULL, lpFile, wszExe, sizeof(xlpFile) / sizeof(WCHAR), xlpFile, NULL))
 +                            cmd = xlpFile;
 +                        else
 +                            cmd = lpFile;
 +
 +                        used += wcslen(cmd);
 +                        if (used < len)
 +                        {
 +                            wcscpy(res, cmd);
 +                            res += wcslen(cmd);
 +                        }
 +                    }
 +                    found_p1 = TRUE;
 +                    break;
 +
 +                    /*
 +                     * IE uses this a lot for activating things such as windows media
 +                     * player. This is not verified to be fully correct but it appears
 +                     * to work just fine.
 +                     */
 +                case 'l':
 +                case 'L':
 +                    if (lpFile)
 +                    {
 +                        used += wcslen(lpFile);
 +                        if (used < len)
 +                        {
 +                            wcscpy(res, lpFile);
 +                            res += wcslen(lpFile);
 +                        }
 +                    }
 +                    found_p1 = TRUE;
 +                    break;
 +
 +                case 'i':
 +                case 'I':
 +                    if (pidl)
 +                    {
 +                        DWORD chars = 0;
 +                        /* %p should not exceed 8, maybe 16 when looking forward to 64bit.
 +                            * allowing a buffer of 100 should more than exceed all needs */
 +                        WCHAR buf[100];
 +                        LPVOID  pv;
 +                        HGLOBAL hmem = SHAllocShared(pidl, ILGetSize(pidl), 0);
 +                        pv = SHLockShared(hmem, 0);
 +                        chars = swprintf(buf, L":%p", pv);
 +
 +                        if (chars >= sizeof(buf) / sizeof(WCHAR))
 +                            ERR("pidl format buffer too small!\n");
 +
 +                        used += chars;
 +
 +                        if (used < len)
 +                        {
 +                            wcscpy(res, buf);
 +                            res += chars;
 +                        }
 +                        SHUnlockShared(pv);
 +                    }
 +                    found_p1 = TRUE;
 +                    break;
 +
 +                default:
 +                    /*
 +                     * Check if this is an env-variable here...
 +                     */
 +
 +                    /* Make sure that we have at least one more %.*/
 +                    if (strchrW(fmt, '%'))
 +                    {
 +                        WCHAR   tmpBuffer[1024];
 +                        PWSTR   tmpB = tmpBuffer;
 +                        WCHAR   tmpEnvBuff[MAX_PATH];
 +                        DWORD   envRet;
 +
 +                        while (*fmt != '%')
 +                            *tmpB++ = *fmt++;
 +                        *tmpB++ = 0;
 +
 +                        TRACE("Checking %s to be an env-var\n", debugstr_w(tmpBuffer));
 +
 +                        envRet = GetEnvironmentVariableW(tmpBuffer, tmpEnvBuff, MAX_PATH);
 +                        if (envRet == 0 || envRet > MAX_PATH)
 +                        {
 +                            used += wcslen(tmpBuffer);
 +                            if (used < len)
 +                            {
 +                                wcscpy( res, tmpBuffer );
 +                                res += wcslen(tmpBuffer);
 +                            }
 +                        }
 +                        else
 +                        {
 +                            used += wcslen(tmpEnvBuff);
 +                            if (used < len)
 +                            {
 +                                wcscpy( res, tmpEnvBuff );
 +                                res += wcslen(tmpEnvBuff);
 +                            }
 +                        }
 +                    }
 +                    done = TRUE;
 +                    break;
 +            }
 +            /* Don't skip past terminator (catch a single '%' at the end) */
 +            if (*fmt != '\0')
 +            {
 +                fmt++;
 +            }
 +        }
 +        else
 +        {
 +            used ++;
 +            if (used < len)
 +                *res++ = *fmt++;
 +            else
 +                fmt++;
 +        }
 +    }
 +
-    if (psei->fMask & SEE_MASK_NO_CONSOLE)
++    used++;
++    if (res - out < static_cast<int>(len))
++        *res = '\0';
++    else
++        out[len-1] = '\0';
++
 +    TRACE("used %i of %i space\n", used, len);
 +    if (out_len)
 +        *out_len = used;
 +
 +    TRACE("After parsing: %p, %d, %s, %s, %p, %p\n", out, len, debugstr_w(fmt),
 +          debugstr_w(lpFile), pidl, args);
 +
 +    return found_p1;
 +}
 +
 +static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR pszPath, UINT uOutSize)
 +{
 +    STRRET strret;
 +    IShellFolder *desktop;
 +
 +    HRESULT hr = SHGetDesktopFolder(&desktop);
 +
 +    if (SUCCEEDED(hr))
 +    {
 +        hr = desktop->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret);
 +
 +        if (SUCCEEDED(hr))
 +            StrRetToStrNW(pszPath, uOutSize, &strret, pidl);
 +
 +        desktop->Release();
 +    }
 +
 +    return hr;
 +}
 +
 +/*************************************************************************
 + *    SHELL_ExecuteW [Internal]
 + *
 + */
 +static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait,
 +                               const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
 +{
 +    STARTUPINFOW  startup;
 +    PROCESS_INFORMATION info;
 +    UINT_PTR retval = SE_ERR_NOASSOC;
 +    UINT gcdret = 0;
 +    WCHAR curdir[MAX_PATH];
 +    DWORD dwCreationFlags;
 +    const WCHAR *lpDirectory = NULL;
 +
 +    TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory));
 +
 +    /* make sure we don't fail the CreateProcess if the calling app passes in
 +     * a bad working directory */
 +    if (psei->lpDirectory && psei->lpDirectory[0])
 +    {
 +        DWORD attr = GetFileAttributesW(psei->lpDirectory);
 +        if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY)
 +            lpDirectory = psei->lpDirectory;
 +    }
 +
 +    /* ShellExecute specifies the command from psei->lpDirectory
 +     * if present. Not from the current dir as CreateProcess does */
 +    if (lpDirectory)
 +        if ((gcdret = GetCurrentDirectoryW( MAX_PATH, curdir)))
 +            if (!SetCurrentDirectoryW( lpDirectory))
 +                ERR("cannot set directory %s\n", debugstr_w(lpDirectory));
 +
 +    ZeroMemory(&startup, sizeof(STARTUPINFOW));
 +    startup.cb = sizeof(STARTUPINFOW);
 +    startup.dwFlags = STARTF_USESHOWWINDOW;
 +    startup.wShowWindow = psei->nShow;
 +    dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
- static UINT SHELL_FindExecutableByOperation(LPCWSTR lpOperation, LPWSTR key, LPWSTR filetype, LPWSTR command, LONG commandlen)
++    if (!(psei->fMask & SEE_MASK_NO_CONSOLE))
 +        dwCreationFlags |= CREATE_NEW_CONSOLE;    
 +    startup.lpTitle = (LPWSTR)(psei->fMask & (SEE_MASK_HASLINKNAME | SEE_MASK_HASTITLE) ? psei->lpClass : NULL);
 +
 +    if (psei->fMask & SEE_MASK_HASLINKNAME)
 +        startup.dwFlags |= STARTF_TITLEISLINKNAME;
 +
 +    if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env,
 +                       lpDirectory, &startup, &info))
 +    {
 +        /* Give 30 seconds to the app to come up, if desired. Probably only needed
 +           when starting app immediately before making a DDE connection. */
 +        if (shWait)
 +            if (WaitForInputIdle(info.hProcess, 30000) == WAIT_FAILED)
 +                WARN("WaitForInputIdle failed: Error %d\n", GetLastError() );
 +        retval = 33;
 +
 +        if (psei->fMask & SEE_MASK_NOCLOSEPROCESS)
 +            psei_out->hProcess = info.hProcess;
 +        else
 +            CloseHandle( info.hProcess );
 +        CloseHandle( info.hThread );
 +    }
 +    else if ((retval = GetLastError()) >= 32)
 +    {
 +        WARN("CreateProcess returned error %ld\n", retval);
 +        retval = ERROR_BAD_FORMAT;
 +    }
 +
 +    TRACE("returning %lu\n", retval);
 +
 +    psei_out->hInstApp = (HINSTANCE)retval;
 +
 +    if (gcdret)
 +        if (!SetCurrentDirectoryW(curdir))
 +            ERR("cannot return to directory %s\n", debugstr_w(curdir));
 +
 +    return retval;
 +}
 +
 +
 +/***********************************************************************
 + *           SHELL_BuildEnvW    [Internal]
 + *
 + * Build the environment for the new process, adding the specified
 + * path to the PATH variable. Returned pointer must be freed by caller.
 + */
 +static LPWSTR SHELL_BuildEnvW( const WCHAR *path )
 +{
 +    static const WCHAR wPath[] = L"PATH=";
 +    WCHAR *strings, *new_env;
 +    WCHAR *p, *p2;
 +    int total = wcslen(path) + 1;
 +    BOOL got_path = FALSE;
 +
 +    if (!(strings = GetEnvironmentStringsW())) return NULL;
 +    p = strings;
 +    while (*p)
 +    {
 +        int len = wcslen(p) + 1;
 +        if (!_wcsnicmp( p, wPath, 5 )) got_path = TRUE;
 +        total += len;
 +        p += len;
 +    }
 +    if (!got_path) total += 5;  /* we need to create PATH */
 +    total++;  /* terminating null */
 +
 +    if (!(new_env = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, total * sizeof(WCHAR))))
 +    {
 +        FreeEnvironmentStringsW(strings);
 +        return NULL;
 +    }
 +    p = strings;
 +    p2 = new_env;
 +    while (*p)
 +    {
 +        int len = wcslen(p) + 1;
 +        memcpy(p2, p, len * sizeof(WCHAR));
 +        if (!_wcsnicmp( p, wPath, 5 ))
 +        {
 +            p2[len - 1] = ';';
 +            wcscpy( p2 + len, path );
 +            p2 += wcslen(path) + 1;
 +        }
 +        p += len;
 +        p2 += len;
 +    }
 +    if (!got_path)
 +    {
 +        wcscpy(p2, wPath);
 +        wcscat(p2, path);
 +        p2 += wcslen(p2) + 1;
 +    }
 +    *p2 = 0;
 +    FreeEnvironmentStringsW(strings);
 +    return new_env;
 +}
 +
 +
 +/***********************************************************************
 + *           SHELL_TryAppPathW    [Internal]
 + *
 + * Helper function for SHELL_FindExecutable
 + * @param lpResult - pointer to a buffer of size MAX_PATH
 + * On entry: szName is a filename (probably without path separators).
 + * On exit: if szName found in "App Path", place full path in lpResult, and return true
 + */
 +static BOOL SHELL_TryAppPathW( LPCWSTR szName, LPWSTR lpResult, WCHAR **env)
 +{
 +    HKEY hkApp = 0;
 +    WCHAR buffer[1024];
 +    LONG len;
 +    LONG res;
 +    BOOL found = FALSE;
 +
 +    if (env) *env = NULL;
 +    wcscpy(buffer, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\");
 +    wcscat(buffer, szName);
 +    res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hkApp);
 +    if (res) goto end;
 +
 +    len = MAX_PATH * sizeof(WCHAR);
 +    res = RegQueryValueW(hkApp, NULL, lpResult, &len);
 +    if (res) goto end;
 +    found = TRUE;
 +
 +    if (env)
 +    {
 +        DWORD count = sizeof(buffer);
 +        if (!RegQueryValueExW(hkApp, L"Path", NULL, NULL, (LPBYTE)buffer, &count) && buffer[0])
 +            *env = SHELL_BuildEnvW(buffer);
 +    }
 +
 +end:
 +    if (hkApp) RegCloseKey(hkApp);
 +    return found;
 +}
 +
-     if (RegOpenKeyExW(HKEY_CLASSES_ROOT, filetype, 0, 0x02000000, &hkeyClass))
++/*************************************************************************
++ *     SHELL_FindExecutableByVerb [Internal]
++ *
++ * called from SHELL_FindExecutable or SHELL_execute_class
++ * in/out:
++ *      classname a buffer, big enough, to get the key name to do actually the
++ *              command   "WordPad.Document.1\\shell\\open\\command"
++ *              passed as "WordPad.Document.1"
++ * in:
++ *      lpVerb the operation on it (open)
++ *      commandlen the size of command buffer (in bytes)
++ * out:
++ *      command a buffer, to store the command to do the
++ *              operation on the file
++ *      key a buffer, big enough, to get the key name to do actually the
++ *              command "WordPad.Document.1\\shell\\open\\command"
++ *              Can be NULL
++ */
++static UINT SHELL_FindExecutableByVerb(LPCWSTR lpVerb, LPWSTR key, LPWSTR classname, LPWSTR command, LONG commandlen)
 +{
 +    static const WCHAR wCommand[] = L"\\command";
 +    HKEY hkeyClass;
 +    WCHAR verb[MAX_PATH];
 +
-     if (!HCR_GetDefaultVerbW(hkeyClass, lpOperation, verb, sizeof(verb) / sizeof(verb[0])))
++    if (RegOpenKeyExW(HKEY_CLASSES_ROOT, classname, 0, 0x02000000, &hkeyClass))
 +        return SE_ERR_NOASSOC;
-     wcscat(filetype, L"\\shell\\");
-     wcscat(filetype, verb);
-     wcscat(filetype, wCommand);
++    if (!HCR_GetDefaultVerbW(hkeyClass, lpVerb, verb, sizeof(verb) / sizeof(verb[0])))
 +        return SE_ERR_NOASSOC;
 +    RegCloseKey(hkeyClass);
 +
 +    /* Looking for ...buffer\shell\<verb>\command */
-     if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, command,
++    wcscat(classname, L"\\shell\\");
++    wcscat(classname, verb);
++    wcscat(classname, wCommand);
 +
-         if (key) wcscpy(key, filetype);
++    if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, command,
 +                       &commandlen) == ERROR_SUCCESS)
 +    {
 +        commandlen /= sizeof(WCHAR);
-         tmp = strstrW(filetype, wCommand);
++        if (key) wcscpy(key, classname);
 +#if 0
 +        LPWSTR tmp;
 +        WCHAR param[256];
 +        LONG paramlen = sizeof(param);
 +        static const WCHAR wSpace[] = {' ', 0};
 +
 +        /* FIXME: it seems all Windows version don't behave the same here.
 +         * the doc states that this ddeexec information can be found after
 +         * the exec names.
 +         * on Win98, it doesn't appear, but I think it does on Win2k
 +         */
 +        /* Get the parameters needed by the application
 +           from the associated ddeexec key */
-         wcscat(filetype, wDdeexec);
-         if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, param,
++        tmp = strstrW(classname, wCommand);
 +        tmp[0] = '\0';
-  *      lpOperation the operation on it (open)
++        wcscat(classname, wDdeexec);
++        if (RegQueryValueW(HKEY_CLASSES_ROOT, classname, param,
 +                           &paramlen) == ERROR_SUCCESS)
 +        {
 +            paramlen /= sizeof(WCHAR);
 +            wcscat(command, wSpace);
 +            wcscat(command, param);
 +            commandlen += paramlen;
 +        }
 +#endif
 +
 +        command[commandlen] = '\0';
 +
 +        return 33; /* FIXME see SHELL_FindExecutable() */
 +    }
 +
 +    return SE_ERR_NOASSOC;
 +}
 +
 +/*************************************************************************
 + *    SHELL_FindExecutable [Internal]
 + *
 + * Utility for code sharing between FindExecutable and ShellExecute
 + * in:
 + *      lpFile the name of a file
- static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation,
++ *      lpVerb the operation on it (open)
 + * out:
 + *      lpResult a buffer, big enough :-(, to store the command to do the
 + *              operation on the file
 + *      key a buffer, big enough, to get the key name to do actually the
 + *              command (it'll be used afterwards for more information
 + *              on the operation)
 + */
-     WCHAR filetype[256];     /* registry name for this filetype */
-     LONG  filetypelen = sizeof(filetype); /* length of above */
++static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb,
 +                                 LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env, LPITEMIDLIST pidl, LPCWSTR args)
 +{
 +    WCHAR *extension = NULL; /* pointer to file extension */
-         /* Hey, isn't this value ignored?  Why make this call?  Shouldn't we return here?  --dank*/
++    WCHAR classname[256];     /* registry name for this file type */
++    LONG  classnamelen = sizeof(classname); /* length of above */
 +    WCHAR command[1024];     /* command from registry */
 +    WCHAR wBuffer[256];      /* Used to GetProfileString */
 +    UINT  retval = SE_ERR_NOASSOC;
 +    WCHAR *tok;              /* token pointer */
 +    WCHAR xlpFile[256];      /* result of SearchPath */
 +    DWORD attribs;           /* file attributes */
 +
 +    TRACE("%s\n", debugstr_w(lpFile));
 +
 +    if (!lpResult)
 +        return ERROR_INVALID_PARAMETER;
 +
 +    xlpFile[0] = '\0';
 +    lpResult[0] = '\0'; /* Start off with an empty return string */
 +    if (key) *key = '\0';
 +
 +    /* trap NULL parameters on entry */
 +    if (!lpFile)
 +    {
 +        WARN("(lpFile=%s,lpResult=%s): NULL parameter\n",
 +             debugstr_w(lpFile), debugstr_w(lpResult));
 +        return ERROR_FILE_NOT_FOUND; /* File not found. Close enough, I guess. */
 +    }
 +
 +    if (SHELL_TryAppPathW( lpFile, lpResult, env ))
 +    {
 +        TRACE("found %s via App Paths\n", debugstr_w(lpResult));
 +        return 33;
 +    }
 +
 +    if (SearchPathW(lpPath, lpFile, wszExe, sizeof(xlpFile) / sizeof(WCHAR), xlpFile, NULL))
 +    {
 +        TRACE("SearchPathW returned non-zero\n");
 +        lpFile = xlpFile;
-         wcscpy(filetype, L"Folder");
-         filetypelen = 6;    /* strlen("Folder") */
++        /* The file was found in the application-supplied default directory (or the system search path) */
 +    }
 +    else if (lpPath && SearchPathW(NULL, lpFile, wszExe, sizeof(xlpFile)/sizeof(WCHAR), xlpFile, NULL))
 +    {
 +        TRACE("SearchPathW returned non-zero\n");
 +        lpFile = xlpFile;
 +        /* The file was found in one of the directories in the system-wide search path */
 +    }
 +    
 +    attribs = GetFileAttributesW(lpFile);
 +    if (attribs != INVALID_FILE_ATTRIBUTES && (attribs & FILE_ATTRIBUTE_DIRECTORY))
 +    {
-         /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
++        wcscpy(classname, L"Folder");
 +    }
 +    else
 +    {
 +        /* Did we get something? Anything? */
 +        if (xlpFile[0] == 0)
 +        {
 +            TRACE("Returning SE_ERR_FNF\n");
 +            return SE_ERR_FNF;
 +        }
 +        /* First thing we need is the file's extension */
 +        extension = wcsrchr(xlpFile, '.'); /* Assume last "." is the one; */
 +        /* File->Run in progman uses */
 +        /* .\FILE.EXE :( */
 +        TRACE("xlpFile=%s,extension=%s\n", debugstr_w(xlpFile), debugstr_w(extension));
 +
 +        if (extension == NULL || extension[1] == 0)
 +        {
 +            WARN("Returning SE_ERR_NOASSOC\n");
 +            return SE_ERR_NOASSOC;
 +        }
 +
 +        /* Three places to check: */
 +        /* 1. win.ini, [windows], programs (NB no leading '.') */
-         if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, filetype,
-                            &filetypelen) == ERROR_SUCCESS)
++        /* 2. Registry, HKEY_CLASS_ROOT\<classname>\shell\open\command */
 +        /* 3. win.ini, [extensions], extension (NB no leading '.' */
 +        /* All I know of the order is that registry is checked before */
 +        /* extensions; however, it'd make sense to check the programs */
 +        /* section first, so that's what happens here. */
 +
 +        /* See if it's a program - if GetProfileString fails, we skip this
 +         * section. Actually, if GetProfileString fails, we've probably
 +         * got a lot more to worry about than running a program... */
 +        if (GetProfileStringW(L"windows", L"programs", L"exe pif bat cmd com", wBuffer, sizeof(wBuffer) / sizeof(WCHAR)) > 0)
 +        {
 +            CharLowerW(wBuffer);
 +            tok = wBuffer;
 +            while (*tok)
 +            {
 +                WCHAR *p = tok;
 +                while (*p && *p != ' ' && *p != '\t') p++;
 +                if (*p)
 +                {
 +                    *p++ = 0;
 +                    while (*p == ' ' || *p == '\t') p++;
 +                }
 +
 +                if (wcsicmp(tok, &extension[1]) == 0) /* have to skip the leading "." */
 +                {
 +                    wcscpy(lpResult, xlpFile);
 +                    /* Need to perhaps check that the file has a path
 +                     * attached */
 +                    TRACE("found %s\n", debugstr_w(lpResult));
 +                    return 33;
 +                    /* Greater than 32 to indicate success */
 +                }
 +                tok = p;
 +            }
 +        }
 +
 +        /* Check registry */
-             filetypelen /= sizeof(WCHAR);
-             if (filetypelen == sizeof(filetype) / sizeof(WCHAR))
-                 filetypelen--;
++        if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, classname,
++                           &classnamelen) == ERROR_SUCCESS)
 +        {
-             filetype[filetypelen] = '\0';
-             TRACE("File type: %s\n", debugstr_w(filetype));
++            classnamelen /= sizeof(WCHAR);
++            if (classnamelen == sizeof(classname) / sizeof(WCHAR))
++                classnamelen--;
 +
-             *filetype = '\0';
-             filetypelen = 0;
++            classname[classnamelen] = '\0';
++            TRACE("File type: %s\n", debugstr_w(classname));
 +        }
 +        else
 +        {
-     if (*filetype)
++            *classname = '\0';
 +        }
 +    }
 +
-         /* pass the operation string to SHELL_FindExecutableByOperation() */
-         filetype[filetypelen] = '\0';
-         retval = SHELL_FindExecutableByOperation(lpOperation, key, filetype, command, sizeof(command));
++    if (*classname)
 +    {
-     WCHAR       app[256], topic[256], ifexec[256], res[256];
++        /* pass the verb string to SHELL_FindExecutableByVerb() */
++        retval = SHELL_FindExecutableByVerb(lpVerb, key, classname, command, sizeof(command));
 +
 +        if (retval > 32)
 +        {
 +            DWORD finishedLen;
 +            SHELL_ArgifyW(lpResult, resultLen, command, xlpFile, pidl, args, &finishedLen);
 +            if (finishedLen > resultLen)
 +                ERR("Argify buffer not large enough.. truncated\n");
 +            /* Remove double quotation marks and command line arguments */
 +            if (*lpResult == '"')
 +            {
 +                WCHAR *p = lpResult;
 +                while (*(p + 1) != '"')
 +                {
 +                    *p = *(p + 1);
 +                    p++;
 +                }
 +                *p = '\0';
 +            }
 +            else
 +            {
 +                /* Truncate on first space */
 +                WCHAR *p = lpResult;
 +                while (*p != ' ' && *p != '\0')
 +                    p++;
 +                *p = '\0';
 +            }
 +        }
 +    }
 +    else /* Check win.ini */
 +    {
 +        /* Toss the leading dot */
 +        extension++;
 +        if (GetProfileStringW(L"extensions", extension, L"", command, sizeof(command) / sizeof(WCHAR)) > 0)
 +        {
 +            if (wcslen(command) != 0)
 +            {
 +                wcscpy(lpResult, command);
 +                tok = wcschr(lpResult, '^'); /* should be ^.extension? */
 +                if (tok != NULL)
 +                {
 +                    tok[0] = '\0';
 +                    wcscat(lpResult, xlpFile); /* what if no dir in xlpFile? */
 +                    tok = wcschr(command, '^'); /* see above */
 +                    if ((tok != NULL) && (wcslen(tok) > 5))
 +                    {
 +                        wcscat(lpResult, &tok[5]);
 +                    }
 +                }
 +                retval = 33; /* FIXME - see above */
 +            }
 +        }
 +    }
 +
 +    TRACE("returning %s\n", debugstr_w(lpResult));
 +    return retval;
 +}
 +
 +/******************************************************************
 + *        dde_cb
 + *
 + * callback for the DDE connection. not really useful
 + */
 +static HDDEDATA CALLBACK dde_cb(UINT uType, UINT uFmt, HCONV hConv,
 +                                HSZ hsz1, HSZ hsz2, HDDEDATA hData,
 +                                ULONG_PTR dwData1, ULONG_PTR dwData2)
 +{
 +    TRACE("dde_cb: %04x, %04x, %p, %p, %p, %p, %08lx, %08lx\n",
 +          uType, uFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
 +    return NULL;
 +}
 +
 +/******************************************************************
 + *        dde_connect
 + *
 + * ShellExecute helper. Used to do an operation with a DDE connection
 + *
 + * Handles both the direct connection (try #1), and if it fails,
 + * launching an application and trying (#2) to connect to it
 + *
 + */
 +static unsigned dde_connect(const WCHAR* key, const WCHAR* start, WCHAR* ddeexec,
 +                            const WCHAR* lpFile, WCHAR *env,
 +                            LPCWSTR szCommandline, LPITEMIDLIST pidl, SHELL_ExecuteW32 execfunc,
 +                            const SHELLEXECUTEINFOW *psei, LPSHELLEXECUTEINFOW psei_out)
 +{
 +    WCHAR       regkey[256];
 +    WCHAR *     endkey = regkey + wcslen(key);
-     DWORD       resultLen;
++    WCHAR       app[256], topic[256], ifexec[256], static_res[256];
++    WCHAR *     dynamic_res=NULL;
++    WCHAR *     res;
 +    LONG        applen, topiclen, ifexeclen;
 +    WCHAR *     exec;
 +    DWORD       ddeInst = 0;
 +    DWORD       tid;
-     wcscpy(endkey, L"\\application");
++    DWORD       resultLen, endkeyLen;
 +    HSZ         hszApp, hszTopic;
 +    HCONV       hConv;
 +    HDDEDATA    hDdeData;
 +    unsigned    ret = SE_ERR_NOASSOC;
 +    BOOL unicode = !(GetVersion() & 0x80000000);
 +
++    if (strlenW(key) + 1 > sizeof(regkey) / sizeof(regkey[0]))
++    {
++        FIXME("input parameter %s larger than buffer\n", debugstr_w(key));
++        return 2;
++    }
 +    wcscpy(regkey, key);
-             LPWSTR p, space;
-             for (p = (LPWSTR)start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1)
++    static const WCHAR wApplication[] = L"\\application";
++    endkeyLen = sizeof(regkey) / sizeof(regkey[0]) - (endkey - regkey);
++    if (strlenW(wApplication) + 1 > endkeyLen)
++    {
++        FIXME("endkey %s overruns buffer\n", debugstr_w(wApplication));
++        return 2;
++    }
++    wcscpy(endkey, wApplication);
 +    applen = sizeof(app);
 +    if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, app, &applen) != ERROR_SUCCESS)
 +    {
 +        WCHAR command[1024], fullpath[MAX_PATH];
 +        static const WCHAR wSo[] = L".so";
 +        DWORD sizeSo = sizeof(wSo) / sizeof(WCHAR);
 +        LPWSTR ptr = NULL;
 +        DWORD ret = 0;
 +
 +        /* Get application command from start string and find filename of application */
 +        if (*start == '"')
 +        {
++            if (strlenW(start + 1) + 1 > sizeof(command) / sizeof(command[0]))
++            {
++                FIXME("size of input parameter %s larger than buffer\n",
++                      debugstr_w(start + 1));
++                return 2;
++            }
 +            wcscpy(command, start + 1);
 +            if ((ptr = wcschr(command, '"')))
 +                * ptr = 0;
 +            ret = SearchPathW(NULL, command, wszExe, sizeof(fullpath) / sizeof(WCHAR), fullpath, &ptr);
 +        }
 +        else
 +        {
-     wcscpy(endkey, L"\\topic");
++            LPCWSTR p;
++            LPWSTR space;
++            for (p = start; (space = const_cast<LPWSTR>(strchrW(p, ' '))); p = space + 1)
 +            {
 +                int idx = space - start;
 +                memcpy(command, start, idx * sizeof(WCHAR));
 +                command[idx] = '\0';
 +                if ((ret = SearchPathW(NULL, command, wszExe, sizeof(fullpath) / sizeof(WCHAR), fullpath, &ptr)))
 +                    break;
 +            }
 +            if (!ret)
 +                ret = SearchPathW(NULL, start, wszExe, sizeof(fullpath) / sizeof(WCHAR), fullpath, &ptr);
 +        }
 +
 +        if (!ret)
 +        {
 +            ERR("Unable to find application path for command %s\n", debugstr_w(start));
 +            return ERROR_ACCESS_DENIED;
 +        }
++        if (strlenW(ptr) + 1 > sizeof(app) / sizeof(app[0]))
++        {
++            FIXME("size of found path %s larger than buffer\n", debugstr_w(ptr));
++            return 2;
++        }
 +        wcscpy(app, ptr);
 +
 +        /* Remove extensions (including .so) */
 +        ptr = app + wcslen(app) - (sizeSo - 1);
 +        if (wcslen(app) >= sizeSo &&
 +                !wcscmp(ptr, wSo))
 +            *ptr = 0;
 +
 +        ptr = const_cast<LPWSTR>(strrchrW(app, '.'));
 +        assert(ptr);
 +        *ptr = 0;
 +    }
-         strcpyW(endkey, L"\\ifexec");
++    
++    static const WCHAR wTopic[] = L"\\topic";
++    if (strlenW(wTopic) + 1 > endkeyLen)
++    {
++        FIXME("endkey %s overruns buffer\n", debugstr_w(wTopic));
++        return 2;
++    }
++    wcscpy(endkey, wTopic);
 +    topiclen = sizeof(topic);
 +    if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS)
 +    {
 +        wcscpy(topic, L"System");
 +    }
 +
 +    if (unicode)
 +    {
 +        if (DdeInitializeW(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
 +            return 2;
 +    }
 +    else
 +    {
 +        if (DdeInitializeA(&ddeInst, dde_cb, APPCMD_CLIENTONLY, 0L) != DMLERR_NO_ERROR)
 +            return 2;
 +    }
 +
 +    hszApp = DdeCreateStringHandleW(ddeInst, app, CP_WINUNICODE);
 +    hszTopic = DdeCreateStringHandleW(ddeInst, topic, CP_WINUNICODE);
 +
 +    hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
 +    exec = ddeexec;
 +    if (!hConv)
 +    {
 +        TRACE("Launching %s\n", debugstr_w(start));
 +        ret = execfunc(start, env, TRUE, psei, psei_out);
 +        if (ret <= 32)
 +        {
 +            TRACE("Couldn't launch\n");
 +            goto error;
 +        }
 +        hConv = DdeConnect(ddeInst, hszApp, hszTopic, NULL);
 +        if (!hConv)
 +        {
 +            TRACE("Couldn't connect. ret=%d\n", ret);
 +            DdeUninitialize(ddeInst);
 +            SetLastError(ERROR_DDE_FAIL);
 +            return 30; /* whatever */
 +        }
-     SHELL_ArgifyW(res, sizeof(res) / sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen);
-     if (resultLen > sizeof(res) / sizeof(WCHAR))
-         ERR("Argify buffer not large enough, truncated\n");
++        static const WCHAR wIfexec[] = L"\\ifexec";
++        if (strlenW(wIfexec) + 1 > endkeyLen)
++        {
++            FIXME("endkey %s overruns buffer\n", debugstr_w(wIfexec));
++            return 2;
++        }
++        strcpyW(endkey, wIfexec);
 +        ifexeclen = sizeof(ifexec);
 +        if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS)
 +        {
 +            exec = ifexec;
 +        }
 +    }
 +
-     ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI));
++    SHELL_ArgifyW(static_res, sizeof(static_res)/sizeof(WCHAR), exec, lpFile, pidl, szCommandline, &resultLen);
++    if (resultLen > sizeof(static_res)/sizeof(WCHAR))
++    {
++        res = dynamic_res = static_cast<WCHAR *>(HeapAlloc(GetProcessHeap(), 0, resultLen * sizeof(WCHAR)));
++        SHELL_ArgifyW(dynamic_res, resultLen, exec, lpFile, pidl, szCommandline, NULL);
++    }
++    else
++        res = static_res;
 +    TRACE("%s %s => %s\n", debugstr_w(exec), debugstr_w(lpFile), debugstr_w(res));
 +
 +    /* It's documented in the KB 330337 that IE has a bug and returns
 +     * error DMLERR_NOTPROCESSED on XTYP_EXECUTE request.
 +     */
 +    if (unicode)
 +        hDdeData = DdeClientTransaction((LPBYTE)res, (strlenW(res) + 1) * sizeof(WCHAR), hConv, 0L, 0, XTYP_EXECUTE, 30000, &tid);
 +    else
 +    {
 +        DWORD lenA = WideCharToMultiByte(CP_ACP, 0, res, -1, NULL, 0, NULL, NULL);
 +        char *resA = (LPSTR)HeapAlloc(GetProcessHeap(), 0, lenA);
 +        WideCharToMultiByte(CP_ACP, 0, res, -1, resA, lenA, NULL, NULL);
 +        hDdeData = DdeClientTransaction( (LPBYTE)resA, lenA, hConv, 0L, 0,
 +                                         XTYP_EXECUTE, 10000, &tid );
 +        HeapFree(GetProcessHeap(), 0, resA);
 +    }
 +    if (hDdeData)
 +        DdeFreeDataHandle(hDdeData);
 +    else
 +        WARN("DdeClientTransaction failed with error %04x\n", DdeGetLastError(ddeInst));
 +    ret = 33;
 +
++    HeapFree(GetProcessHeap(), 0, dynamic_res);
++
 +    DdeDisconnect(hConv);
 +
 +error:
 +    DdeUninitialize(ddeInst);
 +
 +    return ret;
 +}
 +
 +/*************************************************************************
 + *    execute_from_key [Internal]
 + */
 +static UINT_PTR execute_from_key(LPCWSTR key, LPCWSTR lpFile, WCHAR *env,
 +                                 LPCWSTR szCommandline, LPCWSTR executable_name,
 +                                 SHELL_ExecuteW32 execfunc,
 +                                 LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out)
 +{
 +    WCHAR cmd[256], param[1024], ddeexec[256];
 +    DWORD cmdlen = sizeof(cmd), ddeexeclen = sizeof(ddeexec);
 +    UINT_PTR retval = SE_ERR_NOASSOC;
 +    DWORD resultLen;
 +    LPWSTR tmp;
 +
 +    TRACE("%s %s %s %s %s\n", debugstr_w(key), debugstr_w(lpFile), debugstr_w(env),
 +          debugstr_w(szCommandline), debugstr_w(executable_name));
 +
 +    cmd[0] = '\0';
 +    param[0] = '\0';
 +
 +    /* Get the application from the registry */
 +    if (RegQueryValueW(HKEY_CLASSES_ROOT, key, cmd, (LONG *)&cmdlen) == ERROR_SUCCESS)
 +    {
 +        TRACE("got cmd: %s\n", debugstr_w(cmd));
 +
 +        /* Is there a replace() function anywhere? */
 +        cmdlen /= sizeof(WCHAR);
 +        if (cmdlen >= sizeof(cmd) / sizeof(WCHAR))
 +            cmdlen = sizeof(cmd) / sizeof(WCHAR) - 1;
 +        cmd[cmdlen] = '\0';
 +        SHELL_ArgifyW(param, sizeof(param) / sizeof(WCHAR), cmd, lpFile, (LPITEMIDLIST)psei->lpIDList, szCommandline, &resultLen);
 +        if (resultLen > sizeof(param) / sizeof(WCHAR))
 +            ERR("Argify buffer not large enough, truncating\n");
 +    }
 +
 +    /* Get the parameters needed by the application
 +       from the associated ddeexec key */
 +    tmp = const_cast<LPWSTR>(strstrW(key, L"command"));
 +    assert(tmp);
 +    wcscpy(tmp, L"ddeexec");
 +
 +    if (RegQueryValueW(HKEY_CLASSES_ROOT, key, ddeexec, (LONG *)&ddeexeclen) == ERROR_SUCCESS)
 +    {
 +        TRACE("Got ddeexec %s => %s\n", debugstr_w(key), debugstr_w(ddeexec));
 +        if (!param[0]) strcpyW(param, executable_name);
 +        retval = dde_connect(key, param, ddeexec, lpFile, env, szCommandline, (LPITEMIDLIST)psei->lpIDList, execfunc, psei, psei_out);
 +    }
 +    else if (param[0])
 +    {
 +        TRACE("executing: %s\n", debugstr_w(param));
 +        retval = execfunc(param, env, FALSE, psei, psei_out);
 +    }
 +    else
 +        WARN("Nothing appropriate found for %s\n", debugstr_w(key));
 +
 +    return retval;
 +}
 +
 +/*************************************************************************
 + * FindExecutableA            [SHELL32.@]
 + */
 +HINSTANCE WINAPI FindExecutableA(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
 +{
 +    HINSTANCE retval;
 +    WCHAR *wFile = NULL, *wDirectory = NULL;
 +    WCHAR wResult[MAX_PATH];
 +
 +    if (lpFile) __SHCloneStrAtoW(&wFile, lpFile);
 +    if (lpDirectory) __SHCloneStrAtoW(&wDirectory, lpDirectory);
 +
 +    retval = FindExecutableW(wFile, wDirectory, wResult);
 +    WideCharToMultiByte(CP_ACP, 0, wResult, -1, lpResult, MAX_PATH, NULL, NULL);
 +    SHFree(wFile);
 +    SHFree(wDirectory);
 +
 +    TRACE("returning %s\n", lpResult);
 +    return retval;
 +}
 +
 +/*************************************************************************
 + * FindExecutableW            [SHELL32.@]
 + *
 + * This function returns the executable associated with the specified file
 + * for the default verb.
 + *
 + * PARAMS
 + *  lpFile   [I] The file to find the association for. This must refer to
 + *               an existing file otherwise FindExecutable fails and returns
 + *               SE_ERR_FNF.
 + *  lpResult [O] Points to a buffer into which the executable path is
 + *               copied. This parameter must not be NULL otherwise
 + *               FindExecutable() segfaults. The buffer must be of size at
 + *               least MAX_PATH characters.
 + *
 + * RETURNS
 + *  A value greater than 32 on success, less than or equal to 32 otherwise.
 + *  See the SE_ERR_* constants.
 + *
 + * NOTES
 + *  On Windows XP and 2003, FindExecutable() seems to first convert the
 + *  filename into 8.3 format, thus taking into account only the first three
 + *  characters of the extension, and expects to find an association for those.
 + *  However other Windows versions behave sanely.
 + */
 +HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory, LPWSTR lpResult)
 +{
 +    UINT_PTR retval = SE_ERR_NOASSOC;
 +    WCHAR old_dir[1024];
 +
 +    TRACE("File %s, Dir %s\n", debugstr_w(lpFile), debugstr_w(lpDirectory));
 +
 +    lpResult[0] = '\0'; /* Start off with an empty return string */
 +    if (lpFile == NULL)
 +        return (HINSTANCE)SE_ERR_FNF;
 +
 +    if (lpDirectory)
 +    {
 +        GetCurrentDirectoryW(sizeof(old_dir) / sizeof(WCHAR), old_dir);
 +        SetCurrentDirectoryW(lpDirectory);
 +    }
 +
 +    retval = SHELL_FindExecutable(lpDirectory, lpFile, wszOpen, lpResult, MAX_PATH, NULL, NULL, NULL, NULL);
 +
 +    TRACE("returning %s\n", debugstr_w(lpResult));
 +    if (lpDirectory)
 +        SetCurrentDirectoryW(old_dir);
 +    return (HINSTANCE)retval;
 +}
 +
 +/* FIXME: is this already implemented somewhere else? */
 +static HKEY ShellExecute_GetClassKey(const SHELLEXECUTEINFOW *sei)
 +{
 +    LPCWSTR ext = NULL, lpClass = NULL;
 +    LPWSTR cls = NULL;
 +    DWORD type = 0, sz = 0;
 +    HKEY hkey = 0;
 +    LONG r;
 +
 +    if (sei->fMask & SEE_MASK_CLASSALL)
 +        return sei->hkeyClass;
 +
 +    if (sei->fMask & SEE_MASK_CLASSNAME)
 +        lpClass = sei->lpClass;
 +    else
 +    {
 +        ext = PathFindExtensionW(sei->lpFile);
 +        TRACE("ext = %s\n", debugstr_w(ext));
 +        if (!ext)
 +            return hkey;
 +
 +        r = RegOpenKeyW(HKEY_CLASSES_ROOT, ext, &hkey);
 +        if (r != ERROR_SUCCESS)
 +            return hkey;
 +
 +        r = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &sz);
 +        if (r == ERROR_SUCCESS && type == REG_SZ)
 +        {
 +            sz += sizeof (WCHAR);
 +            cls = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sz);
 +            cls[0] = 0;
 +            RegQueryValueExW(hkey, NULL, 0, &type, (LPBYTE) cls, &sz);
 +        }
 +
 +        RegCloseKey( hkey );
 +        lpClass = cls;
 +    }
 +
 +    TRACE("class = %s\n", debugstr_w(lpClass));
 +
 +    hkey = 0;
 +    if (lpClass)
 +        RegOpenKeyW( HKEY_CLASSES_ROOT, lpClass, &hkey);
 +
 +    HeapFree(GetProcessHeap(), 0, cls);
 +
 +    return hkey;
 +}
 +
 +static IDataObject *shellex_get_dataobj( LPSHELLEXECUTEINFOW sei )
 +{
 +    LPCITEMIDLIST pidllast = NULL;
 +    IDataObject *dataobj = NULL;
 +    IShellFolder *shf = NULL;
 +    LPITEMIDLIST pidl = NULL;
 +    HRESULT r;
 +
 +    if (sei->fMask & SEE_MASK_CLASSALL)
 +        pidl = (LPITEMIDLIST)sei->lpIDList;
 +    else
 +    {
 +        WCHAR fullpath[MAX_PATH];
 +        BOOL ret;
 +
 +        fullpath[0] = 0;
 +        ret = GetFullPathNameW(sei->lpFile, MAX_PATH, fullpath, NULL);
 +        if (!ret)
 +            goto end;
 +
 +        pidl = ILCreateFromPathW(fullpath);
 +    }
 +
 +    r = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast);
 +    if (FAILED(r))
 +        goto end;
 +
 +    shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IDataObject, &dataobj));
 +
 +end:
 +    if (pidl != sei->lpIDList)
 +        ILFree(pidl);
 +    if (shf)
 +        shf->Release();
 +    return dataobj;
 +}
 +
 +static HRESULT shellex_run_context_menu_default(IShellExtInit *obj,
 +        LPSHELLEXECUTEINFOW sei)
 +{
 +    IContextMenu *cm = NULL;
 +    CMINVOKECOMMANDINFOEX ici;
 +    MENUITEMINFOW info;
 +    WCHAR string[0x80];
 +    INT i, n, def = -1;
 +    HMENU hmenu = 0;
 +    HRESULT r;
 +
 +    TRACE("%p %p\n", obj, sei);
 +
 +    r = obj->QueryInterface(IID_PPV_ARG(IContextMenu, &cm));
 +    if (FAILED(r))
 +        return r;
 +
 +    hmenu = CreateMenu();
 +    if (!hmenu)
 +        goto end;
 +
 +    /* the number of the last menu added is returned in r */
 +    r = cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY);
 +    if (FAILED(r))
 +        goto end;
 +
 +    n = GetMenuItemCount(hmenu);
 +    for (i = 0; i < n; i++)
 +    {
 +        memset(&info, 0, sizeof(info));
 +        info.cbSize = sizeof info;
 +        info.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_DATA | MIIM_ID;
 +        info.dwTypeData = string;
 +        info.cch = sizeof string;
 +        string[0] = 0;
 +        GetMenuItemInfoW(hmenu, i, TRUE, &info);
 +
 +        TRACE("menu %d %s %08x %08lx %08x %08x\n", i, debugstr_w(string),
 +              info.fState, info.dwItemData, info.fType, info.wID);
 +        if ((!sei->lpVerb && (info.fState & MFS_DEFAULT)) ||
 +            (sei->lpVerb && !lstrcmpiW(sei->lpVerb, string)))
 +        {
 +            def = i;
 +            break;
 +        }
 +    }
 +
 +    r = E_FAIL;
 +    if (def == -1)
 +        goto end;
 +
 +    memset(&ici, 0, sizeof ici);
 +    ici.cbSize = sizeof ici;
-     WCHAR execCmd[1024], wcmd[1024];
++    ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (SEE_MASK_NO_CONSOLE | SEE_MASK_NOASYNC | SEE_MASK_ASYNCOK | SEE_MASK_FLAG_NO_UI));
 +    ici.nShow = sei->nShow;
 +    ici.lpVerb = MAKEINTRESOURCEA(def);
 +    ici.hwnd = sei->hwnd;
 +    ici.lpParametersW = sei->lpParameters;
 +
 +    r = cm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
 +
 +    TRACE("invoke command returned %08x\n", r);
 +
 +end:
 +    if (hmenu)
 +        DestroyMenu( hmenu );
 +    if (cm)
 +        cm->Release();
 +    return r;
 +}
 +
 +static HRESULT shellex_load_object_and_run(HKEY hkey, LPCGUID guid, LPSHELLEXECUTEINFOW sei)
 +{
 +    IDataObject *dataobj = NULL;
 +    IObjectWithSite *ows = NULL;
 +    IShellExtInit *obj = NULL;
 +    HRESULT r;
 +
 +    TRACE("%p %s %p\n", hkey, debugstr_guid(guid), sei);
 +
 +    r = CoInitialize(NULL);
 +    if (FAILED(r))
 +        goto end;
 +
 +    r = CoCreateInstance(*guid, NULL, CLSCTX_INPROC_SERVER,
 +                         IID_PPV_ARG(IShellExtInit, &obj));
 +    if (FAILED(r))
 +    {
 +        ERR("failed %08x\n", r);
 +        goto end;
 +    }
 +
 +    dataobj = shellex_get_dataobj(sei);
 +    if (!dataobj)
 +    {
 +        ERR("failed to get data object\n");
 +        goto end;
 +    }
 +
 +    r = obj->Initialize(NULL, dataobj, hkey);
 +    if (FAILED(r))
 +        goto end;
 +
 +    r = obj->QueryInterface(IID_PPV_ARG(IObjectWithSite, &ows));
 +    if (FAILED(r))
 +        goto end;
 +
 +    ows->SetSite(NULL);
 +
 +    r = shellex_run_context_menu_default(obj, sei);
 +
 +end:
 +    if (ows)
 +        ows->Release();
 +    if (dataobj)
 +        dataobj->Release();
 +    if (obj)
 +        obj->Release();
 +    CoUninitialize();
 +    return r;
 +}
 +
 +
 +/*************************************************************************
 + *    ShellExecute_FromContextMenu [Internal]
 + */
 +static LONG ShellExecute_FromContextMenu( LPSHELLEXECUTEINFOW sei )
 +{
 +    HKEY hkey, hkeycm = 0;
 +    WCHAR szguid[39];
 +    HRESULT hr;
 +    GUID guid;
 +    DWORD i;
 +    LONG r;
 +
 +    TRACE("%s\n", debugstr_w(sei->lpFile));
 +
 +    hkey = ShellExecute_GetClassKey(sei);
 +    if (!hkey)
 +        return ERROR_FUNCTION_FAILED;
 +
 +    r = RegOpenKeyW(hkey, L"shellex\\ContextMenuHandlers", &hkeycm);
 +    if (r == ERROR_SUCCESS)
 +    {
 +        i = 0;
 +        while (1)
 +        {
 +            r = RegEnumKeyW(hkeycm, i++, szguid, sizeof(szguid) / sizeof(szguid[0]));
 +            if (r != ERROR_SUCCESS)
 +                break;
 +
 +            hr = CLSIDFromString(szguid, &guid);
 +            if (SUCCEEDED(hr))
 +            {
 +                /* stop at the first one that succeeds in running */
 +                hr = shellex_load_object_and_run(hkey, &guid, sei);
 +                if (SUCCEEDED(hr))
 +                    break;
 +            }
 +        }
 +        RegCloseKey(hkeycm);
 +    }
 +
 +    if (hkey != sei->hkeyClass)
 +        RegCloseKey(hkey);
 +    return r;
 +}
 +
++static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR lpstrProtocol, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc);
++
 +static UINT_PTR SHELL_execute_class(LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
 +{
-     HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL,
-                            (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL,
-                            psei->lpVerb,
-                            execCmd, sizeof(execCmd));
-     /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
-     TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
-     wcmd[0] = '\0';
-     done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen);
-     if (!done && wszApplicationName[0])
++    WCHAR execCmd[1024], classname[1024];
 +    /* launch a document by fileclass like 'WordPad.Document.1' */
 +    /* the Commandline contains 'c:\Path\wordpad.exe "%1"' */
 +    /* FIXME: wcmd should not be of a fixed size. Fixed to 1024, MAX_PATH is way too short! */
 +    ULONG cmask = (psei->fMask & SEE_MASK_CLASSALL);
 +    DWORD resultLen;
 +    BOOL done;
-         strcatW(wcmd, L" ");
-         strcatW(wcmd, wszApplicationName);
++    UINT_PTR rslt;
++    
++    /* FIXME: remove following block when SHELL_quote_and_execute supports hkeyClass parameter */
++    if (cmask != SEE_MASK_CLASSNAME)
 +    {
-     if (resultLen > sizeof(wcmd) / sizeof(WCHAR))
-         ERR("Argify buffer not large enough... truncating\n");
-     return execfunc(wcmd, NULL, FALSE, psei, psei_out);
++        WCHAR wcmd[1024];
++        HCR_GetExecuteCommandW((cmask == SEE_MASK_CLASSKEY) ? psei->hkeyClass : NULL,
++                               (cmask == SEE_MASK_CLASSNAME) ? psei->lpClass : NULL,
++                               psei->lpVerb,
++                               execCmd, sizeof(execCmd));
++
++        /* FIXME: get the extension of lpFile, check if it fits to the lpClass */
++        TRACE("SEE_MASK_CLASSNAME->%s, doc->%s\n", debugstr_w(execCmd), debugstr_w(wszApplicationName));
++
++        wcmd[0] = '\0';
++        done = SHELL_ArgifyW(wcmd, sizeof(wcmd) / sizeof(WCHAR), execCmd, wszApplicationName, (LPITEMIDLIST)psei->lpIDList, NULL, &resultLen);
++        if (!done && wszApplicationName[0])
++        {
++            strcatW(wcmd, L" ");
++            if (*wszApplicationName != '"')
++            {
++                strcatW(wcmd, L"\"");
++                strcatW(wcmd, wszApplicationName);
++                strcatW(wcmd, L"\"");
++            }
++            else
++                strcatW(wcmd, wszApplicationName);
++        }
++        if (resultLen > sizeof(wcmd) / sizeof(WCHAR))
++            ERR("Argify buffer not large enough... truncating\n");
++        return execfunc(wcmd, NULL, FALSE, psei, psei_out);
 +    }
-     if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)))) {
++    
++    strcpyW(classname, psei->lpClass);
++    rslt = SHELL_FindExecutableByVerb(psei->lpVerb, NULL, classname, execCmd, sizeof(execCmd));
++
++    TRACE("SHELL_FindExecutableByVerb returned %u (%s, %s)\n", (unsigned int)rslt, debugstr_w(classname), debugstr_w(execCmd));
++    if (33 > rslt)
++        return rslt;
++    rslt = SHELL_quote_and_execute( execCmd, L"", classname,
++                                      wszApplicationName, NULL, psei,
++                                      psei_out, execfunc );
++    return rslt;
++
 +}
 +
 +static BOOL SHELL_translate_idlist(LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen)
 +{
 +    static const WCHAR wExplorer[] = L"explorer.exe";
 +    WCHAR buffer[MAX_PATH];
 +    BOOL appKnownSingular = FALSE;
 +
 +    /* last chance to translate IDList: now also allow CLSID paths */
- static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR lpstrProtocol, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
++    if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)/sizeof(WCHAR)))) {
 +        if (buffer[0] == ':' && buffer[1] == ':') {
 +            /* open shell folder for the specified class GUID */
 +            if (strlenW(buffer) + 1 > parametersLen)
 +                ERR("parameters len exceeds buffer size (%i > %i), truncating\n",
 +                    lstrlenW(buffer) + 1, parametersLen);
 +            lstrcpynW(wszParameters, buffer, parametersLen);
 +            if (strlenW(wExplorer) > dwApplicationNameLen)
 +                ERR("application len exceeds buffer size (%i > %i), truncating\n",
 +                    lstrlenW(wExplorer) + 1, dwApplicationNameLen);
 +            lstrcpynW(wszApplicationName, wExplorer, dwApplicationNameLen);
 +            appKnownSingular = TRUE;
 +
 +            sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
 +        } else {
 +            WCHAR target[MAX_PATH];
 +            DWORD attribs;
 +            DWORD resultLen;
 +            /* Check if we're executing a directory and if so use the
 +               handler for the Folder class */
 +            strcpyW(target, buffer);
 +            attribs = GetFileAttributesW(buffer);
 +            if (attribs != INVALID_FILE_ATTRIBUTES &&
 +                    (attribs & FILE_ATTRIBUTE_DIRECTORY) &&
 +                    HCR_GetExecuteCommandW(0, L"Folder",
 +                                           sei->lpVerb,
 +                                           buffer, sizeof(buffer))) {
 +                SHELL_ArgifyW(wszApplicationName, dwApplicationNameLen,
 +                              buffer, target, (LPITEMIDLIST)sei->lpIDList, NULL, &resultLen);
 +                if (resultLen > dwApplicationNameLen)
 +                    ERR("Argify buffer not large enough... truncating\n");
 +                appKnownSingular = FALSE;
 +            }
 +            sei->fMask &= ~SEE_MASK_INVOKEIDLIST;
 +        }
 +    }
 +    return appKnownSingular;
 +}
 +
-     TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(lpstrProtocol));
++static UINT_PTR SHELL_quote_and_execute(LPCWSTR wcmd, LPCWSTR wszParameters, LPCWSTR wszKeyname, LPCWSTR wszApplicationName, LPWSTR env, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
 +{
 +    UINT_PTR retval;
 +    DWORD len;
 +    WCHAR *wszQuotedCmd;
 +
 +    /* Length of quotes plus length of command plus NULL terminator */
 +    len = 2 + lstrlenW(wcmd) + 1;
 +    if (wszParameters[0])
 +    {
 +        /* Length of space plus length of parameters */
 +        len += 1 + lstrlenW(wszParameters);
 +    }
 +    wszQuotedCmd = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +    /* Must quote to handle case where cmd contains spaces,
 +     * else security hole if malicious user creates executable file "C:\\Program"
 +     */
 +    strcpyW(wszQuotedCmd, L"\"");
 +    strcatW(wszQuotedCmd, wcmd);
 +    strcatW(wszQuotedCmd, L"\"");
 +    if (wszParameters[0])
 +    {
 +        strcatW(wszQuotedCmd, L" ");
 +        strcatW(wszQuotedCmd, wszParameters);
 +    }
 +
-     if (*lpstrProtocol)
-         retval = execute_from_key(lpstrProtocol, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
++    TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(wszKeyname));
 +
- static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
++    if (*wszKeyname)
++        retval = execute_from_key(wszKeyname, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
 +    else
 +        retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out);
 +    HeapFree(GetProcessHeap(), 0, wszQuotedCmd);
 +    return retval;
 +}
 +
-     /* Looking for ...protocol\shell\lpOperation\command */
++static UINT_PTR SHELL_execute_url(LPCWSTR lpFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc)
 +{
 +    static const WCHAR wShell[] = L"\\shell\\";
 +    static const WCHAR wCommand[] = L"\\command";
 +    UINT_PTR retval;
 +    WCHAR *lpstrProtocol;
 +    LPCWSTR lpstrRes;
 +    INT iSize;
 +    DWORD len;
 +
 +    lpstrRes = strchrW(lpFile, ':');
 +    if (lpstrRes)
 +        iSize = lpstrRes - lpFile;
 +    else
 +        iSize = strlenW(lpFile);
 +
 +    TRACE("Got URL: %s\n", debugstr_w(lpFile));
-     if (psei->lpVerb)
++    /* Looking for ...<protocol>\shell\<lpVerb>\command */
 +    len = iSize + lstrlenW(wShell) + lstrlenW(wCommand) + 1;
-     strcatW(lpstrProtocol, psei->lpVerb ? psei->lpVerb : wszOpen);
++    if (psei->lpVerb && *psei->lpVerb)
 +        len += lstrlenW(psei->lpVerb);
 +    else
 +        len += lstrlenW(wszOpen);
 +    lpstrProtocol = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +    memcpy(lpstrProtocol, lpFile, iSize * sizeof(WCHAR));
 +    lpstrProtocol[iSize] = '\0';
 +    strcatW(lpstrProtocol, wShell);
-     /* Remove File Protocol from lpFile */
-     /* In the case file://path/file     */
-     if (!strncmpiW(lpFile, wFile, iSize))
-     {
-         lpFile += iSize;
-         while (*lpFile == ':') lpFile++;
-     }
++    strcatW(lpstrProtocol, psei->lpVerb && *psei->lpVerb ? psei->lpVerb : wszOpen);
 +    strcatW(lpstrProtocol, wCommand);
 +
- void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename)
 +    retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters,
 +                              wcmd, execfunc, psei, psei_out);
 +    HeapFree(GetProcessHeap(), 0, lpstrProtocol);
 +    return retval;
 +}
 +
- BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
++static void do_error_dialog(UINT_PTR retval, HWND hwnd, WCHAR* filename)
 +{
 +    WCHAR msg[2048];
 +    DWORD_PTR msgArguments[3]  = { (DWORD_PTR)filename, 0, 0 };
 +    DWORD error_code;
 +
 +    error_code = GetLastError();
 +
 +    if (retval == SE_ERR_NOASSOC)
 +        LoadStringW(shell32_hInstance, IDS_SHLEXEC_NOASSOC, msg, sizeof(msg) / sizeof(WCHAR));
 +    else
 +        FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
 +                       NULL,
 +                       error_code,
 +                       LANG_USER_DEFAULT,
 +                       msg,
 +                       sizeof(msg) / sizeof(WCHAR),
 +                       (va_list*)msgArguments);
 +
 +    MessageBoxW(hwnd, msg, NULL, MB_ICONERROR);
 +}
 +
 +/*************************************************************************
 + *    SHELL_execute [Internal]
 + */
-     WCHAR lpstrProtocol[256];
++static BOOL SHELL_execute(LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc)
 +{
 +    static const DWORD unsupportedFlags =
 +        SEE_MASK_INVOKEIDLIST  | SEE_MASK_ICON         | SEE_MASK_HOTKEY |
 +        SEE_MASK_CONNECTNETDRV | SEE_MASK_FLAG_DDEWAIT |
 +        SEE_MASK_UNICODE       | SEE_MASK_ASYNCOK      | SEE_MASK_HMONITOR;
 +
 +    WCHAR parametersBuffer[1024], dirBuffer[MAX_PATH], wcmdBuffer[1024];
 +    WCHAR *wszApplicationName, *wszParameters, *wszDir, *wcmd;
 +    DWORD dwApplicationNameLen = MAX_PATH + 2;
 +    DWORD parametersLen = sizeof(parametersBuffer) / sizeof(WCHAR);
 +    DWORD dirLen = sizeof(dirBuffer) / sizeof(WCHAR);
 +    DWORD wcmdLen = sizeof(wcmdBuffer) / sizeof(WCHAR);
 +    DWORD len;
 +    SHELLEXECUTEINFOW sei_tmp;    /* modifiable copy of SHELLEXECUTEINFO struct */
 +    WCHAR wfileName[MAX_PATH];
 +    WCHAR *env;
-     /* expand environment strings */
-     len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0);
-     if (len > 0)
++    WCHAR wszKeyname[256];
 +    LPCWSTR lpFile;
 +    UINT_PTR retval = SE_ERR_NOASSOC;
 +    BOOL appKnownSingular = FALSE;
 +
 +    /* make a local copy of the LPSHELLEXECUTEINFO structure and work with this from now on */
 +    sei_tmp = *sei;
 +
 +    TRACE("mask=0x%08x hwnd=%p verb=%s file=%s parm=%s dir=%s show=0x%08x class=%s\n",
 +          sei_tmp.fMask, sei_tmp.hwnd, debugstr_w(sei_tmp.lpVerb),
 +          debugstr_w(sei_tmp.lpFile), debugstr_w(sei_tmp.lpParameters),
 +          debugstr_w(sei_tmp.lpDirectory), sei_tmp.nShow,
 +          ((sei_tmp.fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME) ?
 +          debugstr_w(sei_tmp.lpClass) : "not used");
 +
 +    sei->hProcess = NULL;
 +
 +    /* make copies of all path/command strings */
 +    if (!sei_tmp.lpFile)
 +    {
 +        wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR));
 +        *wszApplicationName = '\0';
 +    }
 +    else if (*sei_tmp.lpFile == '\"')
 +    {
 +        DWORD l = strlenW(sei_tmp.lpFile + 1);
 +        if(l >= dwApplicationNameLen)
 +            dwApplicationNameLen = l + 1;
 +
 +        wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR));
 +        memcpy(wszApplicationName, sei_tmp.lpFile + 1, (l + 1)*sizeof(WCHAR));
 +
 +        if (wszApplicationName[l-1] == L'\"')
 +            wszApplicationName[l-1] = L'\0';
 +        appKnownSingular = TRUE;
 +
 +        TRACE("wszApplicationName=%s\n", debugstr_w(wszApplicationName));
 +    }
 +    else
 +    {
 +        DWORD l = strlenW(sei_tmp.lpFile) + 1;
 +        if(l > dwApplicationNameLen) dwApplicationNameLen = l + 1;
 +        wszApplicationName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwApplicationNameLen * sizeof(WCHAR));
 +        memcpy(wszApplicationName, sei_tmp.lpFile, l * sizeof(WCHAR));
 +    }
 +
 +    wszParameters = parametersBuffer;
 +    if (sei_tmp.lpParameters)
 +    {
 +        len = lstrlenW(sei_tmp.lpParameters) + 1;
 +        if (len > parametersLen)
 +        {
 +            wszParameters = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +            parametersLen = len;
 +        }
 +        strcpyW(wszParameters, sei_tmp.lpParameters);
 +    }
 +    else
 +        *wszParameters = L'\0';
 +
 +    wszDir = dirBuffer;
 +    if (sei_tmp.lpDirectory)
 +    {
 +        len = lstrlenW(sei_tmp.lpDirectory) + 1;
 +        if (len > dirLen)
 +        {
 +            wszDir = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +            dirLen = len;
 +        }
 +        strcpyW(wszDir, sei_tmp.lpDirectory);
 +    }
 +    else
 +        *wszDir = L'\0';
 +
 +    /* adjust string pointers to point to the new buffers */
 +    sei_tmp.lpFile = wszApplicationName;
 +    sei_tmp.lpParameters = wszParameters;
 +    sei_tmp.lpDirectory = wszDir;
 +
 +    if (sei_tmp.fMask & unsupportedFlags)
 +    {
 +        FIXME("flags ignored: 0x%08x\n", sei_tmp.fMask & unsupportedFlags);
 +    }
 +
 +    /* process the IDList */
 +    if (sei_tmp.fMask & SEE_MASK_IDLIST)
 +    {
 +        IShellExecuteHookW* pSEH;
 +
 +        HRESULT hr = SHBindToParent((LPCITEMIDLIST)sei_tmp.lpIDList, IID_PPV_ARG(IShellExecuteHookW, &pSEH), NULL);
 +
 +        if (SUCCEEDED(hr))
 +        {
 +            hr = pSEH->Execute(&sei_tmp);
 +
 +            pSEH->Release();
 +
 +            if (hr == S_OK)
 +            {
 +                HeapFree(GetProcessHeap(), 0, wszApplicationName);
 +                if (wszParameters != parametersBuffer)
 +                    HeapFree(GetProcessHeap(), 0, wszParameters);
 +                if (wszDir != dirBuffer)
 +                    HeapFree(GetProcessHeap(), 0, wszDir);
 +                return TRUE;
 +            }
 +        }
 +
 +        SHGetPathFromIDListW((LPCITEMIDLIST)sei_tmp.lpIDList, wszApplicationName);
 +        appKnownSingular = TRUE;
 +        TRACE("-- idlist=%p (%s)\n", sei_tmp.lpIDList, debugstr_w(wszApplicationName));
 +    }
 +
 +    if (ERROR_SUCCESS == ShellExecute_FromContextMenu(&sei_tmp))
 +    {
 +        sei->hInstApp = (HINSTANCE) 33;
 +        HeapFree(GetProcessHeap(), 0, wszApplicationName);
 +        if (wszParameters != parametersBuffer)
 +            HeapFree(GetProcessHeap(), 0, wszParameters);
 +        if (wszDir != dirBuffer)
 +            HeapFree(GetProcessHeap(), 0, wszDir);
 +        return TRUE;
 +    }
 +
 +    if (sei_tmp.fMask & SEE_MASK_CLASSALL)
 +    {
 +        retval = SHELL_execute_class(wszApplicationName, &sei_tmp, sei, execfunc);
 +        if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
 +        {
 +            OPENASINFO Info;
 +
 +            //FIXME
 +            // need full path
 +
 +            Info.pcszFile = wszApplicationName;
 +            Info.pcszClass = NULL;
 +            Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
 +
 +            //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
 +            do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
 +        }
 +        HeapFree(GetProcessHeap(), 0, wszApplicationName);
 +        if (wszParameters != parametersBuffer)
 +            HeapFree(GetProcessHeap(), 0, wszParameters);
 +        if (wszDir != dirBuffer)
 +            HeapFree(GetProcessHeap(), 0, wszDir);
 +        return retval > 32;
 +    }
 +
 +    /* Has the IDList not yet been translated? */
 +    if (sei_tmp.fMask & SEE_MASK_IDLIST)
 +    {
 +        appKnownSingular = SHELL_translate_idlist( &sei_tmp, wszParameters,
 +                           parametersLen,
 +                           wszApplicationName,
 +                           dwApplicationNameLen );
 +    }
 +
-         buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
++    /* convert file URLs */
++    if (UrlIsFileUrlW(sei_tmp.lpFile))
 +    {
 +        LPWSTR buf;
-         ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1);
++        DWORD size;
++
++        size = MAX_PATH;
++        buf = static_cast<LPWSTR>(HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)));
++        if (!buf || FAILED(PathCreateFromUrlW(sei_tmp.lpFile, buf, &size, 0)))
++        {
++            HeapFree(GetProcessHeap(), 0, buf);
++            return SE_ERR_OOM;
++        }
 +
-         dwApplicationNameLen = len + 1;
 +        HeapFree(GetProcessHeap(), 0, wszApplicationName);
-         /* appKnownSingular unmodified */
++        dwApplicationNameLen = lstrlenW(buf) + 1;
 +        wszApplicationName = buf;
-     if (*sei_tmp.lpParameters)
 +        sei_tmp.lpFile = wszApplicationName;
 +    }
-         len = ExpandEnvironmentStringsW(sei_tmp.lpParameters, NULL, 0);
++    else /* or expand environment strings (not both!) */
 +    {
-             len++;
-             buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-             ExpandEnvironmentStringsW(sei_tmp.lpParameters, buf, len);
-             if (wszParameters != parametersBuffer)
-                 HeapFree(GetProcessHeap(), 0, wszParameters);
-             wszParameters = buf;
-             parametersLen = len;
-             sei_tmp.lpParameters = wszParameters;
++        len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0);
 +        if (len > 0)
 +        {
 +            LPWSTR buf;
-             lstrcpynW(wfileName, sei_tmp.lpFile, sizeof(wfileName) / sizeof(WCHAR));
++            buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
++
++            ExpandEnvironmentStringsW(sei_tmp.lpFile, buf, len + 1);
++            HeapFree(GetProcessHeap(), 0, wszApplicationName);
++            dwApplicationNameLen = len + 1;
++            wszApplicationName = buf;
++            /* appKnownSingular unmodified */
++
++            sei_tmp.lpFile = wszApplicationName;
 +        }
 +    }
 +
 +    if (*sei_tmp.lpDirectory)
 +    {
 +        len = ExpandEnvironmentStringsW(sei_tmp.lpDirectory, NULL, 0);
 +        if (len > 0)
 +        {
 +            LPWSTR buf;
 +            len++;
 +            buf = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +            ExpandEnvironmentStringsW(sei_tmp.lpDirectory, buf, len);
 +            if (wszDir != dirBuffer)
 +                HeapFree(GetProcessHeap(), 0, wszDir);
 +            wszDir = buf;
 +            sei_tmp.lpDirectory = wszDir;
 +        }
 +    }
 +
 +    /* Else, try to execute the filename */
 +    TRACE("execute: %s,%s,%s\n", debugstr_w(wszApplicationName), debugstr_w(wszParameters), debugstr_w(wszDir));
 +
 +    /* separate out command line arguments from executable file name */
 +    if (!*sei_tmp.lpParameters && !appKnownSingular)
 +    {
 +        /* If the executable path is quoted, handle the rest of the command line as parameters. */
 +        if (sei_tmp.lpFile[0] == L'"')
 +        {
 +            LPWSTR src = wszApplicationName/*sei_tmp.lpFile*/ + 1;
 +            LPWSTR dst = wfileName;
 +            LPWSTR end;
 +
 +            /* copy the unquoted executable path to 'wfileName' */
 +            while(*src && *src != L'"')
 +                *dst++ = *src++;
 +
 +            *dst = L'\0';
 +
 +            if (*src == L'"')
 +            {
 +                end = ++src;
 +
 +                while(isspace(*src))
 +                    ++src;
 +            }
 +            else
 +                end = src;
 +
 +            /* copy the parameter string to 'wszParameters' */
 +            strcpyW(wszParameters, src);
 +
 +            /* terminate previous command string after the quote character */
 +            *end = L'\0';
++            lpFile = wfileName;
 +        }
 +        else
 +        {
 +            /* If the executable name is not quoted, we have to use this search loop here,
 +               that in CreateProcess() is not sufficient because it does not handle shell links. */
 +            WCHAR buffer[MAX_PATH], xlpFile[MAX_PATH];
 +            LPWSTR space, s;
 +
 +            LPWSTR beg = wszApplicationName/*sei_tmp.lpFile*/;
 +            for(s = beg; (space = const_cast<LPWSTR>(strchrW(s, L' '))); s = space + 1)
 +            {
 +                int idx = space - sei_tmp.lpFile;
 +                memcpy(buffer, sei_tmp.lpFile, idx * sizeof(WCHAR));
 +                buffer[idx] = '\0';
 +
 +                /*FIXME This finds directory paths if the targeted file name contains spaces. */
 +                if (SearchPathW(*sei_tmp.lpDirectory ? sei_tmp.lpDirectory : NULL, buffer, wszExe, sizeof(xlpFile) / sizeof(xlpFile[0]), xlpFile, NULL))
 +                {
 +                    /* separate out command from parameter string */
 +                    LPCWSTR p = space + 1;
 +
 +                    while(isspaceW(*p))
 +                        ++p;
 +
 +                    strcpyW(wszParameters, p);
 +                    *space = L'\0';
 +
 +                    break;
 +                }
 +            }
 +
-         lstrcpynW(wfileName, sei_tmp.lpFile, sizeof(wfileName) / sizeof(WCHAR));
-     lpFile = wfileName;
++            lpFile = sei_tmp.lpFile;
 +        }
 +    }
 +    else
-     retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, lpstrProtocol, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
++        lpFile = sei_tmp.lpFile;
 +
 +    wcmd = wcmdBuffer;
 +    len = lstrlenW(wszApplicationName) + 3;
 +    if (sei_tmp.lpParameters[0])
 +        len += 1 + lstrlenW(wszParameters);
 +    if (len > wcmdLen)
 +    {
 +        wcmd = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 +        wcmdLen = len;
 +    }
 +    swprintf(wcmd, L"\"%s\"", wszApplicationName);
 +    if (sei_tmp.lpParameters[0])
 +    {
 +        strcatW(wcmd, L" ");
 +        strcatW(wcmd, wszParameters);
 +    }
 +
 +    retval = execfunc(wcmd, NULL, FALSE, &sei_tmp, sei);
 +    if (retval > 32)
 +    {
 +        HeapFree(GetProcessHeap(), 0, wszApplicationName);
 +        if (wszParameters != parametersBuffer)
 +            HeapFree(GetProcessHeap(), 0, wszParameters);
 +        if (wszDir != dirBuffer)
 +            HeapFree(GetProcessHeap(), 0, wszDir);
 +        if (wcmd != wcmdBuffer)
 +            HeapFree(GetProcessHeap(), 0, wcmd);
 +        return TRUE;
 +    }
 +
 +    /* Else, try to find the executable */
 +    wcmd[0] = L'\0';
-         retval = SHELL_quote_and_execute(wcmd, wszParameters, lpstrProtocol,
++    retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, wszKeyname, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
 +    if (retval > 32)  /* Found */
 +    {
-                                                  lpstrProtocol,
++        retval = SHELL_quote_and_execute(wcmd, wszParameters, wszKeyname,
 +                                         wszApplicationName, env, &sei_tmp,
 +                                         sei, execfunc);
 +        HeapFree(GetProcessHeap(), 0, env);
 +    }
 +    else if (PathIsDirectoryW(lpFile))
 +    {
 +        WCHAR wExec[MAX_PATH];
 +        WCHAR * lpQuotedFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (strlenW(lpFile) + 3));
 +
 +        if (lpQuotedFile)
 +        {
 +            retval = SHELL_FindExecutable(sei_tmp.lpDirectory, L"explorer",
 +                                          wszOpen, wExec, MAX_PATH,
 +                                          NULL, &env, NULL, NULL);
 +            if (retval > 32)
 +            {
 +                swprintf(lpQuotedFile, L"\"%s\"", lpFile);
 +                retval = SHELL_quote_and_execute(wExec, lpQuotedFile,
-         retval = SHELL_execute_url(lpFile, L"file", wcmd, &sei_tmp, sei, execfunc );
++                                                 wszKeyname,
 +                                                 wszApplicationName, env,
 +                                                 &sei_tmp, sei, execfunc);
 +                HeapFree(GetProcessHeap(), 0, env);
 +            }
 +            HeapFree(GetProcessHeap(), 0, lpQuotedFile);
 +        }
 +        else
 +            retval = 0; /* Out of memory */
 +    }
 +    else if (PathIsURLW(lpFile))    /* File not found, check for URL */
 +    {
-         /* if so, append lpFile http:// and call ShellExecute */
++        retval = SHELL_execute_url(lpFile, wcmd, &sei_tmp, sei, execfunc );
 +    }
 +    /* Check if file specified is in the form www.??????.*** */
 +    else if (!strncmpiW(lpFile, L"www", 3))
 +    {
- HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile,
++        /* if so, prefix lpFile with http:// and call ShellExecute */
 +        WCHAR lpstrTmpFile[256];
 +        strcpyW(lpstrTmpFile, L"http://");
 +        strcatW(lpstrTmpFile, lpFile);
 +        retval = (UINT_PTR)ShellExecuteW(sei_tmp.hwnd, sei_tmp.lpVerb, lpstrTmpFile, NULL, NULL, 0);
 +    }
 +
 +    TRACE("retval %lu\n", retval);
 +
 +    if (retval <= 32 && !(sei_tmp.fMask & SEE_MASK_FLAG_NO_UI))
 +    {
 +        OPENASINFO Info;
 +
 +        //FIXME
 +        // need full path
 +
 +        Info.pcszFile = wszApplicationName;
 +        Info.pcszClass = NULL;
 +        Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_EXEC;
 +
 +        //if (SHOpenWithDialog(sei_tmp.hwnd, &Info) != S_OK)
 +        do_error_dialog(retval, sei_tmp.hwnd, wszApplicationName);
 +    }
 +
 +    HeapFree(GetProcessHeap(), 0, wszApplicationName);
 +    if (wszParameters != parametersBuffer)
 +        HeapFree(GetProcessHeap(), 0, wszParameters);
 +    if (wszDir != dirBuffer)
 +        HeapFree(GetProcessHeap(), 0, wszDir);
 +    if (wcmd != wcmdBuffer)
 +        HeapFree(GetProcessHeap(), 0, wcmd);
 +
 +    sei->hInstApp = (HINSTANCE)(retval > 32 ? 33 : retval);
 +
 +    return retval > 32;
 +}
 +
 +/*************************************************************************
 + * ShellExecuteA            [SHELL32.290]
 + */
-           hWnd, debugstr_a(lpOperation), debugstr_a(lpFile),
++HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile,
 +                               LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
 +{
 +    SHELLEXECUTEINFOA sei;
 +
 +    TRACE("%p,%s,%s,%s,%s,%d\n",
-     sei.lpVerb = lpOperation;
++          hWnd, debugstr_a(lpVerb), debugstr_a(lpFile),
 +          debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd);
 +
 +    sei.cbSize = sizeof(sei);
 +    sei.fMask = SEE_MASK_FLAG_NO_UI;
 +    sei.hwnd = hWnd;
-  * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpOperation,
++    sei.lpVerb = lpVerb;
 +    sei.lpFile = lpFile;
 +    sei.lpParameters = lpParameters;
 +    sei.lpDirectory = lpDirectory;
 +    sei.nShow = iShowCmd;
 +    sei.lpIDList = 0;
 +    sei.lpClass = 0;
 +    sei.hkeyClass = 0;
 +    sei.dwHotKey = 0;
 +    sei.hProcess = 0;
 +
 +    ShellExecuteExA(&sei);
 +    return sei.hInstApp;
 +}
 +
 +/*************************************************************************
 + * ShellExecuteExA                [SHELL32.292]
 + *
 + */
 +BOOL
 +WINAPI
 +DECLSPEC_HOTPATCH
 +ShellExecuteExA(LPSHELLEXECUTEINFOA sei)
 +{
 +    SHELLEXECUTEINFOW seiW;
 +    BOOL ret;
 +    WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL, *wClass = NULL;
 +
 +    TRACE("%p\n", sei);
 +
 +    memcpy(&seiW, sei, sizeof(SHELLEXECUTEINFOW));
 +
 +    if (sei->lpVerb)
 +        seiW.lpVerb = __SHCloneStrAtoW(&wVerb, sei->lpVerb);
 +
 +    if (sei->lpFile)
 +        seiW.lpFile = __SHCloneStrAtoW(&wFile, sei->lpFile);
 +
 +    if (sei->lpParameters)
 +        seiW.lpParameters = __SHCloneStrAtoW(&wParameters, sei->lpParameters);
 +
 +    if (sei->lpDirectory)
 +        seiW.lpDirectory = __SHCloneStrAtoW(&wDirectory, sei->lpDirectory);
 +
 +    if ((sei->fMask & SEE_MASK_CLASSALL) == SEE_MASK_CLASSNAME && sei->lpClass)
 +        seiW.lpClass = __SHCloneStrAtoW(&wClass, sei->lpClass);
 +    else
 +        seiW.lpClass = NULL;
 +
 +    ret = SHELL_execute(&seiW, SHELL_ExecuteW);
 +
 +    sei->hInstApp = seiW.hInstApp;
 +
 +    if (sei->fMask & SEE_MASK_NOCLOSEPROCESS)
 +        sei->hProcess = seiW.hProcess;
 +
 +    SHFree(wVerb);
 +    SHFree(wFile);
 +    SHFree(wParameters);
 +    SHFree(wDirectory);
 +    SHFree(wClass);
 +
 +    return ret;
 +}
 +
 +/*************************************************************************
 + * ShellExecuteExW                [SHELL32.293]
 + *
 + */
 +BOOL
 +WINAPI
 +DECLSPEC_HOTPATCH
 +ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
 +{
 +    return SHELL_execute(sei, SHELL_ExecuteW);
 +}
 +
 +/*************************************************************************
 + * ShellExecuteW            [SHELL32.294]
 + * from shellapi.h
- HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile,
++ * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpVerb,
 + * LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);
 + */
-     sei.lpVerb = lpOperation;
++HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile,
 +                               LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
 +{
 +    SHELLEXECUTEINFOW sei;
 +
 +    TRACE("\n");
 +    sei.cbSize = sizeof(sei);
 +    sei.fMask = SEE_MASK_FLAG_NO_UI;
 +    sei.hwnd = hwnd;
- EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile,
++    sei.lpVerb = lpVerb;
 +    sei.lpFile = lpFile;
 +    sei.lpParameters = lpParameters;
 +    sei.lpDirectory = lpDirectory;
 +    sei.nShow = nShowCmd;
 +    sei.lpIDList = 0;
 +    sei.lpClass = 0;
 +    sei.hkeyClass = 0;
 +    sei.dwHotKey = 0;
 +    sei.hProcess = 0;
 +
 +    SHELL_execute(&sei, SHELL_ExecuteW);
 +    return sei.hInstApp;
 +}
 +
 +/*************************************************************************
 + * WOWShellExecute            [SHELL32.@]
 + *
 + * FIXME: the callback function most likely doesn't work the same way on Windows.
 + */
-     seiW.lpVerb = lpOperation ? __SHCloneStrAtoW(&wVerb, lpOperation) : NULL;
++EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpVerb, LPCSTR lpFile,
 +        LPCSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd, void *callback)
 +{
 +    SHELLEXECUTEINFOW seiW;
 +    WCHAR *wVerb = NULL, *wFile = NULL, *wParameters = NULL, *wDirectory = NULL;
 +    HANDLE hProcess = 0;
 +
++    seiW.lpVerb = lpVerb ? __SHCloneStrAtoW(&wVerb, lpVerb) : NULL;
 +    seiW.lpFile = lpFile ? __SHCloneStrAtoW(&wFile, lpFile) : NULL;
 +    seiW.lpParameters = lpParameters ? __SHCloneStrAtoW(&wParameters, lpParameters) : NULL;
 +    seiW.lpDirectory = lpDirectory ? __SHCloneStrAtoW(&wDirectory, lpDirectory) : NULL;
 +
 +    seiW.cbSize = sizeof(seiW);
 +    seiW.fMask = 0;
 +    seiW.hwnd = hWnd;
 +    seiW.nShow = iShowCmd;
 +    seiW.lpIDList = 0;
 +    seiW.lpClass = 0;
 +    seiW.hkeyClass = 0;
 +    seiW.dwHotKey = 0;
 +    seiW.hProcess = hProcess;
 +
 +    SHELL_execute(&seiW, (SHELL_ExecuteW32)callback);
 +
 +    SHFree(wVerb);
 +    SHFree(wFile);
 +    SHFree(wParameters);
 +    SHFree(wDirectory);
 +    return seiW.hInstApp;
 +}
 +
 +/*************************************************************************
 + * OpenAs_RunDLLA          [SHELL32.@]
 + */
 +EXTERN_C void WINAPI OpenAs_RunDLLA(HWND hwnd, HINSTANCE hinst, LPCSTR cmdline, int cmdshow)
 +{
 +    FIXME("%p, %p, %s, %d\n", hwnd, hinst, debugstr_a(cmdline), cmdshow);
 +}
 +
 +/*************************************************************************
 + * OpenAs_RunDLLW          [SHELL32.@]
 + */
 +EXTERN_C void WINAPI OpenAs_RunDLLW(HWND hwnd, HINSTANCE hinst, LPCWSTR cmdline, int cmdshow)
 +{
 +    FIXME("%p, %p, %s, %d\n", hwnd, hinst, debugstr_w(cmdline), cmdshow);
 +}
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 7dba263,0000000..13d2732
mode 100644,000000..100644
--- /dev/null
@@@ -1,4493 -1,0 +1,4517 @@@
-          hNewMenu = co_IntLoadSysMenuTemplate();
 +/*
 + * COPYRIGHT:        See COPYING in the top level directory
 + * PROJECT:          ReactOS Win32k subsystem
 + * PURPOSE:          Windows
 + * FILE:             subsystems/win32/win32k/ntuser/window.c
 + * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
 + */
 +
 +#include <win32k.h>
 +DBG_DEFAULT_CHANNEL(UserWnd);
 +
 +INT gNestedWindowLimit = 50;
 +
 +/* HELPER FUNCTIONS ***********************************************************/
 +
 +BOOL FASTCALL UserUpdateUiState(PWND Wnd, WPARAM wParam)
 +{
 +    WORD Action = LOWORD(wParam);
 +    WORD Flags = HIWORD(wParam);
 +
 +    if (Flags & ~(UISF_HIDEFOCUS | UISF_HIDEACCEL | UISF_ACTIVE))
 +    {
 +        EngSetLastError(ERROR_INVALID_PARAMETER);
 +        return FALSE;
 +    }
 +
 +    switch (Action)
 +    {
 +        case UIS_INITIALIZE:
 +            EngSetLastError(ERROR_INVALID_PARAMETER);
 +            return FALSE;
 +
 +        case UIS_SET:
 +            if (Flags & UISF_HIDEFOCUS)
 +                Wnd->HideFocus = TRUE;
 +            if (Flags & UISF_HIDEACCEL)
 +                Wnd->HideAccel = TRUE;
 +            break;
 +
 +        case UIS_CLEAR:
 +            if (Flags & UISF_HIDEFOCUS)
 +                Wnd->HideFocus = FALSE;
 +            if (Flags & UISF_HIDEACCEL)
 +                Wnd->HideAccel = FALSE;
 +            break;
 +    }
 +
 +    return TRUE;
 +}
 +
 +PWND FASTCALL IntGetWindowObject(HWND hWnd)
 +{
 +   PWND Window;
 +
 +   if (!hWnd) return NULL;
 +
 +   Window = UserGetWindowObject(hWnd);
 +   if (Window)
 +      Window->head.cLockObj++;
 +
 +   return Window;
 +}
 +
 +PWND FASTCALL VerifyWnd(PWND pWnd)
 +{
 +   HWND hWnd;
 +   UINT State, State2;
 +
 +   if (!pWnd) return NULL;
 +
 +   _SEH2_TRY
 +   {
 +      hWnd = UserHMGetHandle(pWnd);
 +      State = pWnd->state;
 +      State2 = pWnd->state2;
 +   }
 +   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +   {
 +      _SEH2_YIELD(return NULL);
 +   }
 +   _SEH2_END
 +
 +   if ( UserObjectInDestroy(hWnd) ||
 +        State & WNDS_DESTROYED ||
 +        State2 & WNDS2_INDESTROY )
 +      return NULL;
 +
 +   return pWnd;
 +}
 +
 +PWND FASTCALL ValidateHwndNoErr(HWND hWnd)
 +{
 +   if (hWnd) return (PWND)UserGetObjectNoErr(gHandleTable, hWnd, TYPE_WINDOW);
 +   return NULL;
 +}
 +
 +/* Temp HACK */
 +PWND FASTCALL UserGetWindowObject(HWND hWnd)
 +{
 +    PWND Window;
 +
 +   if (!hWnd)
 +   {
 +      EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
 +      return NULL;
 +   }
 +
 +   Window = (PWND)UserGetObject(gHandleTable, hWnd, TYPE_WINDOW);
 +   if (!Window || 0 != (Window->state & WNDS_DESTROYED))
 +   {
 +      EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
 +      return NULL;
 +   }
 +
 +   return Window;
 +}
 +
 +ULONG FASTCALL
 +IntSetStyle( PWND pwnd, ULONG set_bits, ULONG clear_bits )
 +{
 +    ULONG styleOld, styleNew;
 +    styleOld = pwnd->style;
 +    styleNew = (pwnd->style | set_bits) & ~clear_bits;
 +    if (styleNew == styleOld) return styleNew;
 +    pwnd->style = styleNew;
 +    if ((styleOld ^ styleNew) & WS_VISIBLE) // State Change.
 +    {
 +       if (styleOld & WS_VISIBLE) pwnd->head.pti->cVisWindows--; 
 +       if (styleNew & WS_VISIBLE) pwnd->head.pti->cVisWindows++;
 +       DceResetActiveDCEs( pwnd );
 +    }
 +    return styleOld;
 +}
 +
 +/*
 + * IntIsWindow
 + *
 + * The function determines whether the specified window handle identifies
 + * an existing window.
 + *
 + * Parameters
 + *    hWnd
 + *       Handle to the window to test.
 + *
 + * Return Value
 + *    If the window handle identifies an existing window, the return value
 + *    is TRUE. If the window handle does not identify an existing window,
 + *    the return value is FALSE.
 + */
 +
 +BOOL FASTCALL
 +IntIsWindow(HWND hWnd)
 +{
 +   PWND Window;
 +
 +   if (!(Window = UserGetWindowObject(hWnd)))
 +   {
 +      return FALSE;
 +   }
 +
 +   return TRUE;
 +}
 +
 +BOOL FASTCALL
 +IntIsWindowVisible(PWND Wnd)
 +{
 +   PWND Temp = Wnd;
 +   for (;;)
 +   {
 +      if (!Temp) return TRUE;
 +      if (!(Temp->style & WS_VISIBLE)) break;
 +      if (Temp->style & WS_MINIMIZE && Temp != Wnd) break;
 +      if (Temp->fnid == FNID_DESKTOP) return TRUE;
 +      Temp = Temp->spwndParent;
 +   }
 +   return FALSE;
 +}
 +
 +PWND FASTCALL
 +IntGetParent(PWND Wnd)
 +{
 +   if (Wnd->style & WS_POPUP)
 +   {
 +      return Wnd->spwndOwner;
 +   }
 +   else if (Wnd->style & WS_CHILD)
 +   {
 +      return Wnd->spwndParent;
 +   }
 +
 +   return NULL;
 +}
 +
 +BOOL
 +FASTCALL
 +IntEnableWindow( HWND hWnd, BOOL bEnable )
 +{
 +   BOOL Update;
 +   PWND pWnd;
 +   UINT bIsDisabled;
 +
 +   if(!(pWnd = UserGetWindowObject(hWnd)))
 +   {
 +      return FALSE;
 +   }
 +
 +   /* check if updating is needed */
 +   bIsDisabled = !!(pWnd->style & WS_DISABLED);
 +   Update = bIsDisabled;
 +
 +    if (bEnable)
 +    {
 +       IntSetStyle( pWnd, 0, WS_DISABLED );
 +    }
 +    else
 +    {
 +       Update = !bIsDisabled;
 +
 +       co_IntSendMessage( hWnd, WM_CANCELMODE, 0, 0);
 +
 +       /* Remove keyboard focus from that window if it had focus */
 +       if (hWnd == IntGetThreadFocusWindow())
 +       {
 +          TRACE("IntEnableWindow SF NULL\n");
 +          co_UserSetFocus(NULL);
 +       }
 +       IntSetStyle( pWnd, WS_DISABLED, 0 );
 +    }
 +
 +    if (Update)
 +    {
 +        IntNotifyWinEvent(EVENT_OBJECT_STATECHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
 +        co_IntSendMessage(hWnd, WM_ENABLE, (LPARAM)bEnable, 0);
 +    }
 +    // Return nonzero if it was disabled, or zero if it wasn't:
 +    return bIsDisabled;
 +}
 +
 +/*
 + * IntWinListChildren
 + *
 + * Compile a list of all child window handles from given window.
 + *
 + * Remarks
 + *    This function is similar to Wine WIN_ListChildren. The caller
 + *    must free the returned list with ExFreePool.
 + */
 +
 +HWND* FASTCALL
 +IntWinListChildren(PWND Window)
 +{
 +   PWND Child;
 +   HWND *List;
 +   UINT Index, NumChildren = 0;
 +
 +   if (!Window) return NULL;
 +
 +   for (Child = Window->spwndChild; Child; Child = Child->spwndNext)
 +      ++NumChildren;
 +
 +   List = ExAllocatePoolWithTag(PagedPool, (NumChildren + 1) * sizeof(HWND), USERTAG_WINDOWLIST);
 +   if(!List)
 +   {
 +      ERR("Failed to allocate memory for children array\n");
 +      EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
 +      return NULL;
 +   }
 +   for (Child = Window->spwndChild, Index = 0;
 +         Child != NULL;
 +         Child = Child->spwndNext, ++Index)
 +      List[Index] = Child->head.h;
 +   List[Index] = NULL;
 +
 +   return List;
 +}
 +
 +PWND FASTCALL
 +IntGetNonChildAncestor(PWND pWnd)
 +{
 +   while(pWnd && (pWnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
 +      pWnd = pWnd->spwndParent;
 +   return pWnd;
 +}
 +
 +BOOL FASTCALL
 +IntIsTopLevelWindow(PWND pWnd)
 +{
 +   if ( pWnd->spwndParent &&
 +        pWnd->spwndParent == co_GetDesktopWindow(pWnd) ) return TRUE;
 +   return FALSE;
 +}
 +
 +BOOL FASTCALL
 +IntValidateOwnerDepth(PWND Wnd, PWND Owner)
 +{
 +   INT Depth = 1;
 +   for (;;)
 +   {
 +      if ( !Owner ) return gNestedWindowLimit >= Depth;
 +      if (Owner == Wnd) break;
 +      Owner = Owner->spwndOwner;
 +      Depth++;
 +   }
 +   return FALSE;
 +}
 +
 +HWND FASTCALL
 +IntGetWindow(HWND hWnd,
 +          UINT uCmd)
 +{
 +    PWND Wnd, FoundWnd;
 +    HWND Ret = NULL;
 +
 +    Wnd = ValidateHwndNoErr(hWnd);
 +    if (!Wnd)
 +        return NULL;
 +
 +    FoundWnd = NULL;
 +    switch (uCmd)
 +    {
 +            case GW_OWNER:
 +                if (Wnd->spwndOwner != NULL)
 +                    FoundWnd = Wnd->spwndOwner;
 +                break;
 +
 +            case GW_HWNDFIRST:
 +                if(Wnd->spwndParent != NULL)
 +                {
 +                    FoundWnd = Wnd->spwndParent;
 +                    if (FoundWnd->spwndChild != NULL)
 +                        FoundWnd = FoundWnd->spwndChild;
 +                }
 +                break;
 +            case GW_HWNDNEXT:
 +                if (Wnd->spwndNext != NULL)
 +                    FoundWnd = Wnd->spwndNext;
 +                break;
 +
 +            case GW_HWNDPREV:
 +                if (Wnd->spwndPrev != NULL)
 +                    FoundWnd = Wnd->spwndPrev;
 +                break;
 +   
 +            case GW_CHILD:
 +                if (Wnd->spwndChild != NULL)
 +                    FoundWnd = Wnd->spwndChild;
 +                break;
 +
 +            case GW_HWNDLAST:
 +                FoundWnd = Wnd;
 +                while ( FoundWnd->spwndNext != NULL)
 +                    FoundWnd = FoundWnd->spwndNext;
 +                break;
 +
 +            default:
 +                Wnd = NULL;
 +                break;
 +    }
 +
 +    if (FoundWnd != NULL)
 +        Ret = UserHMGetHandle(FoundWnd);
 +    return Ret;
 +}
 +
 +/***********************************************************************
 + *           IntSendDestroyMsg
 + */
 +static void IntSendDestroyMsg(HWND hWnd)
 +{
 +
 +   PWND Window;
 +#if 0 /* FIXME */
 +
 +   GUITHREADINFO info;
 +
 +   if (GetGUIThreadInfo(GetCurrentThreadId(), &info))
 +   {
 +      if (hWnd == info.hwndCaret)
 +      {
 +         DestroyCaret();
 +      }
 +   }
 +#endif
 +
 +   Window = UserGetWindowObject(hWnd);
 +   if (Window)
 +   {
 +//      USER_REFERENCE_ENTRY Ref;
 +//      UserRefObjectCo(Window, &Ref);
 +
 +      if (!Window->spwndOwner && !IntGetParent(Window))
 +      {
 +         co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM) hWnd, 0);
 +      }
 +
 +//      UserDerefObjectCo(Window);
 +   }
 +
 +   /* The window could already be destroyed here */
 +
 +   /*
 +    * Send the WM_DESTROY to the window.
 +    */
 +
 +   co_IntSendMessage(hWnd, WM_DESTROY, 0, 0);
 +
 +   /*
 +    * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
 +    * make sure that the window still exists when we come back.
 +    */
 +#if 0 /* FIXME */
 +
 +   if (IsWindow(Wnd))
 +   {
 +      HWND* pWndArray;
 +      int i;
 +
 +      if (!(pWndArray = WIN_ListChildren( hwnd )))
 +         return;
 +
 +      /* start from the end (FIXME: is this needed?) */
 +      for (i = 0; pWndArray[i]; i++)
 +         ;
 +
 +      while (--i >= 0)
 +      {
 +         if (IsWindow( pWndArray[i] ))
 +            WIN_SendDestroyMsg( pWndArray[i] );
 +      }
 +      HeapFree(GetProcessHeap(), 0, pWndArray);
 +   }
 +   else
 +   {
 +      TRACE("destroyed itself while in WM_DESTROY!\n");
 +   }
 +#endif
 +}
 +
 +static VOID
 +UserFreeWindowInfo(PTHREADINFO ti, PWND Wnd)
 +{
 +    PCLIENTINFO ClientInfo = GetWin32ClientInfo();
 +
 +    if (!Wnd) return;
 +
 +    if (ClientInfo->CallbackWnd.pWnd == DesktopHeapAddressToUser(Wnd))
 +    {
 +        ClientInfo->CallbackWnd.hWnd = NULL;
 +        ClientInfo->CallbackWnd.pWnd = NULL;
 +    }
 +
 +   if (Wnd->strName.Buffer != NULL)
 +   {
 +       Wnd->strName.Length = 0;
 +       Wnd->strName.MaximumLength = 0;
 +       DesktopHeapFree(Wnd->head.rpdesk,
 +                       Wnd->strName.Buffer);
 +       Wnd->strName.Buffer = NULL;
 +   }
 +
 +//    DesktopHeapFree(Wnd->head.rpdesk, Wnd);
 +//    WindowObject->hWnd = NULL;
 +}
 +
 +/***********************************************************************
 + *           IntDestroyWindow
 + *
 + * Destroy storage associated to a window. "Internals" p.358
 + *
 + * This is the "functional" DestroyWindows function ei. all stuff
 + * done in CreateWindow is undone here and not in DestroyWindow:-P
 +
 + */
 +static LRESULT co_UserFreeWindow(PWND Window,
 +                                   PPROCESSINFO ProcessData,
 +                                   PTHREADINFO ThreadData,
 +                                   BOOLEAN SendMessages)
 +{
 +   HWND *Children;
 +   HWND *ChildHandle;
 +   PWND Child;
 +   PMENU Menu;
 +   BOOLEAN BelongsToThreadData;
 +
 +   ASSERT(Window);
 +
 +   if(Window->state2 & WNDS2_INDESTROY)
 +   {
 +      TRACE("Tried to call IntDestroyWindow() twice\n");
 +      return 0;
 +   }
 +   Window->state2 |= WNDS2_INDESTROY;
 +   Window->style &= ~WS_VISIBLE;
 +   Window->head.pti->cVisWindows--;
 +
 +   IntNotifyWinEvent(EVENT_OBJECT_DESTROY, Window, OBJID_WINDOW, CHILDID_SELF, 0);
 +
 +   /* remove the window already at this point from the thread window list so we
 +      don't get into trouble when destroying the thread windows while we're still
 +      in IntDestroyWindow() */
 +   RemoveEntryList(&Window->ThreadListEntry);
 +
 +   BelongsToThreadData = IntWndBelongsToThread(Window, ThreadData);
 +
 +   IntDeRegisterShellHookWindow(Window->head.h);
 +
 +   if(SendMessages)
 +   {
 +      /* Send destroy messages */
 +      IntSendDestroyMsg(Window->head.h);
 +   }
 +
 +   /* free child windows */
 +   Children = IntWinListChildren(Window);
 +   if (Children)
 +   {
 +      for (ChildHandle = Children; *ChildHandle; ++ChildHandle)
 +      {
 +         if ((Child = IntGetWindowObject(*ChildHandle)))
 +         {
 +            if(!IntWndBelongsToThread(Child, ThreadData))
 +            {
 +               /* send WM_DESTROY messages to windows not belonging to the same thread */
 +               IntSendDestroyMsg(Child->head.h);
 +            }
 +            else
 +               co_UserFreeWindow(Child, ProcessData, ThreadData, SendMessages);
 +
 +            UserDereferenceObject(Child);
 +         }
 +      }
 +      ExFreePoolWithTag(Children, USERTAG_WINDOWLIST);
 +   }
 +
 +   if(SendMessages)
 +   {
 +      /*
 +       * Clear the update region to make sure no WM_PAINT messages will be
 +       * generated for this window while processing the WM_NCDESTROY.
 +       */
 +      co_UserRedrawWindow(Window, NULL, 0,
 +                          RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
 +                          RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
 +      if(BelongsToThreadData)
 +         co_IntSendMessage(Window->head.h, WM_NCDESTROY, 0, 0);
 +   }
 +
 +   DestroyTimersForWindow(ThreadData, Window);
 +
 +   /* Unregister hot keys */
 +   UnregisterWindowHotKeys (Window);
 +
 +   /* flush the message queue */
 +   MsqRemoveWindowMessagesFromQueue(Window);
 +
 +   /* from now on no messages can be sent to this window anymore */
 +   Window->state |= WNDS_DESTROYED;
 +   Window->fnid |= FNID_FREED;
 +
 +   /* don't remove the WINDOWSTATUS_DESTROYING bit */
 +
 +   /* reset shell window handles */
 +   if(ThreadData->rpdesk)
 +   {
 +      if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellWindow)
 +         ThreadData->rpdesk->rpwinstaParent->ShellWindow = NULL;
 +
 +      if (Window->head.h == ThreadData->rpdesk->rpwinstaParent->ShellListView)
 +         ThreadData->rpdesk->rpwinstaParent->ShellListView = NULL;
 +   }
 +
 +   /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
 +
 +#if 0 /* FIXME */
 +
 +   WinPosCheckInternalPos(Window->head.h);
 +   if (Window->head.h == GetCapture())
 +   {
 +      ReleaseCapture();
 +   }
 +
 +   /* free resources associated with the window */
 +   TIMER_RemoveWindowTimers(Window->head.h);
 +#endif
 +
 +   if ( ((Window->style & (WS_CHILD|WS_POPUP)) != WS_CHILD) &&
 +        Window->IDMenu &&
 +        (Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
 +   {
 +      IntDestroyMenuObject(Menu, TRUE, TRUE);
 +      Window->IDMenu = 0;
 +   }
 +
 +   if(Window->SystemMenu
 +         && (Menu = UserGetMenuObject(Window->SystemMenu)))
 +   {
 +      IntDestroyMenuObject(Menu, TRUE, TRUE);
 +      Window->SystemMenu = (HMENU)0;
 +   }
 +
 +   DceFreeWindowDCE(Window);    /* Always do this to catch orphaned DCs */
 +#if 0 /* FIXME */
 +
 +   WINPROC_FreeProc(Window->winproc, WIN_PROC_WINDOW);
 +   CLASS_RemoveWindow(Window->Class);
 +#endif
 +
 +   IntUnlinkWindow(Window);
 +
 +   if (Window->PropListItems)
 +   {
 +      IntRemoveWindowProp(Window);
 +      TRACE("Window->PropListItems %d\n",Window->PropListItems);
 +      ASSERT(Window->PropListItems==0);
 +   }
 +
 +   UserReferenceObject(Window);
 +   UserDeleteObject(Window->head.h, TYPE_WINDOW);
 +
 +   IntDestroyScrollBars(Window);
 +
 +   /* dereference the class */
 +   IntDereferenceClass(Window->pcls,
 +                       Window->head.pti->pDeskInfo,
 +                       Window->head.pti->ppi);
 +   Window->pcls = NULL;
 +
 +   if(Window->hrgnClip)
 +   {
 +      IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
 +      GreDeleteObject(Window->hrgnClip);
 +      Window->hrgnClip = NULL;
 +   }
 +   Window->head.pti->cWindows--;
 +
 +//   ASSERT(Window != NULL);
 +   UserFreeWindowInfo(Window->head.pti, Window);
 +
 +   UserDereferenceObject(Window);
 +
 +   UserClipboardFreeWindow(Window);
 +
 +   return 0;
 +}
 +
 +//
 +// Same as User32:IntGetWndProc.
 +//
 +WNDPROC FASTCALL
 +IntGetWindowProc(PWND pWnd,
 +                 BOOL Ansi)
 +{
 +   INT i;
 +   PCLS Class;
 +   WNDPROC gcpd, Ret = 0;
 +
 +   ASSERT(UserIsEnteredExclusive() == TRUE);
 +
 +   Class = pWnd->pcls;
 +
 +   if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
 +   {
 +      for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
 +      {
 +         if (GETPFNSERVER(i) == pWnd->lpfnWndProc)
 +         {
 +            if (Ansi)
 +               Ret = GETPFNCLIENTA(i);
 +            else
 +               Ret = GETPFNCLIENTW(i);
 +         }
 +      }
 +      return Ret;
 +   }
 +
 +   if (Class->fnid == FNID_EDIT)
 +      Ret = pWnd->lpfnWndProc;
 +   else
 +   {
 +      Ret = pWnd->lpfnWndProc;
 +
 +      if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
 +      {
 +         if (Ansi)
 +         {
 +            if (GETPFNCLIENTW(Class->fnid) == pWnd->lpfnWndProc)
 +               Ret = GETPFNCLIENTA(Class->fnid);
 +         }
 +         else
 +         {
 +            if (GETPFNCLIENTA(Class->fnid) == pWnd->lpfnWndProc)
 +               Ret = GETPFNCLIENTW(Class->fnid);
 +         }
 +      }
 +      if ( Ret != pWnd->lpfnWndProc)
 +         return Ret;
 +   }
 +   if ( Ansi == !!(pWnd->state & WNDS_ANSIWINDOWPROC) )
 +      return Ret;
 +
 +   gcpd = (WNDPROC)UserGetCPD(
 +                       pWnd,
 +                      (Ansi ? UserGetCPDA2U : UserGetCPDU2A )|UserGetCPDWindow,
 +                      (ULONG_PTR)Ret);
 +
 +   return (gcpd ? gcpd : Ret);
 +}
 +
 +static WNDPROC
 +IntSetWindowProc(PWND pWnd,
 +                 WNDPROC NewWndProc,
 +                 BOOL Ansi)
 +{
 +   INT i;
 +   PCALLPROCDATA CallProc;
 +   PCLS Class;
 +   WNDPROC Ret, chWndProc = NULL;
 +
 +   // Retrieve previous window proc.
 +   Ret = IntGetWindowProc(pWnd, Ansi);
 +
 +   Class = pWnd->pcls;
 +
 +   if (IsCallProcHandle(NewWndProc))
 +   {
 +      CallProc = UserGetObject(gHandleTable, NewWndProc, TYPE_CALLPROC);
 +      if (CallProc)
 +      {  // Reset new WndProc.
 +         NewWndProc = CallProc->pfnClientPrevious;
 +         // Reset Ansi from CallProc handle. This is expected with wine "deftest".
 +         Ansi = !!(CallProc->wType & UserGetCPDU2A);
 +      }
 +   }
 +   // Switch from Client Side call to Server Side call if match. Ref: "deftest".
 +   for ( i = FNID_FIRST; i <= FNID_SWITCH; i++)
 +   {
 +       if (GETPFNCLIENTW(i) == NewWndProc)
 +       {
 +          chWndProc = GETPFNSERVER(i);
 +          break;
 +       }
 +       if (GETPFNCLIENTA(i) == NewWndProc)
 +       {
 +          chWndProc = GETPFNSERVER(i);
 +          break;
 +       }
 +   }
 +   // If match, set/reset to Server Side and clear ansi.
 +   if (chWndProc)
 +   {
 +      pWnd->lpfnWndProc = chWndProc;
 +      pWnd->Unicode = TRUE;
 +      pWnd->state &= ~WNDS_ANSIWINDOWPROC;
 +      pWnd->state |= WNDS_SERVERSIDEWINDOWPROC;
 +   }
 +   else
 +   {
 +      pWnd->Unicode = !Ansi;
 +      // Handle the state change in here.
 +      if (Ansi)
 +         pWnd->state |= WNDS_ANSIWINDOWPROC;
 +      else
 +         pWnd->state &= ~WNDS_ANSIWINDOWPROC;
 +
 +      if (pWnd->state & WNDS_SERVERSIDEWINDOWPROC)
 +         pWnd->state &= ~WNDS_SERVERSIDEWINDOWPROC;
 +
 +      if (!NewWndProc) NewWndProc = pWnd->lpfnWndProc;
 +
 +      if (Class->fnid <= FNID_GHOST && Class->fnid >= FNID_BUTTON)
 +      {
 +         if (Ansi)
 +         {
 +            if (GETPFNCLIENTW(Class->fnid) == NewWndProc)
 +               chWndProc = GETPFNCLIENTA(Class->fnid);
 +         }
 +         else
 +         {
 +            if (GETPFNCLIENTA(Class->fnid) == NewWndProc)
 +               chWndProc = GETPFNCLIENTW(Class->fnid);
 +         }
 +      }
 +      // Now set the new window proc.
 +      pWnd->lpfnWndProc = (chWndProc ? chWndProc : NewWndProc);
 +   }
 +   return Ret;
 +}
 +
 +static BOOL FASTCALL
 +IntSetMenu(
 +   PWND Wnd,
 +   HMENU Menu,
 +   BOOL *Changed)
 +{
 +   PMENU OldMenu, NewMenu = NULL;
 +
 +   if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
 +   {
 +      ERR("SetMenu: Invalid handle 0x%p!\n",UserHMGetHandle(Wnd));
 +      EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
 +      return FALSE;
 +   }
 +
 +   *Changed = (Wnd->IDMenu != (UINT) Menu);
 +   if (! *Changed)
 +   {
 +      return TRUE;
 +   }
 +
 +   if (Wnd->IDMenu)
 +   {
 +      OldMenu = IntGetMenuObject((HMENU) Wnd->IDMenu);
 +      ASSERT(NULL == OldMenu || OldMenu->hWnd == Wnd->head.h);
 +   }
 +   else
 +   {
 +      OldMenu = NULL;
 +   }
 +
 +   if (NULL != Menu)
 +   {
 +      NewMenu = IntGetMenuObject(Menu);
 +      if (NULL == NewMenu)
 +      {
 +         if (NULL != OldMenu)
 +         {
 +            IntReleaseMenuObject(OldMenu);
 +         }
 +         EngSetLastError(ERROR_INVALID_MENU_HANDLE);
 +         return FALSE;
 +      }
 +      if (NULL != NewMenu->hWnd)
 +      {
 +         /* Can't use the same menu for two windows */
 +         if (NULL != OldMenu)
 +         {
 +            IntReleaseMenuObject(OldMenu);
 +         }
 +         EngSetLastError(ERROR_INVALID_MENU_HANDLE);
 +         return FALSE;
 +      }
 +
 +   }
 +
 +   Wnd->IDMenu = (UINT) Menu;
 +   if (NULL != NewMenu)
 +   {
 +      NewMenu->hWnd = Wnd->head.h;
 +      IntReleaseMenuObject(NewMenu);
 +   }
 +   if (NULL != OldMenu)
 +   {
 +      OldMenu->hWnd = NULL;
 +      IntReleaseMenuObject(OldMenu);
 +   }
 +
 +   return TRUE;
 +}
 +
 +
 +/* INTERNAL ******************************************************************/
 +
 +
 +VOID FASTCALL
 +co_DestroyThreadWindows(struct _ETHREAD *Thread)
 +{
 +   PTHREADINFO WThread;
 +   PLIST_ENTRY Current;
 +   PWND Wnd;
 +   USER_REFERENCE_ENTRY Ref;
 +   WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
 +
 +   while (!IsListEmpty(&WThread->WindowListHead))
 +   {
 +      Current = WThread->WindowListHead.Flink;
 +      Wnd = CONTAINING_RECORD(Current, WND, ThreadListEntry);
 +
 +      TRACE("thread cleanup: while destroy wnds, wnd=%p\n", Wnd);
 +
 +      /* Window removes itself from the list */
 +
 +      /*
 +       * FIXME: It is critical that the window removes itself! If now, we will loop
 +       * here forever...
 +       */
 +
 +      //ASSERT(co_UserDestroyWindow(Wnd));
 +
 +      UserRefObjectCo(Wnd, &Ref); // FIXME: Temp HACK??
 +      if (!co_UserDestroyWindow(Wnd))
 +      {
 +         ERR("Unable to destroy window %p at thread cleanup... This is _VERY_ bad!\n", Wnd);
 +      }
 +      UserDerefObjectCo(Wnd); // FIXME: Temp HACK??
 +   }
 +}
 +
 +PMENU FASTCALL
 +IntGetSystemMenu(PWND Window, BOOL bRevert, BOOL RetMenu)
 +{
 +   PMENU Menu, NewMenu = NULL, SysMenu = NULL, ret = NULL;
 +   PTHREADINFO W32Thread;
 +   HMENU hNewMenu, hSysMenu;
++   ROSMENUITEMINFO ItemInfoSet = {0};
 +   ROSMENUITEMINFO ItemInfo = {0};
++   UNICODE_STRING MenuName;
 +
 +   if(bRevert)
 +   {
 +      W32Thread = PsGetCurrentThreadWin32Thread();
 +
 +      if(!W32Thread->rpdesk)
 +         return NULL;
 +
 +      if(Window->SystemMenu)
 +      {
 +         Menu = UserGetMenuObject(Window->SystemMenu);
 +         if(Menu)
 +         {
 +            IntDestroyMenuObject(Menu, TRUE, TRUE);
 +            Window->SystemMenu = (HMENU)0;
 +         }
 +      }
 +
 +      if(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate)
 +      {
 +         /* Clone system menu */
 +         Menu = UserGetMenuObject(W32Thread->rpdesk->rpwinstaParent->SystemMenuTemplate);
 +         if(!Menu)
 +            return NULL;
 +
 +         NewMenu = IntCloneMenu(Menu);
 +         if(NewMenu)
 +         {  // Use spmenuSys
 +            Window->SystemMenu = NewMenu->head.h;
 +            NewMenu->fFlags |= MNF_SYSDESKMN;
 +            NewMenu->hWnd = Window->head.h;
 +            ret = NewMenu;
 +            //IntReleaseMenuObject(NewMenu);
 +         }
 +      }
 +      else
 +      {
 +         hSysMenu = UserCreateMenu(FALSE);
 +         if (NULL == hSysMenu)
 +         {
 +            return NULL;
 +         }
 +         SysMenu = IntGetMenuObject(hSysMenu);
 +         if (NULL == SysMenu)
 +         {
 +            UserDestroyMenu(hSysMenu);
 +            return NULL;
 +         }
 +         SysMenu->fFlags |= MNF_SYSDESKMN;
 +         SysMenu->hWnd = Window->head.h;
-          //hNewMenu = co_IntCallLoadMenu( NULL, L"SYSMENUMDI");
-          // else
-          //hNewMenu = co_IntCallLoadMenu( NULL, L"SYSMENU");
-          // Do the rest in here.
++         //hNewMenu = co_IntLoadSysMenuTemplate();
 +         //if ( Window->ExStyle & WS_EX_MDICHILD )
++         //{
++         //   RtlInitUnicodeString( &MenuName, L"SYSMENUMDI");
++         //   hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
++         //}
++         //else
++         {
++            RtlInitUnicodeString( &MenuName, L"SYSMENU");
++            hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
++            //ERR("%wZ\n",&MenuName);
++         }
 +         if(!hNewMenu)
 +         {
++            ERR("No Menu!!\n");
 +            IntReleaseMenuObject(SysMenu);
 +            UserDestroyMenu(hSysMenu);
 +            return NULL;
 +         }
 +         Menu = IntGetMenuObject(hNewMenu);
 +         if(!Menu)
 +         {
 +            IntReleaseMenuObject(SysMenu);
 +            UserDestroyMenu(hSysMenu);
 +            return NULL;
 +         }
 +
++         // Do the rest in here.
++
++         Menu->fFlags |= MNS_CHECKORBMP | MNF_SYSDESKMN | MNF_POPUP;
++
++         ItemInfoSet.cbSize = sizeof( MENUITEMINFOW);
++         ItemInfoSet.fMask = MIIM_BITMAP;
++         ItemInfoSet.hbmpItem = HBMMENU_POPUP_CLOSE;
++         IntMenuItemInfo(Menu, SC_CLOSE, FALSE, &ItemInfoSet, TRUE, NULL);
++         ItemInfoSet.hbmpItem = HBMMENU_POPUP_RESTORE;
++         IntMenuItemInfo(Menu, SC_RESTORE, FALSE, &ItemInfoSet, TRUE, NULL);
++         ItemInfoSet.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
++         IntMenuItemInfo(Menu, SC_MAXIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
++         ItemInfoSet.hbmpItem = HBMMENU_POPUP_MINIMIZE;
++         IntMenuItemInfo(Menu, SC_MINIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
++
 +         NewMenu = IntCloneMenu(Menu);
 +         if(NewMenu)
 +         {
 +            NewMenu->fFlags |= MNF_SYSDESKMN | MNF_POPUP;
 +            // Do not set MNS_CHECKORBMP it breaks menus, also original code destroyed the style anyway.
 +            IntReleaseMenuObject(NewMenu);
 +            UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
 +
 +            if (Window->pcls->style & CS_NOCLOSE)
 +               IntRemoveMenuItem(NewMenu, SC_CLOSE, MF_BYCOMMAND, TRUE);
 +
 +            ItemInfo.cbSize = sizeof(MENUITEMINFOW);
 +            ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
 +            ItemInfo.fType = 0;
 +            ItemInfo.fState = MFS_ENABLED;
 +            ItemInfo.dwTypeData = NULL;
 +            ItemInfo.cch = 0;
 +            ItemInfo.hSubMenu = NewMenu->head.h;
 +            IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo, NULL);
 +
 +            Window->SystemMenu = SysMenu->head.h;
 +
 +            ret = SysMenu;
 +         }
 +         IntDestroyMenuObject(Menu, FALSE, TRUE);
 +      }
 +      if(RetMenu)
 +         return ret;
 +      else
 +         return NULL;
 +   }
 +   else
 +   {
 +      if(Window->SystemMenu)
 +         return IntGetMenuObject((HMENU)Window->SystemMenu);
 +      else
 +         return NULL;
 +   }
 +}
 +
 +
 +BOOL FASTCALL
 +IntIsChildWindow(PWND Parent, PWND BaseWindow)
 +{
 +   PWND Window;
 +
 +   Window = BaseWindow;
 +   while (Window && ((Window->style & (WS_POPUP|WS_CHILD)) == WS_CHILD))
 +   {
 +      if (Window == Parent)
 +      {
 +         return(TRUE);
 +      }
 +
 +      Window = Window->spwndParent;
 +   }
 +
 +   return(FALSE);
 +}
 +
 +/*
 +   Link the window into siblings list
 +   children and parent are kept in place.
 +*/
 +VOID FASTCALL
 +IntLinkWindow(
 +   PWND Wnd,
 +   PWND WndInsertAfter /* set to NULL if top sibling */
 +)
 +{
 +  if ((Wnd->spwndPrev = WndInsertAfter))
 +   {
 +      /* link after WndInsertAfter */
 +      if ((Wnd->spwndNext = WndInsertAfter->spwndNext))
 +         Wnd->spwndNext->spwndPrev = Wnd;
 +
 +      Wnd->spwndPrev->spwndNext = Wnd;
 +   }
 +   else
 +   {
 +      /* link at top */
 +     if ((Wnd->spwndNext = Wnd->spwndParent->spwndChild))
 +         Wnd->spwndNext->spwndPrev = Wnd;
 +
 +     Wnd->spwndParent->spwndChild = Wnd;
 +   }
 +}
 +
 +/*
 + Note: Wnd->spwndParent can be null if it is the desktop.
 +*/
 +VOID FASTCALL IntLinkHwnd(PWND Wnd, HWND hWndPrev)
 +{
 +    if (hWndPrev == HWND_NOTOPMOST)
 +    {
 +        if (!(Wnd->ExStyle & WS_EX_TOPMOST) &&
 +            (Wnd->ExStyle2 & WS_EX2_LINKED)) return;  /* nothing to do */
 +        Wnd->ExStyle &= ~WS_EX_TOPMOST;
 +        hWndPrev = HWND_TOP;  /* fallback to the HWND_TOP case */
 +    }
 +
 +    IntUnlinkWindow(Wnd);  /* unlink it from the previous location */
 +
 +    if (hWndPrev == HWND_BOTTOM)
 +    {
 +        /* Link in the bottom of the list */
 +        PWND WndInsertAfter;
 +
 +        WndInsertAfter = Wnd->spwndParent->spwndChild;
 +        while( WndInsertAfter && WndInsertAfter->spwndNext)
 +            WndInsertAfter = WndInsertAfter->spwndNext;
 +
 +        IntLinkWindow(Wnd, WndInsertAfter);
 +        Wnd->ExStyle &= ~WS_EX_TOPMOST;
 +    }
 +    else if (hWndPrev == HWND_TOPMOST)
 +    {
 +        /* Link in the top of the list */
 +        IntLinkWindow(Wnd, NULL);
 +
 +        Wnd->ExStyle |= WS_EX_TOPMOST;
 +    }
 +    else if (hWndPrev == HWND_TOP)
 +    {
 +        /* Link it after the last topmost window */
 +        PWND WndInsertBefore;
 +
 +        WndInsertBefore = Wnd->spwndParent->spwndChild;
 +
 +        if (!(Wnd->ExStyle & WS_EX_TOPMOST))  /* put it above the first non-topmost window */
 +        {
 +            while (WndInsertBefore != NULL && WndInsertBefore->spwndNext != NULL)
 +            {
 +                if (!(WndInsertBefore->ExStyle & WS_EX_TOPMOST)) break;
 +                if (WndInsertBefore == Wnd->spwndOwner)  /* keep it above owner */
 +                {
 +                    Wnd->ExStyle |= WS_EX_TOPMOST;
 +                    break;
 +                }
 +                WndInsertBefore = WndInsertBefore->spwndNext;
 +            }
 +        }
 +
 +        IntLinkWindow(Wnd, WndInsertBefore ? WndInsertBefore->spwndPrev : NULL);
 +    }
 +    else
 +    {
 +        /* Link it after hWndPrev */
 +        PWND WndInsertAfter;
 +
 +        WndInsertAfter = UserGetWindowObject(hWndPrev);
 +        /* Are we called with an erroneous handle */
 +        if(WndInsertAfter == NULL)
 +        {
 +            /* Link in a default position */
 +            IntLinkHwnd(Wnd, HWND_TOP);
 +            return;
 +        }
 +
 +        IntLinkWindow(Wnd, WndInsertAfter);
 +
 +        /* Fix the WS_EX_TOPMOST flag */
 +        if (!(WndInsertAfter->ExStyle & WS_EX_TOPMOST))
 +        {
 +            Wnd->ExStyle &= ~WS_EX_TOPMOST;
 +        }
 +        else
 +        {
 +            if(WndInsertAfter->spwndNext &&
 +               WndInsertAfter->spwndNext->ExStyle & WS_EX_TOPMOST)
 +            {
 +                Wnd->ExStyle |= WS_EX_TOPMOST;
 +            }
 +        }
 +    }
 +    Wnd->ExStyle2 |= WS_EX2_LINKED;
 +}
 +
 +VOID FASTCALL
 +IntProcessOwnerSwap(PWND Wnd, PWND WndNewOwner, PWND WndOldOwner)
 +{
 +   if (WndOldOwner)
 +   {
 +      if (Wnd->head.pti != WndOldOwner->head.pti)
 +      {
 +         if (!WndNewOwner ||
 +              Wnd->head.pti == WndNewOwner->head.pti ||
 +              WndOldOwner->head.pti != WndNewOwner->head.pti )
 +         {
 +            //ERR("ProcessOwnerSwap Old out.\n");
 +            UserAttachThreadInput(Wnd->head.pti, WndOldOwner->head.pti, FALSE);
 +         }
 +      }
 +   }
 +   if (WndNewOwner)
 +   {
 +      if (Wnd->head.pti != WndNewOwner->head.pti)
 +      {
 +         if (!WndOldOwner ||
 +              WndOldOwner->head.pti != WndNewOwner->head.pti )
 +         {
 +            //ERR("ProcessOwnerSwap New in.\n");
 +            UserAttachThreadInput(Wnd->head.pti, WndNewOwner->head.pti, TRUE);
 +         }
 +      }
 +   }
 +   // FIXME: System Tray checks.
 +}
 +
 +HWND FASTCALL
 +IntSetOwner(HWND hWnd, HWND hWndNewOwner)
 +{
 +   PWND Wnd, WndOldOwner, WndNewOwner;
 +   HWND ret;
 +
 +   Wnd = IntGetWindowObject(hWnd);
 +   if(!Wnd)
 +      return NULL;
 +
 +   WndOldOwner = Wnd->spwndOwner;
 +
 +   ret = WndOldOwner ? UserHMGetHandle(WndOldOwner) : 0;
 +   WndNewOwner = UserGetWindowObject(hWndNewOwner);
 +
 +   if (!WndNewOwner && hWndNewOwner)
 +   {
 +      EngSetLastError(ERROR_INVALID_PARAMETER);
 +      ret = NULL;
 +      goto Error;
 +   }
 +
 +   /* if parent belongs to a different thread and the window isn't */
 +   /* top-level, attach the two threads */
 +   IntProcessOwnerSwap(Wnd, WndNewOwner, WndOldOwner);
 +
 +   if (IntValidateOwnerDepth(Wnd, WndNewOwner))
 +   {
 +      if (WndNewOwner)
 +      {
 +         Wnd->spwndOwner= WndNewOwner;
 +      }
 +      else
 +      {
 +         Wnd->spwndOwner = NULL;
 +      }
 +   }
 +   else
 +   {
 +      IntProcessOwnerSwap(Wnd, WndOldOwner, WndNewOwner);
 +      EngSetLastError(ERROR_INVALID_PARAMETER);
 +      ret = NULL;
 +   }
 +Error:
 +   UserDereferenceObject(Wnd);
 +   return ret;
 +}
 +
 +PWND FASTCALL
 +co_IntSetParent(PWND Wnd, PWND WndNewParent)
 +{
 +   PWND WndOldParent, pWndExam;
 +   BOOL WasVisible;
 +   POINT pt;
 +   int swFlags = SWP_NOSIZE|SWP_NOZORDER;
 +
 +   ASSERT(Wnd);
 +   ASSERT(WndNewParent);
 +   ASSERT_REFS_CO(Wnd);
 +   ASSERT_REFS_CO(WndNewParent);
 +
 +   if (Wnd == Wnd->head.rpdesk->spwndMessage)
 +   {
 +      EngSetLastError(ERROR_ACCESS_DENIED);
 +      return( NULL);
 +   }
 +
 +   /* Some applications try to set a child as a parent */
 +   if (IntIsChildWindow(Wnd, WndNewParent))
 +   {
 +      TRACE("IntSetParent try to set a child as a parent.\n");
 +      EngSetLastError( ERROR_INVALID_PARAMETER );
 +      return NULL;
 +   }
 +
 +   pWndExam = WndNewParent; // Load parent Window to examine.
 +   // Now test for set parent to parent hit.
 +   while (pWndExam)
 +   {
 +      if (Wnd == pWndExam)
 +      {
 +         TRACE("IntSetParent Failed Test for set parent to parent!\n");
 +         EngSetLastError(ERROR_INVALID_PARAMETER);
 +         return NULL;
 +      }
 +      pWndExam = pWndExam->spwndParent;
 +   }
 +
 +   /*
 +    * Windows hides the window first, then shows it again
 +    * including the WM_SHOWWINDOW messages and all
 +    */
 +   WasVisible = co_WinPosShowWindow(Wnd, SW_HIDE);
 +
 +   /* Window must belong to current process */
 +   if (Wnd->head.pti->ppi != PsGetCurrentProcessWin32Process())
 +   {
 +      ERR("IntSetParent Window must belong to current process!\n");
 +      return NULL;
 +   }
 +
 +   WndOldParent = Wnd->spwndParent;
 +
 +   if ( WndOldParent &&
 +        WndOldParent->ExStyle & WS_EX_LAYOUTRTL)
 +      pt.x = Wnd->rcWindow.right;
 +   else
 +      pt.x = Wnd->rcWindow.left;
 +   pt.y = Wnd->rcWindow.top;
 +
 +   IntScreenToClient(WndOldParent, &pt);
 +
 +   if (WndOldParent) UserReferenceObject(WndOldParent); /* Caller must deref */
 +
 +   if (WndNewParent != WndOldParent)
 +   {
 +      /* Unlink the window from the siblings list */
 +      IntUnlinkWindow(Wnd);
 +      Wnd->ExStyle2 &= ~WS_EX2_LINKED;
 +
 +      /* Set the new parent */
 +      Wnd->spwndParent = WndNewParent;
 +
 +      if ( Wnd->style & WS_CHILD &&
 +           Wnd->spwndOwner &&
 +           Wnd->spwndOwner->ExStyle & WS_EX_TOPMOST )
 +      {
 +         ERR("SetParent Top Most from Pop up!\n");
 +         Wnd->ExStyle |= WS_EX_TOPMOST;
 +      }
 +
 +      /* Link the window with its new siblings */
 +      IntLinkHwnd( Wnd,
 +                  ((0 == (Wnd->ExStyle & WS_EX_TOPMOST) &&
 +                    WndNewParent == UserGetDesktopWindow() ) ? HWND_TOP : HWND_TOPMOST ) );
 +
 +   }
 +
 +   if ( WndNewParent == co_GetDesktopWindow(Wnd) &&
 +       !(Wnd->style & WS_CLIPSIBLINGS) )
 +   {
 +      Wnd->style |= WS_CLIPSIBLINGS;
 +      DceResetActiveDCEs(Wnd);
 +   }
 +
 +   /* if parent belongs to a different thread and the window isn't */
 +   /* top-level, attach the two threads */
 +   if ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
 +   {
 +      if ( Wnd->spwndParent != co_GetDesktopWindow(Wnd))
 +      {
 +         if (Wnd->head.pti != WndOldParent->head.pti)
 +         {
 +            //ERR("SetParent Old out.\n");
 +            UserAttachThreadInput(Wnd->head.pti, WndOldParent->head.pti, FALSE);
 +         }
 +      }
 +      if ( WndNewParent != co_GetDesktopWindow(Wnd))
 +      {
 +         if (Wnd->head.pti != WndNewParent->head.pti)
 +         {
 +            //ERR("SetParent New in.\n");
 +            UserAttachThreadInput(Wnd->head.pti, WndNewParent->head.pti, TRUE);
 +         }
 +      }
 +   }
 +
 +   if (WndOldParent == UserGetMessageWindow() || WndNewParent == UserGetMessageWindow())
 +      swFlags |= SWP_NOACTIVATE;
 +
 +   IntNotifyWinEvent(EVENT_OBJECT_PARENTCHANGE, Wnd ,OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
 +   /*
 +    * SetParent additionally needs to make hwnd the top window
 +    * in the z-order and send the expected WM_WINDOWPOSCHANGING and
 +    * WM_WINDOWPOSCHANGED notification messages.
 +    */
 +   //ERR("IntSetParent SetWindowPos 1\n");
 +   co_WinPosSetWindowPos( Wnd,
 +                         (0 == (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOP : HWND_TOPMOST),
 +                          pt.x, pt.y, 0, 0, swFlags);
 +   //ERR("IntSetParent SetWindowPos 2 X %d Y %d\n",pt.x, pt.y);
 +   if (WasVisible) co_WinPosShowWindow(Wnd, SW_SHOWNORMAL);
 +
 +   return WndOldParent;
 +}
 +
 +HWND FASTCALL
 +co_UserSetParent(HWND hWndChild, HWND hWndNewParent)
 +{
 +   PWND Wnd = NULL, WndParent = NULL, WndOldParent;
 +   HWND hWndOldParent = NULL;
 +   USER_REFERENCE_ENTRY Ref, ParentRef;
 +
 +   if (IntIsBroadcastHwnd(hWndChild) || IntIsBroadcastHwnd(hWndNewParent))
 +   {
 +      EngSetLastError(ERROR_INVALID_PARAMETER);
 +      return( NULL);
 +   }
 +
 +   if (hWndChild == IntGetDesktopWindow())
 +   {
 +      ERR("UserSetParent Access Denied!\n");
 +      EngSetLastError(ERROR_ACCESS_DENIED);
 +      return( NULL);
 +   }
 +
 +   if (hWndNewParent)
 +   {
 +      if (!(WndParent = UserGetWindowObject(hWndNewParent)))
 +      {
 +         ERR("UserSetParent Bad New Parent!\n");
 +         return( NULL);
 +      }
 +   }
 +   else
 +   {
 +      if (!(WndParent = UserGetWindowObject(IntGetDesktopWindow())))
 +      {
 +         return( NULL);
 +      }
 +   }
 +
 +   if (!(Wnd = UserGetWindowObject(hWndChild)))
 +   {
 +      ERR("UserSetParent Bad Child!\n");
 +      return( NULL);
 +   }
 +
 +   UserRefObjectCo(Wnd, &Ref);
 +   UserRefObjectCo(WndParent, &ParentRef);
 +   //ERR("Enter co_IntSetParent\n");
 +   WndOldParent = co_IntSetParent(Wnd, WndParent);
 +   //ERR("Leave co_IntSetParent\n");
 +   UserDerefObjectCo(WndParent);
 +   UserDerefObjectCo(Wnd);
 +
 +   if (WndOldParent)
 +   {
 +      hWndOldParent = WndOldParent->head.h;
 +      UserDereferenceObject(WndOldParent);
 +   }
 +
 +   return( hWndOldParent);
 +}
 +
 +BOOL FASTCALL
 +IntSetSystemMenu(PWND Window, PMENU Menu)
 +{
 +   PMENU OldMenu;
 +   if(Window->SystemMenu)
 +   {
 +      OldMenu = IntGetMenuObject(Window->SystemMenu);
 +      if(OldMenu)
 +      {
 +         OldMenu->fFlags &= ~ MNF_SYSDESKMN;
 +         IntReleaseMenuObject(OldMenu);
 +      }
 +   }
 +
 +   if(Menu)
 +   {
 +      /* FIXME: Check window style, propably return FALSE? */
 +      Window->SystemMenu = Menu->head.h;
 +      Menu->fFlags |= MNF_SYSDESKMN;
 +   }
 +   else // Use spmenuSys too!
 +      Window->SystemMenu = (HMENU)0;
 +
 +   return TRUE;
 +}
 +
 +/* Unlink the window from siblings. children and parent are kept in place. */
 +VOID FASTCALL
 +IntUnlinkWindow(PWND Wnd)
 +{
 +   if (Wnd->spwndNext)
 +       Wnd->spwndNext->spwndPrev = Wnd->spwndPrev;
 +
 +   if (Wnd->spwndPrev)
 +       Wnd->spwndPrev->spwndNext = Wnd->spwndNext;
 +
 +   if (Wnd->spwndParent && Wnd->spwndParent->spwndChild == Wnd)
 +       Wnd->spwndParent->spwndChild = Wnd->spwndNext;
 +
 +   Wnd->spwndPrev = Wnd->spwndNext = NULL;
 +}
 +
 +/* FUNCTIONS *****************************************************************/
 +
 +/*
 + * As best as I can figure, this function is used by EnumWindows,
 + * EnumChildWindows, EnumDesktopWindows, & EnumThreadWindows.
 + *
 + * It's supposed to build a list of HWNDs to return to the caller.
 + * We can figure out what kind of list by what parameters are
 + * passed to us.
 + */
 +/*
 + * @implemented
 + */
 +NTSTATUS
 +APIENTRY
 +NtUserBuildHwndList(
 +   HDESK hDesktop,
 +   HWND hwndParent,
 +   BOOLEAN bChildren,
 +   ULONG dwThreadId,
 +   ULONG lParam,
 +   HWND* pWnd,
 +   ULONG* pBufSize)
 +{
 +   NTSTATUS Status;
 +   ULONG dwCount = 0;
 +
 +   if (pBufSize == 0)
 +       return ERROR_INVALID_PARAMETER;
 +
 +   if (hwndParent || !dwThreadId)
 +   {
 +      PDESKTOP Desktop;
 +      PWND Parent, Window;
 +
 +      if(!hwndParent)
 +      {
 +         if(hDesktop == NULL && !(Desktop = IntGetActiveDesktop()))
 +         {
 +            return ERROR_INVALID_HANDLE;
 +         }
 +
 +         if(hDesktop)
 +         {
 +            Status = IntValidateDesktopHandle(hDesktop,
 +                                              UserMode,
 +                                              0,
 +                                              &Desktop);
 +            if(!NT_SUCCESS(Status))
 +            {
 +               return ERROR_INVALID_HANDLE;
 +            }
 +         }
 +         hwndParent = Desktop->DesktopWindow;
 +      }
 +      else
 +      {
 +         hDesktop = 0;
 +      }
 +
 +      if((Parent = UserGetWindowObject(hwndParent)) &&
 +         (Window = Parent->spwndChild))
 +      {
 +         BOOL bGoDown = TRUE;
 +
 +         Status = STATUS_SUCCESS;
 +         while(TRUE)
 +         {
 +            if (bGoDown)
 +            {
 +               if(dwCount++ < *pBufSize && pWnd)
 +               {
 +                  _SEH2_TRY
 +                  {
 +                     ProbeForWrite(pWnd, sizeof(HWND), 1);
 +                     *pWnd = Window->head.h;
 +                     pWnd++;
 +                  }
 +                  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +                  {
 +                     Status = _SEH2_GetExceptionCode();
 +                  }
 +                  _SEH2_END
 +                  if(!NT_SUCCESS(Status))
 +                  {
 +                     SetLastNtError(Status);
 +                     break;
 +                  }
 +               }
 +               if (Window->spwndChild && bChildren)
 +               {
 +                  Window = Window->spwndChild;
 +                  continue;
 +               }
 +               bGoDown = FALSE;
 +            }
 +            if (Window->spwndNext)
 +            {
 +               Window = Window->spwndNext;
 +               bGoDown = TRUE;
 +               continue;
 +            }
 +            Window = Window->spwndParent;
 +            if (Window == Parent)
 +            {
 +               break;
 +            }
 +         }
 +      }
 +
 +      if(hDesktop)
 +      {
 +         ObDereferenceObject(Desktop);
 +      }
 +   }
 +   else // Build EnumThreadWindows list!
 +   {
 +      PETHREAD Thread;
 +      PTHREADINFO W32Thread;
 +      PLIST_ENTRY Current;
 +      PWND Window;
 +
 +      Status = PsLookupThreadByThreadId((HANDLE)dwThreadId, &Thread);
 +      if (!NT_SUCCESS(Status))
 +      {
 +         ERR("Thread Id is not valid!\n");
 +         return ERROR_INVALID_PARAMETER;
 +      }
 +      if (!(W32Thread = (PTHREADINFO)Thread->Tcb.Win32Thread))
 +      {
 +         ObDereferenceObject(Thread);
 +         ERR("Thread is not initialized!\n");
 +         return ERROR_INVALID_PARAMETER;
 +      }
 +
 +      Current = W32Thread->WindowListHead.Flink;
 +      while (Current != &(W32Thread->WindowListHead))
 +      {
 +         Window = CONTAINING_RECORD(Current, WND, ThreadListEntry);
 +         ASSERT(Window);
 +
 +         if (dwCount < *pBufSize && pWnd)
 +         {
 +            _SEH2_TRY
 +            {
 +               ProbeForWrite(pWnd, sizeof(HWND), 1);
 +               *pWnd = Window->head.h;
 +               pWnd++;
 +            }
 +            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +            {
 +               Status = _SEH2_GetExceptionCode();
 +            }
 +            _SEH2_END
 +            if (!NT_SUCCESS(Status))
 +            {
 +               ERR("Failure to build window list!\n");
 +               SetLastNtError(Status);
 +               break;
 +            }
 +         }
 +         dwCount++;
 +         Current = Window->ThreadListEntry.Flink;
 +      }
 +
 +      ObDereferenceObject(Thread);
 +   }
 +
 +   *pBufSize = dwCount;
 +   return STATUS_SUCCESS;
 +}
 +
 +static void IntSendParentNotify( PWND pWindow, UINT msg )
 +{
 +    if ( (pWindow->style & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
 +         !(pWindow->style & WS_EX_NOPARENTNOTIFY))
 +    {
 +        if (pWindow->spwndParent && pWindow->spwndParent != UserGetDesktopWindow())
 +        {
 +            USER_REFERENCE_ENTRY Ref;
 +            UserRefObjectCo(pWindow->spwndParent, &Ref);
 +            co_IntSendMessage( pWindow->spwndParent->head.h,
 +                               WM_PARENTNOTIFY,
 +                               MAKEWPARAM( msg, pWindow->IDMenu),
 +                               (LPARAM)pWindow->head.h );
 +            UserDerefObjectCo(pWindow->spwndParent);
 +        }
 +    }
 +}
 +
 +void FASTCALL
 +IntFixWindowCoordinates(CREATESTRUCTW* Cs, PWND ParentWindow, DWORD* dwShowMode)
 +{
 +#define IS_DEFAULT(x)  ((x) == CW_USEDEFAULT || (x) == (SHORT)0x8000)
 +
 +   /* default positioning for overlapped windows */
 +    if(!(Cs->style & (WS_POPUP | WS_CHILD)))
 +   {
 +      PMONITOR pMonitor;
 +      PRTL_USER_PROCESS_PARAMETERS ProcessParams;
 +
 +      pMonitor = UserGetPrimaryMonitor();
 +
 +      /* Check if we don't have a monitor attached yet */
 +      if(pMonitor == NULL)
 +      {
 +          Cs->x = Cs->y = 0;
 +          Cs->cx = 800;
 +          Cs->cy = 600;
 +          return;
 +      }
 +
 +      ProcessParams = PsGetCurrentProcess()->Peb->ProcessParameters;
 +
 +      if (IS_DEFAULT(Cs->x))
 +      {
 +          if (!IS_DEFAULT(Cs->y)) *dwShowMode = Cs->y;
 +
 +          if(ProcessParams->WindowFlags & STARTF_USEPOSITION)
 +          {
 +              Cs->x = ProcessParams->StartingX;
 +              Cs->y = ProcessParams->StartingY;
 +          }
 +          else
 +          {
 +               Cs->x = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CXSIZE) + UserGetSystemMetrics(SM_CXFRAME));
 +               Cs->y = pMonitor->cWndStack * (UserGetSystemMetrics(SM_CYSIZE) + UserGetSystemMetrics(SM_CYFRAME));
 +               if (Cs->x > ((pMonitor->rcWork.right - pMonitor->rcWork.left) / 4) ||
 +                   Cs->y > ((pMonitor->rcWork.bottom - pMonitor->rcWork.top) / 4))
 +               {
 +                  /* reset counter and position */
 +                  Cs->x = 0;