--- /dev/null
- authors.c
- autocomplete.c
- brsfolder.c
- changenotify.c
- classes.c
- clipboard.c
- control.c
- dataobject.c
- dde.c
- debughlp.c
- desktop.c
- dialogs.c
- dragdrophelper.c
- enumidlist.c
- extracticon.c
- folders.c
- iconcache.c
- pidl.c
- regsvr.c
- shell32_main.c
- shellitem.c
- shelllink.c
- shellole.c
- shellord.c
- shellpath.c
- shellreg.c
- shellstring.c
- shfldr_desktop.c
- shfldr_fs.c
- shfldr_mycomp.c
- shfldr_mydocuments.c
- shfldr_printers.c
- shfldr_admintools.c
- shfldr_netplaces.c
- shfldr_fonts.c
- shfldr_cpanel.c
- shfldr_recyclebin.c
- shlexec.c
- shlfileop.c
- shlfolder.c
- shlfsbind.c
- shlmenu.c
- shlview.c
- shpolicy.c
- shv_def_cmenu.c
- startmenu.c
- stubs.c
- ros-systray.c
- fprop.c
- drive.c
- she_ocmenu.c
- shv_item_new.c
- folder_options.c
++set_cpp()
+
+remove_definitions(-D_WIN32_WINNT=0x502)
+add_definitions(-D_WIN32_WINNT=0x600)
+
+add_definitions(
+ -D_SHELL32_
+ -DCOM_NO_WINDOWS_H
+ -D_WINE)
+
+include_directories(
+ ${REACTOS_SOURCE_DIR}/include/reactos/wine
+ ${REACTOS_SOURCE_DIR}/lib/recyclebin
++ ${REACTOS_SOURCE_DIR}/lib/atl
+ ${REACTOS_SOURCE_DIR})
+
+spec2def(shell32.dll shell32.spec)
+
+list(APPEND SOURCE
- set_module_type(shell32 win32dll)
- target_link_libraries(shell32 wine uuid recyclebin)
++ authors.cpp
++ autocomplete.cpp
++ brsfolder.cpp
++ changenotify.cpp
++ classes.cpp
++ clipboard.cpp
++ control.cpp
++ dataobject.cpp
++ dde.cpp
++ debughlp.cpp
++ desktop.cpp
++ dialogs.cpp
++ dragdrophelper.cpp
++ enumidlist.cpp
++ extracticon.cpp
++ folders.cpp
++ iconcache.cpp
++ pidl.cpp
++ shell32_main.cpp
++ shellitem.cpp
++ shelllink.cpp
++ shellole.cpp
++ shellord.cpp
++ shellpath.cpp
++ shellreg.cpp
++ shellstring.cpp
++ shfldr_desktop.cpp
++ shfldr_fs.cpp
++ shfldr_mycomp.cpp
++ shfldr_mydocuments.cpp
++ shfldr_printers.cpp
++ shfldr_admintools.cpp
++ shfldr_netplaces.cpp
++ shfldr_fonts.cpp
++ shfldr_cpanel.cpp
++ shfldr_recyclebin.cpp
++ shlexec.cpp
++ shlfileop.cpp
++ shlfolder.cpp
++ shlfsbind.cpp
++ shlmenu.cpp
++ shlview.cpp
++ shpolicy.cpp
++ shv_def_cmenu.cpp
++ startmenu.cpp
++ stubs.cpp
++ ros-systray.cpp
++ fprop.cpp
++ drive.cpp
++ she_ocmenu.cpp
++ shv_item_new.cpp
++ folder_options.cpp
+ shell32.rc
+ ${CMAKE_CURRENT_BINARY_DIR}/shell32_stubs.c
+ ${CMAKE_CURRENT_BINARY_DIR}/shell32.def)
+
+add_library(shell32 SHARED ${SOURCE})
++
++set_module_type(shell32 win32dll UNICODE)
++
++target_link_libraries(shell32
++ atlnew
++ wine
++ uuid
++ recyclebin)
++
+add_delay_importlibs(shell32 ole32 version)
+
+add_importlibs(shell32
+ advapi32
+ gdi32
+ user32
+ comctl32
+ comdlg32
+ shlwapi
+ devmgr
+ winspool
+ winmm
+ msvcrt
+ kernel32
+ ntdll)
+
+add_pch(shell32 precomp.h)
++
+add_cd_file(TARGET shell32 DESTINATION reactos/system32 FOR all)
+add_importlib_target(shell32.spec)
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
- #define NONAMELESSUNION
- #define NONAMELESSSTRUCT
+#ifndef _PRECOMP_H__
+#define _PRECOMP_H__
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+
+#define COBJMACROS
- #define UNICODE
- #define _UNICODE
+#define WIN32_NO_STATUS
+#define NTOS_MODE_USER
- #include <ndk/umtypes.h>
+
+#include <windows.h>
+
+#include <shlguid.h>
+#include <shlguid_undoc.h>
+#include <shlwapi.h>
+#include <shlobj.h>
+#include <shlobj_undoc.h>
+#include <shldisp.h>
+#include <commdlg.h>
+#include <commctrl.h>
+#include <cpl.h>
+#include <objbase.h>
+#include <ole2.h>
+#include <ocidl.h>
+#include <docobj.h>
+#include <prsht.h>
+//#include <initguid.h>
+//#include <devguid.h>
+#include <shobjidl.h>
+#include <shellapi.h>
+#include <msi.h>
+#include <appmgmt.h>
+#include <ntquery.h>
+#include <recyclebin.h>
+#include <shtypes.h>
++#include <ndk/rtlfuncs.h>
+#include <fmifs/fmifs.h>
+#include <largeint.h>
+#include <sddl.h>
+
++#include <tchar.h>
++#include <atlbase.h>
++#include <atlcom.h>
++#include <atlwin.h>
++
+#include "base/shell/explorer-new/todo.h"
+#include "dlgs.h"
+#include "pidl.h"
+#include "debughlp.h"
+#include "undocshell.h"
+#include "shell32_main.h"
+#include "shresdef.h"
+#include "cpanel.h"
+#include "enumidlist.h"
+#include "shfldr.h"
+#include "version.h"
+#include "shellfolder.h"
+#include "xdg.h"
+#include "shellapi.h"
+
++#include "shfldr_fs.h"
++#include "shfldr_mycomp.h"
++#include "shfldr_desktop.h"
++#include "shellitem.h"
++#include "shelllink.h"
++#include "dragdrophelper.h"
++#include "shfldr_cpanel.h"
++#include "autocomplete.h"
++#include "shfldr_mydocuments.h"
++#include "shfldr_netplaces.h"
++#include "shfldr_fonts.h"
++#include "shfldr_printers.h"
++#include "shfldr_admintools.h"
++#include "shfldr_recyclebin.h"
++#include "she_ocmenu.h"
++#include "shv_item_new.h"
++#include "startmenu.h"
++
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+extern const GUID CLSID_AdminFolderShortcut;
+extern const GUID CLSID_FontsFolderShortcut;
+extern const GUID CLSID_StartMenu;
+extern const GUID CLSID_MenuBandSite;
+extern const GUID CLSID_OpenWith;
+extern const GUID CLSID_UnixFolder;
+extern const GUID CLSID_UnixDosFolder;
+extern const GUID SHELL32_AdvtShortcutProduct;
+extern const GUID SHELL32_AdvtShortcutComponent;
+
+
+#endif
--- /dev/null
- <module name="shell32" type="win32dll" baseaddress="${BASEADDRESS_SHELL32}" installbase="system32" installname="shell32.dll" crt="msvcrt">
+<group>
- <include base="shell32">.</include>
++<module name="shell32" type="win32dll" baseaddress="${BASEADDRESS_SHELL32}" installbase="system32" installname="shell32.dll" allowwarnings="true" crt="msvcrt">
+ <autoregister infsection="OleControlDlls" type="Both" />
+ <importlibrary definition="shell32.spec" />
- <define name="_SHELL32_" />
+ <include base="recyclebin">.</include>
+ <include base="ReactOS">include/reactos/wine</include>
- <file>authors.c</file>
- <file>autocomplete.c</file>
- <file>brsfolder.c</file>
- <file>changenotify.c</file>
- <file>classes.c</file>
- <file>clipboard.c</file>
- <file>control.c</file>
- <file>dataobject.c</file>
- <file>dde.c</file>
- <file>debughlp.c</file>
- <file>desktop.c</file>
- <file>dialogs.c</file>
- <file>dragdrophelper.c</file>
- <file>enumidlist.c</file>
- <file>extracticon.c</file>
- <file>folders.c</file>
- <file>iconcache.c</file>
- <file>pidl.c</file>
- <file>regsvr.c</file>
- <file>shell32_main.c</file>
- <file>shellitem.c</file>
- <file>shelllink.c</file>
- <file>shellole.c</file>
- <file>shellord.c</file>
- <file>shellpath.c</file>
- <file>shellreg.c</file>
- <file>shellstring.c</file>
- <file>shfldr_desktop.c</file>
- <file>shfldr_fs.c</file>
- <file>shfldr_mycomp.c</file>
- <file>shfldr_mydocuments.c</file>
- <file>shfldr_printers.c</file>
- <file>shfldr_admintools.c</file>
- <file>shfldr_netplaces.c</file>
- <file>shfldr_fonts.c</file>
- <file>shfldr_cpanel.c</file>
- <file>shfldr_recyclebin.c</file>
- <file>shlexec.c</file>
- <file>shlfileop.c</file>
- <file>shlfolder.c</file>
- <file>shlfsbind.c</file>
- <file>shlmenu.c</file>
- <file>shlview.c</file>
- <file>shpolicy.c</file>
- <file>shv_def_cmenu.c</file>
- <file>startmenu.c</file>
- <file>stubs.c</file>
- <file>ros-systray.c</file>
- <file>fprop.c</file>
- <file>drive.c</file>
- <file>she_ocmenu.c</file>
- <file>shv_item_new.c</file>
- <file>folder_options.c</file>
++ <include base="atlnew">.</include>
++ <define name="_SHELL32_" />
+ <define name="COM_NO_WINDOWS_H" />
+ <define name="_WINE" />
++ <define name="UNICODE" />
++ <define name="_UNICODE" />
+ <redefine name="_WIN32_WINNT">0x600</redefine>
+ <library>wine</library>
+ <library>uuid</library>
+ <library>recyclebin</library>
+ <library>ntdll</library>
+ <library>advapi32</library>
+ <library>gdi32</library>
+ <library>user32</library>
+ <library>comctl32</library>
+ <library>comdlg32</library>
+ <library>shlwapi</library>
+ <library>ole32</library>
+ <library>version</library>
+ <library>devmgr</library>
+ <library>winspool</library>
+ <library>winmm</library>
++ <library>msvcrt</library>
++ <library>atlnew</library>
+ <pch>precomp.h</pch>
++ <file>authors.cpp</file>
++ <file>autocomplete.cpp</file>
++ <file>brsfolder.cpp</file>
++ <file>changenotify.cpp</file>
++ <file>classes.cpp</file>
++ <file>clipboard.cpp</file>
++ <file>control.cpp</file>
++ <file>dataobject.cpp</file>
++ <file>dde.cpp</file>
++ <file>debughlp.cpp</file>
++ <file>desktop.cpp</file>
++ <file>dialogs.cpp</file>
++ <file>dragdrophelper.cpp</file>
++ <file>enumidlist.cpp</file>
++ <file>extracticon.cpp</file>
++ <file>folders.cpp</file>
++ <file>iconcache.cpp</file>
++ <file>pidl.cpp</file>
++ <file>shell32_main.cpp</file>
++ <file>shellitem.cpp</file>
++ <file>shelllink.cpp</file>
++ <file>shellole.cpp</file>
++ <file>shellord.cpp</file>
++ <file>shellpath.cpp</file>
++ <file>shellreg.cpp</file>
++ <file>shellstring.cpp</file>
++ <file>shfldr_desktop.cpp</file>
++ <file>shfldr_fs.cpp</file>
++ <file>shfldr_mycomp.cpp</file>
++ <file>shfldr_mydocuments.cpp</file>
++ <file>shfldr_printers.cpp</file>
++ <file>shfldr_admintools.cpp</file>
++ <file>shfldr_netplaces.cpp</file>
++ <file>shfldr_fonts.cpp</file>
++ <file>shfldr_cpanel.cpp</file>
++ <file>shfldr_recyclebin.cpp</file>
++ <file>shlexec.cpp</file>
++ <file>shlfileop.cpp</file>
++ <file>shlfolder.cpp</file>
++ <file>shlfsbind.cpp</file>
++ <file>shlmenu.cpp</file>
++ <file>shlview.cpp</file>
++ <file>shpolicy.cpp</file>
++ <file>shv_def_cmenu.cpp</file>
++ <file>startmenu.cpp</file>
++ <file>stubs.cpp</file>
++ <file>ros-systray.cpp</file>
++ <file>fprop.cpp</file>
++ <file>drive.cpp</file>
++ <file>she_ocmenu.cpp</file>
++ <file>shv_item_new.cpp</file>
++ <file>folder_options.cpp</file>
+ <file>shell32.rc</file>
+</module>
+<module name="shobjidl_local_interface" type="idlinterface">
+ <file>shobjidl_local.idl</file>
+</module>
+</group>
--- /dev/null
--- /dev/null
++/*
++ * Virtual Desktop Folder
++ *
++ * Copyright 1997 Marcus Meissner
++ * Copyright 1998, 1999, 2002 Juergen Schmied
++ * 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
++ */
++
++#include <precomp.h>
++
++WINE_DEFAULT_DEBUG_CHANNEL(shell);
++
++/*
++CDesktopFolder should create two file system folders internally, one representing the
++user's desktop folder, and the other representing the common desktop folder. It should
++also create a CRegFolder to represent the virtual items that exist only in the registry.
++The CRegFolder is aggregated by the CDesktopFolder, and queries for the CLSID_IShellFolder,
++CLSID_IShellFolder2, or CLSID_IShellIconOverlay interfaces prefer the CRegFolder
++implementation.
++The CDesktopFolderEnum class should create two enumerators, one for each of the file
++system folders, and enumerate the contents of each folder. Since the CRegFolder
++implementation of IShellFolder::EnumObjects enumerates the virtual items, the
++CDesktopFolderEnum is only responsible for returning the physical items.
++CDesktopFolderEnum is incorrect where it filters My Computer from the enumeration
++if the new start menu is used. The CDesktopViewCallback is responsible for filtering
++it from the view by handling the IncludeObject query to return S_FALSE. The enumerator
++always shows My Computer.
++*/
++
++/***********************************************************************
++* Desktopfolder implementation
++*/
++
++class CDesktopFolder;
++
++class CDesktopFolderEnum :
++ public IEnumIDListImpl
++{
++private:
++// CComPtr fDesktopEnumerator;
++// CComPtr fCommonDesktopEnumerator;
++public:
++ CDesktopFolderEnum();
++ ~CDesktopFolderEnum();
++ HRESULT WINAPI Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags);
++
++BEGIN_COM_MAP(CDesktopFolderEnum)
++ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
++END_COM_MAP()
++};
++
++WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls);
++int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll);
++
++static const shvheader DesktopSFHeader[] = {
++ {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
++ {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
++ {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
++ {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
++ {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
++};
++
++#define DESKTOPSHELLVIEWCOLUMNS 5
++
++CDesktopFolderEnum::CDesktopFolderEnum()
++{
++}
++
++CDesktopFolderEnum::~CDesktopFolderEnum()
++{
++}
++
++static const WCHAR ClassicStartMenuW[] = {'S','O','F','T','W','A','R','E','\\',
++ 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
++ 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l','o','r','e','r',
++ '\\','H','i','d','e','D','e','s','k','t','o','p','I','c','o','n','s','\\',
++ 'C','l','a','s','s','i','c','S','t','a','r','t','M','e','n','u','\0' };
++
++INT
++IsNamespaceExtensionHidden(WCHAR *iid)
++{
++ DWORD Result, dwResult;
++ dwResult = sizeof(DWORD);
++
++ if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */
++ ClassicStartMenuW,
++ iid,
++ RRF_RT_DWORD,
++ NULL,
++ &Result,
++ &dwResult) != ERROR_SUCCESS)
++ {
++ return -1;
++ }
++
++ return Result;
++}
++
++static
++VOID
++SetNamespaceExtensionVisibleStatus(const WCHAR * iid, DWORD dwStatus)
++{
++ HKEY hKey;
++
++ if (RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
++ {
++ RegSetValueExW(hKey, iid, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(DWORD));
++ RegCloseKey(hKey);
++ }
++}
++
++/**************************************************************************
++ * CreateDesktopEnumList()
++ */
++static const WCHAR Desktop_NameSpaceW[] = { 'S','O','F','T','W','A','R','E',
++ '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
++ 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
++ 'o','r','e','r','\\','D','e','s','k','t','o','p','\\','N','a','m','e','s','p',
++ 'a','c','e','\0' };
++
++HRESULT WINAPI CDesktopFolderEnum::Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags)
++{
++ BOOL ret = TRUE;
++ WCHAR szPath[MAX_PATH];
++
++ static WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}";
++
++ TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
++
++ /* enumerate the root folders */
++ if (dwFlags & SHCONTF_FOLDERS)
++ {
++ HKEY hkey;
++ UINT i;
++ DWORD dwResult;
++
++ /* create the pidl for This item */
++ if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1)
++ {
++ ret = AddToEnumList(_ILCreateMyDocuments());
++ }
++ ret = AddToEnumList(_ILCreateMyComputer());
++
++ for (i = 0; i < 2; i++)
++ {
++ if (i == 0)
++ dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
++ else
++ dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
++
++ if (dwResult == ERROR_SUCCESS)
++ {
++ WCHAR iid[50];
++ LPITEMIDLIST pidl;
++ int i=0;
++
++ while (ret)
++ {
++ DWORD size;
++ LONG r;
++
++ size = sizeof (iid) / sizeof (iid[0]);
++ r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
++ if (ERROR_SUCCESS == r)
++ {
++ if (IsNamespaceExtensionHidden(iid) < 1)
++ {
++ pidl = _ILCreateGuidFromStrW(iid);
++ if (pidl != NULL)
++ {
++ if (!HasItemWithCLSID(pidl))
++ {
++ ret = AddToEnumList(pidl);
++ }
++ else
++ {
++ SHFree(pidl);
++ }
++ }
++ }
++ }
++ else if (ERROR_NO_MORE_ITEMS == r)
++ break;
++ else
++ ret = FALSE;
++ i++;
++ }
++ RegCloseKey(hkey);
++ }
++ }
++ for (i = 0; i < 2; i++)
++ {
++ if (i == 0)
++ dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, ClassicStartMenuW, 0, KEY_READ, &hkey);
++ else
++ dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_READ, &hkey);
++
++ if (dwResult == ERROR_SUCCESS)
++ {
++ DWORD j = 0, dwVal, Val, dwType, dwIID;
++ LONG r;
++ WCHAR iid[50];
++
++ while(ret)
++ {
++ dwVal = sizeof(Val);
++ dwIID = sizeof(iid) / sizeof(WCHAR);
++
++ r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal);
++ if (r == ERROR_SUCCESS)
++ {
++ if (Val == 0 && dwType == REG_DWORD)
++ {
++ LPITEMIDLIST pidl = _ILCreateGuidFromStrW(iid);
++ if (pidl != NULL)
++ {
++ if (!HasItemWithCLSID(pidl))
++ {
++ AddToEnumList(pidl);
++ }
++ else
++ {
++ SHFree(pidl);
++ }
++ }
++ }
++ }
++ else if (ERROR_NO_MORE_ITEMS == r)
++ break;
++ else
++ ret = FALSE;
++ }
++ RegCloseKey(hkey);
++ }
++
++ }
++ }
++
++ /* enumerate the elements in %windir%\desktop */
++ ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
++ ret = ret && CreateFolderEnumList(szPath, dwFlags);
++
++ ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
++ ret = ret && CreateFolderEnumList(szPath, dwFlags);
++
++ return ret ? S_OK : E_FAIL;
++}
++
++CDesktopFolder::CDesktopFolder()
++{
++ pidlRoot = NULL;
++ sPathTarget = NULL;
++}
++
++CDesktopFolder::~CDesktopFolder()
++{
++}
++
++HRESULT WINAPI CDesktopFolder::FinalConstruct()
++{
++ WCHAR szMyPath[MAX_PATH];
++
++ if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
++ return E_UNEXPECTED;
++
++ pidlRoot = _ILCreateDesktop(); /* my qualified pidl */
++ sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
++ wcscpy(sPathTarget, szMyPath);
++ return S_OK;
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnParseDisplayName
++ *
++ * NOTES
++ * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
++ * to MyComputer
++ */
++HRESULT WINAPI CDesktopFolder::ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
++ DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes)
++{
++ WCHAR szElement[MAX_PATH];
++ LPCWSTR szNext = NULL;
++ LPITEMIDLIST pidlTemp = NULL;
++ HRESULT hr = S_OK;
++ CLSID clsid;
++
++ TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
++ this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
++ pchEaten, ppidl, pdwAttributes);
++
++ if (!ppidl)
++ return E_INVALIDARG;
++
++ if (!lpszDisplayName)
++ {
++ *ppidl = NULL;
++ return E_INVALIDARG;
++ }
++
++ *ppidl = NULL;
++
++ if (pchEaten)
++ *pchEaten = 0; /* strange but like the original */
++
++ if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
++ {
++ szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
++ TRACE ("-- element: %s\n", debugstr_w (szElement));
++ CLSIDFromString (szElement + 2, &clsid);
++ pidlTemp = _ILCreateGuid (PT_GUID, clsid);
++ }
++ else if (PathGetDriveNumberW (lpszDisplayName) >= 0)
++ {
++ /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
++ pidlTemp = _ILCreateMyComputer ();
++ szNext = lpszDisplayName;
++ }
++ else if (PathIsUNCW(lpszDisplayName))
++ {
++ pidlTemp = _ILCreateNetwork();
++ szNext = lpszDisplayName;
++ }
++ else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
++ {
++ *ppidl = pidlTemp;
++ return S_OK;
++ }
++ else
++ {
++ /* it's a filesystem path on the desktop. Let a FSFolder parse it */
++
++ if (*lpszDisplayName)
++ {
++ WCHAR szPath[MAX_PATH];
++ LPWSTR pathPtr;
++
++ /* build a complete path to create a simple pidl */
++ lstrcpynW(szPath, sPathTarget, MAX_PATH);
++ pathPtr = PathAddBackslashW(szPath);
++ if (pathPtr)
++ {
++ lstrcpynW(pathPtr, lpszDisplayName, MAX_PATH - (pathPtr - szPath));
++ hr = _ILCreateFromPathW(szPath, &pidlTemp);
++ }
++ else
++ {
++ /* should never reach here, but for completeness */
++ hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
++ }
++ }
++ else
++ pidlTemp = _ILCreateMyComputer();
++
++ szNext = NULL;
++ }
++
++ if (SUCCEEDED(hr) && pidlTemp)
++ {
++ if (szNext && *szNext)
++ {
++ hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
++ &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
++ }
++ else
++ {
++ if (pdwAttributes && *pdwAttributes)
++ hr = SHELL32_GetItemAttributes((IShellFolder *)this,
++ pidlTemp, pdwAttributes);
++ }
++ }
++
++ if (SUCCEEDED(hr))
++ *ppidl = pidlTemp;
++ else
++ *ppidl = NULL;
++
++ TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
++
++ return hr;
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnEnumObjects
++ */
++HRESULT WINAPI CDesktopFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
++{
++ CComObject<CDesktopFolderEnum> *theEnumerator;
++ CComPtr<IEnumIDList> result;
++ HRESULT hResult;
++
++ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
++
++ if (ppEnumIDList == NULL)
++ return E_POINTER;
++ *ppEnumIDList = NULL;
++
++ ATLTRY (theEnumerator = new CComObject<CDesktopFolderEnum>);
++
++ if (theEnumerator == NULL)
++ return E_OUTOFMEMORY;
++
++ hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result);
++ if (FAILED (hResult))
++ {
++ delete theEnumerator;
++ return hResult;
++ }
++
++ hResult = theEnumerator->Initialize (this, hwndOwner, dwFlags);
++ if (FAILED (hResult))
++ return hResult;
++ *ppEnumIDList = result.Detach ();
++
++ TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
++
++ return S_OK;
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnBindToObject
++ */
++HRESULT WINAPI CDesktopFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++{
++ TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
++ this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
++
++ return SHELL32_BindToChild( pidlRoot, sPathTarget, pidl, riid, ppvOut );
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnBindToStorage
++ */
++HRESULT WINAPI CDesktopFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++{
++ FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
++ this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
++
++ *ppvOut = NULL;
++ return E_NOTIMPL;
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnCompareIDs
++ */
++HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++{
++ int nReturn;
++
++ TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
++ nReturn = SHELL32_CompareIDs ((IShellFolder *)this, lParam, pidl1, pidl2);
++ TRACE ("-- %i\n", nReturn);
++ return nReturn;
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnCreateViewObject
++ */
++HRESULT WINAPI CDesktopFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
++{
++ CComPtr<IShellView> pShellView;
++ HRESULT hr = E_INVALIDARG;
++
++ TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
++ this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
++
++ if (!ppvOut)
++ return hr;
++
++ *ppvOut = NULL;
++
++ if (IsEqualIID (riid, IID_IDropTarget))
++ {
++ WARN ("IDropTarget not implemented\n");
++ hr = E_NOTIMPL;
++ }
++ else if (IsEqualIID (riid, IID_IContextMenu))
++ {
++ WARN ("IContextMenu not implemented\n");
++ hr = E_NOTIMPL;
++ }
++ else if (IsEqualIID (riid, IID_IShellView))
++ {
++ hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
++ if (pShellView)
++ hr = pShellView->QueryInterface(riid, ppvOut);
++ }
++ TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
++ return hr;
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnGetAttributesOf
++ */
++HRESULT WINAPI CDesktopFolder::GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut)
++{
++ HRESULT hr = S_OK;
++ static const DWORD dwDesktopAttributes =
++ SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
++ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER;
++ static const DWORD dwMyComputerAttributes =
++ SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET |
++ SFGAO_DROPTARGET | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
++
++ TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
++ this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
++
++ if (!rgfInOut)
++ return E_INVALIDARG;
++ if (cidl && !apidl)
++ return E_INVALIDARG;
++
++ if (*rgfInOut == 0)
++ *rgfInOut = ~0;
++
++ if(cidl == 0) {
++ *rgfInOut &= dwDesktopAttributes;
++ } else {
++ while (cidl > 0 && *apidl) {
++ pdump (*apidl);
++ if (_ILIsDesktop(*apidl)) {
++ *rgfInOut &= dwDesktopAttributes;
++ } else if (_ILIsMyComputer(*apidl)) {
++ *rgfInOut &= dwMyComputerAttributes;
++ } else {
++ SHELL32_GetItemAttributes ((IShellFolder *)this, *apidl, rgfInOut);
++ }
++ apidl++;
++ cidl--;
++ }
++ }
++ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
++ *rgfInOut &= ~SFGAO_VALIDATE;
++
++ TRACE ("-- result=0x%08x\n", *rgfInOut);
++
++ return hr;
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnGetUIObjectOf
++ *
++ * PARAMETERS
++ * HWND hwndOwner, //[in ] Parent window for any output
++ * UINT cidl, //[in ] array size
++ * LPCITEMIDLIST* apidl, //[in ] simple pidl array
++ * REFIID riid, //[in ] Requested Interface
++ * UINT* prgfInOut, //[ ] reserved
++ * LPVOID* ppvObject) //[out] Resulting Interface
++ *
++ */
++HRESULT WINAPI CDesktopFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
++ REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
++{
++ LPITEMIDLIST pidl;
++ IUnknown *pObj = NULL;
++ HRESULT hr = E_INVALIDARG;
++
++ TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
++ this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
++
++ if (!ppvOut)
++ return hr;
++
++ *ppvOut = NULL;
++
++ if (IsEqualIID (riid, IID_IContextMenu))
++ {
++ hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder *)this, NULL, 0, NULL, (IContextMenu **)&pObj);
++ }
++ else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
++ {
++ hr = IDataObject_Constructor( hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
++ }
++ else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
++ {
++ pidl = ILCombine (pidlRoot, apidl[0]);
++ pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
++ SHFree (pidl);
++ hr = S_OK;
++ }
++ else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
++ {
++ pidl = ILCombine (pidlRoot, apidl[0]);
++ pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
++ SHFree (pidl);
++ hr = S_OK;
++ }
++ else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
++ {
++ hr = this->QueryInterface (IID_IDropTarget, (LPVOID *)&pObj);
++ }
++ else if ((IsEqualIID(riid, IID_IShellLinkW) ||
++ IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
++ {
++ pidl = ILCombine (pidlRoot, apidl[0]);
++ hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
++ SHFree (pidl);
++ }
++ else
++ hr = E_NOINTERFACE;
++
++ if (SUCCEEDED(hr) && !pObj)
++ hr = E_OUTOFMEMORY;
++
++ *ppvOut = pObj;
++ TRACE ("(%p)->hr=0x%08x\n", this, hr);
++ return hr;
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnGetDisplayNameOf
++ *
++ * NOTES
++ * special case: pidl = null gives desktop-name back
++ */
++HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++{
++ HRESULT hr = S_OK;
++ LPWSTR pszPath;
++
++ TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
++ pdump (pidl);
++
++ if (!strRet)
++ return E_INVALIDARG;
++
++ pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
++ if (!pszPath)
++ return E_OUTOFMEMORY;
++
++ if (_ILIsDesktop (pidl))
++ {
++ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
++ (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
++ wcscpy(pszPath, sPathTarget);
++ else
++ HCR_GetClassNameW(CLSID_ShellDesktop, pszPath, MAX_PATH);
++ }
++ else if (_ILIsPidlSimple (pidl))
++ {
++ GUID const *clsid;
++
++ if ((clsid = _ILGetGUIDPointer (pidl)))
++ {
++ if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
++ {
++ int bWantsForParsing;
++
++ /*
++ * We can only get a filesystem path from a shellfolder if the
++ * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
++ *
++ * Exception: The MyComputer folder doesn't have this key,
++ * but any other filesystem backed folder it needs it.
++ */
++ if (IsEqualIID (*clsid, CLSID_MyComputer))
++ {
++ bWantsForParsing = TRUE;
++ }
++ else
++ {
++ /* get the "WantsFORPARSING" flag from the registry */
++ static const WCHAR clsidW[] =
++ { 'C','L','S','I','D','\\',0 };
++ static const WCHAR shellfolderW[] =
++ { '\\','s','h','e','l','l','f','o','l','d','e','r',0 };
++ static const WCHAR wantsForParsingW[] =
++ { 'W','a','n','t','s','F','o','r','P','a','r','s','i','n',
++ 'g',0 };
++ WCHAR szRegPath[100];
++ LONG r;
++
++ wcscpy (szRegPath, clsidW);
++ SHELL32_GUIDToStringW (*clsid, &szRegPath[6]);
++ wcscat (szRegPath, shellfolderW);
++ r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
++ wantsForParsingW, NULL, NULL, NULL);
++ if (r == ERROR_SUCCESS)
++ bWantsForParsing = TRUE;
++ else
++ bWantsForParsing = FALSE;
++ }
++
++ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
++ bWantsForParsing)
++ {
++ /*
++ * we need the filesystem path to the destination folder.
++ * Only the folder itself can know it
++ */
++ hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
++ pszPath,
++ MAX_PATH);
++ }
++ else
++ {
++ /* parsing name like ::{...} */
++ pszPath[0] = ':';
++ pszPath[1] = ':';
++ SHELL32_GUIDToStringW (*clsid, &pszPath[2]);
++ }
++ }
++ else
++ {
++ /* user friendly name */
++ HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
++ }
++ }
++ else
++ {
++ int cLen = 0;
++
++ /* file system folder or file rooted at the desktop */
++ if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
++ (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
++ {
++ lstrcpynW(pszPath, sPathTarget, MAX_PATH - 1);
++ PathAddBackslashW(pszPath);
++ cLen = wcslen(pszPath);
++ }
++
++ _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
++ if (!_ILIsFolder(pidl))
++ SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
++
++ if (GetFileAttributes(pszPath) == INVALID_FILE_ATTRIBUTES)
++ {
++ /* file system folder or file rooted at the AllUsers desktop */
++ if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
++ (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
++ {
++ SHGetSpecialFolderPathW(0, pszPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
++ PathAddBackslashW(pszPath);
++ cLen = wcslen(pszPath);
++ }
++
++ _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
++ if (!_ILIsFolder(pidl))
++ SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
++ } }
++ }
++ else
++ {
++ /* a complex pidl, let the subfolder do the work */
++ hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
++ pszPath, MAX_PATH);
++ }
++
++ if (SUCCEEDED(hr))
++ {
++ /* Win9x always returns ANSI strings, NT always returns Unicode strings */
++ if (GetVersion() & 0x80000000)
++ {
++ strRet->uType = STRRET_CSTR;
++ if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
++ NULL, NULL))
++ strRet->cStr[0] = '\0';
++ CoTaskMemFree(pszPath);
++ }
++ else
++ {
++ strRet->uType = STRRET_WSTR;
++ strRet->pOleStr = pszPath;
++ }
++ }
++ else
++ CoTaskMemFree(pszPath);
++
++ TRACE ("-- (%p)->(%s,0x%08x)\n", this,
++ strRet->uType == STRRET_CSTR ? strRet->cStr :
++ debugstr_w(strRet->pOleStr), hr);
++ return hr;
++}
++
++/**************************************************************************
++ * ISF_Desktop_fnSetNameOf
++ * Changes the name of a file object or subfolder, possibly changing its item
++ * identifier in the process.
++ *
++ * PARAMETERS
++ * HWND hwndOwner, //[in ] Owner window for output
++ * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
++ * LPCOLESTR lpszName, //[in ] the items new display name
++ * DWORD dwFlags, //[in ] SHGNO formatting flags
++ * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
++ */
++HRESULT WINAPI CDesktopFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */
++ LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut)
++{
++ CComPtr<IShellFolder2> psf;
++ HRESULT hr;
++ WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
++ LPWSTR ptr;
++ BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
++
++ TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
++ debugstr_w (lpName), dwFlags, pPidlOut);
++
++ if (_ILGetGUIDPointer(pidl))
++ {
++ if (SUCCEEDED(BindToObject(pidl, NULL, IID_IShellFolder2, (LPVOID *)&psf)))
++ {
++ hr = psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
++ return hr;
++ }
++ }
++
++ /* build source path */
++ lstrcpynW(szSrc, sPathTarget, MAX_PATH);
++ ptr = PathAddBackslashW (szSrc);
++ if (ptr)
++ _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
++
++ /* build destination path */
++ if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
++ lstrcpynW(szDest, sPathTarget, MAX_PATH);
++ ptr = PathAddBackslashW (szDest);
++ if (ptr)
++ lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
++ } else
++ lstrcpynW(szDest, lpName, MAX_PATH);
++
++ if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
++ WCHAR *ext = PathFindExtensionW(szSrc);
++ if(*ext != '\0') {
++ INT len = wcslen(szDest);
++ lstrcpynW(szDest + len, ext, MAX_PATH - len);
++ }
++ }
++
++ if (!memcmp(szSrc, szDest, (wcslen(szDest)+1) * sizeof(WCHAR)))
++ {
++ /* src and destination is the same */
++ hr = S_OK;
++ if (pPidlOut)
++ hr = _ILCreateFromPathW(szDest, pPidlOut);
++
++ return hr;
++ }
++
++ TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
++ if (MoveFileW (szSrc, szDest))
++ {
++ hr = S_OK;
++
++ if (pPidlOut)
++ hr = _ILCreateFromPathW(szDest, pPidlOut);
++
++ SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
++ SHCNF_PATHW, szSrc, szDest);
++
++ return hr;
++ }
++ return E_FAIL;
++}
++
++HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
++{
++ FIXME ("(%p)\n", this);
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
++{
++ FIXME ("(%p)\n", this);
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
++{
++ TRACE ("(%p)\n", this);
++
++ if (pSort)
++ *pSort = 0;
++ if (pDisplay)
++ *pDisplay = 0;
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
++{
++ TRACE ("(%p)\n", this);
++
++ if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
++ return E_INVALIDARG;
++
++ *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDesktopFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
++{
++ FIXME ("(%p)\n", this);
++
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDesktopFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
++{
++ HRESULT hr = S_OK;
++
++ TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
++
++ if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
++ return E_INVALIDARG;
++
++ if (!pidl)
++ {
++ psd->fmt = DesktopSFHeader[iColumn].fmt;
++ psd->cxChar = DesktopSFHeader[iColumn].cxChar;
++ psd->str.uType = STRRET_CSTR;
++ LoadStringA (shell32_hInstance, DesktopSFHeader[iColumn].colnameid,
++ psd->str.cStr, MAX_PATH);
++ return S_OK;
++ }
++
++ /* the data from the pidl */
++ psd->str.uType = STRRET_CSTR;
++ switch (iColumn)
++ {
++ case 0: /* name */
++ hr = GetDisplayNameOf(pidl,
++ SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
++ break;
++ case 1: /* size */
++ _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH);
++ break;
++ case 2: /* type */
++ _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
++ break;
++ case 3: /* date */
++ _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH);
++ break;
++ case 4: /* attributes */
++ _ILGetFileAttributes (pidl, psd->str.cStr, MAX_PATH);
++ break;
++ }
++
++ return hr;
++}
++
++HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
++{
++ FIXME ("(%p)\n", this);
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
++{
++ TRACE ("(%p)\n", this);
++
++ if (!lpClassId)
++ return E_POINTER;
++
++ *lpClassId = CLSID_ShellDesktop;
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
++{
++ TRACE ("(%p)->(%p)\n", this, pidl);
++
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
++{
++ TRACE ("(%p)->(%p)\n", this, pidl);
++
++ if (!pidl) return E_POINTER;
++ *pidl = ILClone (pidlRoot);
++ return S_OK;
++}
++
++HRESULT WINAPI CDesktopFolder::GetUniqueName(LPWSTR pwszName, UINT uLen)
++{
++ CComPtr<IEnumIDList> penum;
++ HRESULT hr;
++ WCHAR wszText[MAX_PATH];
++ WCHAR wszNewFolder[25];
++ const WCHAR wszFormat[] = {'%','s',' ','%','d',0 };
++
++ LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, sizeof(wszNewFolder)/sizeof(WCHAR));
++
++ TRACE ("(%p)(%p %u)\n", this, pwszName, uLen);
++
++ if (uLen < sizeof(wszNewFolder)/sizeof(WCHAR) + 3)
++ return E_POINTER;
++
++ lstrcpynW (pwszName, wszNewFolder, uLen);
++
++ hr = EnumObjects(0,
++ SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
++ if (penum) {
++ LPITEMIDLIST pidl;
++ DWORD dwFetched;
++ int i = 1;
++
++next:
++ penum->Reset ();
++ while (S_OK == penum->Next(1, &pidl, &dwFetched) &&
++ dwFetched) {
++ _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
++ if (0 == lstrcmpiW (wszText, pwszName)) {
++ _snwprintf (pwszName, uLen, wszFormat, wszNewFolder, i++);
++ if (i > 99) {
++ hr = E_FAIL;
++ break;
++ }
++ goto next;
++ }
++ }
++
++ }
++ return hr;
++}
++
++HRESULT WINAPI CDesktopFolder::AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut)
++{
++ WCHAR wszNewDir[MAX_PATH];
++ DWORD bRes;
++ HRESULT hres = E_FAIL;
++
++ TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName), ppidlOut);
++
++ wszNewDir[0] = 0;
++ if (sPathTarget)
++ lstrcpynW(wszNewDir, sPathTarget, MAX_PATH);
++ PathAppendW(wszNewDir, pwszName);
++ bRes = CreateDirectoryW (wszNewDir, NULL);
++ if (bRes)
++ {
++ SHChangeNotify (SHCNE_MKDIR, SHCNF_PATHW, wszNewDir, NULL);
++ hres = S_OK;
++ if (ppidlOut)
++ hres = _ILCreateFromPathW(wszNewDir, ppidlOut);
++ }
++
++ return hres;
++}
++
++HRESULT WINAPI CDesktopFolder::DeleteItems(UINT cidl, LPCITEMIDLIST *apidl)
++{
++ UINT i;
++ SHFILEOPSTRUCTW op;
++ WCHAR wszPath[MAX_PATH];
++ WCHAR wszCaption[50];
++ WCHAR *wszPathsList;
++ HRESULT ret;
++ WCHAR *wszCurrentPath;
++ UINT bRestoreWithDeskCpl = FALSE;
++ int res;
++
++ TRACE ("(%p)(%u %p)\n", this, cidl, apidl);
++ if (cidl==0) return S_OK;
++
++ for(i = 0; i < cidl; i++)
++ {
++ if (_ILIsMyComputer(apidl[i]))
++ bRestoreWithDeskCpl++;
++ else if (_ILIsNetHood(apidl[i]))
++ bRestoreWithDeskCpl++;
++ else if (_ILIsMyDocuments(apidl[i]))
++ bRestoreWithDeskCpl++;
++ }
++
++ if (bRestoreWithDeskCpl)
++ {
++ /* FIXME use FormatMessage
++ * use a similar message resource as in windows
++ */
++ LoadStringW(shell32_hInstance, IDS_DELETEMULTIPLE_TEXT, wszPath, sizeof(wszPath)/sizeof(WCHAR));
++ wszPath[(sizeof(wszPath)/sizeof(WCHAR))-1] = 0;
++
++ LoadStringW(shell32_hInstance, IDS_DELETEITEM_CAPTION, wszCaption, sizeof(wszCaption)/sizeof(WCHAR));
++ wszCaption[(sizeof(wszCaption)/sizeof(WCHAR))-1] = 0;
++
++ res = SHELL_ConfirmMsgBox(GetActiveWindow(), wszPath, wszCaption, NULL, cidl > 1);
++ if (res == IDD_YESTOALL || res == IDYES)
++ {
++ for(i = 0; i < cidl; i++)
++ {
++ if (_ILIsMyComputer(apidl[i]))
++ SetNamespaceExtensionVisibleStatus(L"{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0x1);
++ else if (_ILIsNetHood(apidl[i]))
++ SetNamespaceExtensionVisibleStatus(L"{208D2C60-3AEA-1069-A2D7-08002B30309D}", 0x1);
++ else if (_ILIsMyDocuments(apidl[i]))
++ SetNamespaceExtensionVisibleStatus(L"{450D8FBA-AD25-11D0-98A8-0800361B1103}", 0x1);
++ }
++ }
++ }
++ if (sPathTarget)
++ lstrcpynW(wszPath, sPathTarget, MAX_PATH);
++ else
++ wszPath[0] = '\0';
++
++ PathAddBackslashW(wszPath);
++ wszPathsList = build_paths_list(wszPath, cidl, apidl);
++
++ ZeroMemory(&op, sizeof(op));
++ op.hwnd = GetActiveWindow();
++ op.wFunc = FO_DELETE;
++ op.pFrom = wszPathsList;
++ op.fFlags = FOF_ALLOWUNDO;
++ if (SHFileOperationW(&op))
++ {
++ WARN("SHFileOperation failed\n");
++ ret = E_FAIL;
++ }
++ else
++ ret = S_OK;
++
++ /* we currently need to manually send the notifies */
++ wszCurrentPath = wszPathsList;
++ for (i = 0; i < cidl; i++)
++ {
++ LONG wEventId;
++
++ if (_ILIsFolder(apidl[i]))
++ wEventId = SHCNE_RMDIR;
++ else if (_ILIsValue(apidl[i]))
++ wEventId = SHCNE_DELETE;
++ else
++ continue;
++
++ /* check if file exists */
++ if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
++ {
++ LPITEMIDLIST pidl = ILCombine(pidlRoot, apidl[i]);
++ SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
++ SHFree(pidl);
++ }
++
++ wszCurrentPath += wcslen(wszCurrentPath)+1;
++ }
++ HeapFree(GetProcessHeap(), 0, wszPathsList);
++ return ret;
++}
++
++HRESULT WINAPI CDesktopFolder::CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl)
++{
++ CComPtr<IPersistFolder2> ppf2;
++ WCHAR szSrcPath[MAX_PATH];
++ WCHAR szTargetPath[MAX_PATH];
++ SHFILEOPSTRUCTW op;
++ LPITEMIDLIST pidl;
++ LPWSTR pszSrc, pszTarget, pszSrcList, pszTargetList, pszFileName;
++ int res, length;
++ STRRET strRet;
++
++ TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom, cidl, apidl);
++
++ pSFFrom->QueryInterface(IID_IPersistFolder2, (LPVOID *)&ppf2);
++ if (ppf2)
++ {
++ if (FAILED(ppf2->GetCurFolder(&pidl)))
++ return E_FAIL;
++
++ if (FAILED(pSFFrom->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strRet)))
++ {
++ SHFree (pidl);
++ return E_FAIL;
++ }
++
++ if (FAILED(StrRetToBufW(&strRet, pidl, szSrcPath, MAX_PATH)))
++ {
++ SHFree (pidl);
++ return E_FAIL;
++ }
++ SHFree (pidl);
++
++ pszSrc = PathAddBackslashW (szSrcPath);
++
++ wcscpy(szTargetPath, sPathTarget);
++ pszTarget = PathAddBackslashW (szTargetPath);
++
++ pszSrcList = build_paths_list(szSrcPath, cidl, apidl);
++ pszTargetList = build_paths_list(szTargetPath, cidl, apidl);
++
++ if (!pszSrcList || !pszTargetList)
++ {
++ if (pszSrcList)
++ HeapFree(GetProcessHeap(), 0, pszSrcList);
++
++ if (pszTargetList)
++ HeapFree(GetProcessHeap(), 0, pszTargetList);
++
++ SHFree (pidl);
++ return E_OUTOFMEMORY;
++ }
++ ZeroMemory(&op, sizeof(op));
++ if (!pszSrcList[0])
++ {
++ /* remove trailing backslash */
++ pszSrc--;
++ pszSrc[0] = L'\0';
++ op.pFrom = szSrcPath;
++ }
++ else
++ {
++ op.pFrom = pszSrcList;
++ }
++
++ if (!pszTargetList[0])
++ {
++ /* remove trailing backslash */
++ if (pszTarget - szTargetPath > 3)
++ {
++ pszTarget--;
++ pszTarget[0] = L'\0';
++ }
++ else
++ {
++ pszTarget[1] = L'\0';
++ }
++
++ op.pTo = szTargetPath;
++ }
++ else
++ {
++ op.pTo = pszTargetList;
++ }
++ op.hwnd = GetActiveWindow();
++ op.wFunc = FO_COPY;
++ op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
++
++ res = SHFileOperationW(&op);
++
++ if (res == DE_SAMEFILE)
++ {
++ length = wcslen(szTargetPath);
++
++
++ pszFileName = wcsrchr(pszSrcList, '\\');
++ pszFileName++;
++
++ if (LoadStringW(shell32_hInstance, IDS_COPY_OF, pszTarget, MAX_PATH - length))
++ {
++ wcscat(szTargetPath, L" ");
++ }
++
++ wcscat(szTargetPath, pszFileName);
++ op.pTo = szTargetPath;
++
++ res = SHFileOperationW(&op);
++ }
++
++
++ HeapFree(GetProcessHeap(), 0, pszSrcList);
++ HeapFree(GetProcessHeap(), 0, pszTargetList);
++
++ if (res)
++ return E_FAIL;
++ else
++ return S_OK;
++ }
++ return E_FAIL;
++}
--- /dev/null
--- /dev/null
++/*
++ * Virtual Workplace folder
++ *
++ * Copyright 1997 Marcus Meissner
++ * Copyright 1998, 1999, 2002 Juergen Schmied
++ * 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
++ */
++
++#include <precomp.h>
++
++WINE_DEFAULT_DEBUG_CHANNEL (shell);
++
++/*
++CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in
++the registry. The CRegFolder is aggregated by the CDrivesFolder.
++The CDrivesFolderEnum class should enumerate only drives on the system. Since the CRegFolder
++implementation of IShellFolder::EnumObjects enumerates the virtual items, the
++CDrivesFolderEnum is only responsible for returning the physical items.
++
++2. At least on my XP system, the drive pidls returned are of type PT_DRIVE1, not PT_DRIVE
++3. The parsing name returned for my computer is incorrect. It should be "My Computer"
++*/
++
++/***********************************************************************
++* IShellFolder implementation
++*/
++
++class CDrivesFolderEnum :
++ public IEnumIDListImpl
++{
++private:
++public:
++ CDrivesFolderEnum();
++ ~CDrivesFolderEnum();
++ HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
++ BOOL CreateMyCompEnumList(DWORD dwFlags);
++
++BEGIN_COM_MAP(CDrivesFolderEnum)
++ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
++END_COM_MAP()
++};
++
++/***********************************************************************
++* IShellFolder [MyComputer] implementation
++*/
++
++static const shvheader MyComputerSFHeader[] = {
++ {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
++ {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
++ {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
++ {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
++};
++
++#define MYCOMPUTERSHELLVIEWCOLUMNS 4
++
++CDrivesFolderEnum::CDrivesFolderEnum()
++{
++}
++
++CDrivesFolderEnum::~CDrivesFolderEnum()
++{
++}
++
++HRESULT WINAPI CDrivesFolderEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
++{
++ if (CreateMyCompEnumList(dwFlags) == FALSE)
++ return E_FAIL;
++ return S_OK;
++}
++
++/**************************************************************************
++ * CreateMyCompEnumList()
++ */
++static const WCHAR MyComputer_NameSpaceW[] = { 'S','O','F','T','W','A','R','E',
++ '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
++ 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
++ 'o','r','e','r','\\','M','y','C','o','m','p','u','t','e','r','\\','N','a','m',
++ 'e','s','p','a','c','e','\0' };
++
++BOOL CDrivesFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
++{
++ BOOL ret = TRUE;
++
++ TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
++
++ /* enumerate the folders */
++ if (dwFlags & SHCONTF_FOLDERS)
++ {
++ WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
++ DWORD dwDrivemap = GetLogicalDrives();
++ HKEY hkey;
++ UINT i;
++
++ while (ret && wszDriveName[0]<='Z')
++ {
++ if(dwDrivemap & 0x00000001L)
++ ret = AddToEnumList(_ILCreateDrive(wszDriveName));
++ wszDriveName[0]++;
++ dwDrivemap = dwDrivemap >> 1;
++ }
++
++ TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n", this);
++ for (i=0; i<2; i++)
++ {
++ if (ret && !RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
++ MyComputer_NameSpaceW, 0, KEY_READ, &hkey))
++ {
++ WCHAR iid[50];
++ int i=0;
++
++ while (ret)
++ {
++ DWORD size;
++ LONG r;
++
++ size = sizeof(iid) / sizeof(iid[0]);
++ r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
++ if (ERROR_SUCCESS == r)
++ {
++ /* FIXME: shell extensions, shouldn't the type be
++ * PT_SHELLEXT? */
++ LPITEMIDLIST pidl = _ILCreateGuidFromStrW(iid);
++ if (pidl != NULL)
++ ret = AddToEnumList(pidl);
++ i++;
++ }
++ else if (ERROR_NO_MORE_ITEMS == r)
++ break;
++ else
++ ret = FALSE;
++ }
++ RegCloseKey(hkey);
++ }
++ }
++ }
++ return ret;
++}
++
++CDrivesFolder::CDrivesFolder()
++{
++ pidlRoot = NULL;
++ sName = NULL;
++}
++
++CDrivesFolder::~CDrivesFolder()
++{
++ TRACE ("-- destroying IShellFolder(%p)\n", this);
++ SHFree(pidlRoot);
++}
++
++HRESULT WINAPI CDrivesFolder::FinalConstruct()
++{
++ DWORD dwSize;
++ WCHAR szName[MAX_PATH];
++
++ pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */
++ if (pidlRoot == NULL)
++ return E_OUTOFMEMORY;
++
++ dwSize = sizeof(szName);
++ if (RegGetValueW(HKEY_CURRENT_USER,
++ L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
++ NULL, RRF_RT_REG_SZ, NULL, szName, &dwSize) == ERROR_SUCCESS)
++ {
++ szName[MAX_PATH - 1] = 0;
++ sName = (LPWSTR)SHAlloc((wcslen(szName) + 1) * sizeof(WCHAR));
++ if (sName)
++ {
++ wcscpy(sName, szName);
++ }
++ TRACE("sName %s\n", debugstr_w(sName));
++ }
++ return S_OK;
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnParseDisplayName
++*/
++HRESULT WINAPI CDrivesFolder::ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
++ DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
++{
++ HRESULT hr = E_INVALIDARG;
++ LPCWSTR szNext = NULL;
++ WCHAR szElement[MAX_PATH];
++ LPITEMIDLIST pidlTemp = NULL;
++ CLSID clsid;
++
++ TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
++ hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
++ pchEaten, ppidl, pdwAttributes);
++
++ *ppidl = 0;
++ if (pchEaten)
++ *pchEaten = 0; /* strange but like the original */
++
++ /* handle CLSID paths */
++ if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
++ {
++ szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
++ TRACE ("-- element: %s\n", debugstr_w (szElement));
++ CLSIDFromString (szElement + 2, &clsid);
++ pidlTemp = _ILCreateGuid (PT_GUID, clsid);
++ }
++ /* do we have an absolute path name ? */
++ else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
++ lpszDisplayName[2] == (WCHAR) '\\')
++ {
++ szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
++ /* make drive letter uppercase to enable PIDL comparison */
++ szElement[0] = toupper(szElement[0]);
++ pidlTemp = _ILCreateDrive (szElement);
++ }
++
++ if (szNext && *szNext)
++ {
++ hr = SHELL32_ParseNextElement (this, hwndOwner, pbc, &pidlTemp,
++ (LPOLESTR) szNext, pchEaten, pdwAttributes);
++ }
++ else
++ {
++ if (pdwAttributes && *pdwAttributes)
++ SHELL32_GetItemAttributes (this,
++ pidlTemp, pdwAttributes);
++ hr = S_OK;
++ }
++
++ *ppidl = pidlTemp;
++
++ TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
++
++ return hr;
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnEnumObjects
++*/
++HRESULT WINAPI CDrivesFolder::EnumObjects (HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
++{
++ CComObject<CDrivesFolderEnum> *theEnumerator;
++ CComPtr<IEnumIDList> result;
++ HRESULT hResult;
++
++ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
++
++ if (ppEnumIDList == NULL)
++ return E_POINTER;
++
++ *ppEnumIDList = NULL;
++ ATLTRY (theEnumerator = new CComObject<CDrivesFolderEnum>);
++
++ if (theEnumerator == NULL)
++ return E_OUTOFMEMORY;
++
++ hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result);
++ if (FAILED (hResult))
++ {
++ delete theEnumerator;
++ return hResult;
++ }
++
++ hResult = theEnumerator->Initialize (hwndOwner, dwFlags);
++ if (FAILED (hResult))
++ return hResult;
++ *ppEnumIDList = result.Detach ();
++
++ TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
++
++ return S_OK;
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnBindToObject
++*/
++HRESULT WINAPI CDrivesFolder::BindToObject (LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++{
++ TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
++ pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
++
++ return SHELL32_BindToChild (pidlRoot, NULL, pidl, riid, ppvOut);
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnBindToStorage
++*/
++HRESULT WINAPI CDrivesFolder::BindToStorage (LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++{
++ FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
++ pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
++
++ *ppvOut = NULL;
++ return E_NOTIMPL;
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnCompareIDs
++*/
++
++HRESULT WINAPI CDrivesFolder::CompareIDs (LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++{
++ int nReturn;
++
++ TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
++ nReturn = SHELL32_CompareIDs (this, lParam, pidl1, pidl2);
++ TRACE ("-- %i\n", nReturn);
++ return nReturn;
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnCreateViewObject
++*/
++HRESULT WINAPI CDrivesFolder::CreateViewObject (HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
++{
++ LPSHELLVIEW pShellView;
++ HRESULT hr = E_INVALIDARG;
++
++ TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
++ hwndOwner, shdebugstr_guid (&riid), ppvOut);
++
++ if (!ppvOut)
++ return hr;
++
++ *ppvOut = NULL;
++
++ if (IsEqualIID (riid, IID_IDropTarget))
++ {
++ WARN ("IDropTarget not implemented\n");
++ hr = E_NOTIMPL;
++ }
++ else if (IsEqualIID (riid, IID_IContextMenu))
++ {
++ WARN ("IContextMenu not implemented\n");
++ hr = E_NOTIMPL;
++ }
++ else if (IsEqualIID (riid, IID_IShellView))
++ {
++ hr = IShellView_Constructor ((IShellFolder *)this, &pShellView);
++ if (pShellView)
++ {
++ hr = pShellView->QueryInterface(riid, ppvOut);
++ pShellView->Release();
++ }
++ }
++ TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
++ return hr;
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnGetAttributesOf
++*/
++HRESULT WINAPI CDrivesFolder::GetAttributesOf (UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
++{
++ HRESULT hr = S_OK;
++ static const DWORD dwComputerAttributes =
++ SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_CANCOPY |
++ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
++
++ TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
++ this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
++
++ if (!rgfInOut)
++ return E_INVALIDARG;
++ if (cidl && !apidl)
++ return E_INVALIDARG;
++
++ if (*rgfInOut == 0)
++ *rgfInOut = ~0;
++
++ if(cidl == 0) {
++ *rgfInOut &= dwComputerAttributes;
++ } else {
++ while (cidl > 0 && *apidl) {
++ pdump (*apidl);
++ SHELL32_GetItemAttributes (this, *apidl, rgfInOut);
++ apidl++;
++ cidl--;
++ }
++ }
++ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
++ *rgfInOut &= ~SFGAO_VALIDATE;
++
++ TRACE ("-- result=0x%08x\n", *rgfInOut);
++ return hr;
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnGetUIObjectOf
++*
++* PARAMETERS
++* hwndOwner [in] Parent window for any output
++* cidl [in] array size
++* apidl [in] simple pidl array
++* riid [in] Requested Interface
++* prgfInOut [ ] reserved
++* ppvObject [out] Resulting Interface
++*
++*/
++HRESULT WINAPI CDrivesFolder::GetUIObjectOf (HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
++ UINT * prgfInOut, LPVOID * ppvOut)
++{
++ LPITEMIDLIST pidl;
++ IUnknown *pObj = NULL;
++ HRESULT hr = E_INVALIDARG;
++
++ TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
++ hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
++
++ if (!ppvOut)
++ return hr;
++
++ *ppvOut = NULL;
++
++ if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
++ {
++ hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&pObj);
++ }
++ else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
++ {
++ hr = IDataObject_Constructor (hwndOwner,
++ pidlRoot, apidl, cidl, (IDataObject **)&pObj);
++ }
++ else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
++ {
++ pidl = ILCombine (pidlRoot, apidl[0]);
++ pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
++ SHFree (pidl);
++ hr = S_OK;
++ }
++ else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
++ {
++ pidl = ILCombine (pidlRoot, apidl[0]);
++ pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
++ SHFree (pidl);
++ hr = S_OK;
++ }
++ else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
++ {
++ hr = this->QueryInterface(IID_IDropTarget,
++ (LPVOID *) &pObj);
++ }
++ else if ((IsEqualIID(riid,IID_IShellLinkW) ||
++ IsEqualIID(riid,IID_IShellLinkA)) && (cidl == 1))
++ {
++ pidl = ILCombine (pidlRoot, apidl[0]);
++ hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
++ SHFree (pidl);
++ }
++ else
++ hr = E_NOINTERFACE;
++
++ if (SUCCEEDED(hr) && !pObj)
++ hr = E_OUTOFMEMORY;
++
++ *ppvOut = pObj;
++ TRACE ("(%p)->hr=0x%08x\n", this, hr);
++ return hr;
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnGetDisplayNameOf
++*/
++HRESULT WINAPI CDrivesFolder::GetDisplayNameOf (LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++{
++ LPWSTR pszPath;
++ HRESULT hr = S_OK;
++
++ TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
++ pdump (pidl);
++
++ if (!strRet)
++ return E_INVALIDARG;
++
++ pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
++ if (!pszPath)
++ return E_OUTOFMEMORY;
++
++ pszPath[0] = 0;
++
++ if (!pidl->mkid.cb)
++ {
++ /* parsing name like ::{...} */
++ pszPath[0] = ':';
++ pszPath[1] = ':';
++ SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
++ }
++ else if (_ILIsPidlSimple(pidl))
++ {
++ /* take names of special folders only if its only this folder */
++ if (_ILIsSpecialFolder(pidl))
++ {
++ GUID const *clsid;
++
++ clsid = _ILGetGUIDPointer (pidl);
++ if (clsid)
++ {
++ if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
++ {
++ static const WCHAR clsidW[] =
++ { 'C','L','S','I','D','\\',0 };
++ static const WCHAR shellfolderW[] =
++ { '\\','s','h','e','l','l','f','o','l','d','e','r',0 };
++ static const WCHAR wantsForParsingW[] =
++ { 'W','a','n','t','s','F','o','r','P','a','r','s','i','n',
++ 'g',0 };
++ int bWantsForParsing = FALSE;
++ WCHAR szRegPath[100];
++ LONG r;
++
++ /*
++ * We can only get a filesystem path from a shellfolder
++ * if the value WantsFORPARSING exists in
++ * CLSID\\{...}\\shellfolder
++ * exception: the MyComputer folder has this keys not
++ * but like any filesystem backed
++ * folder it needs these behaviour
++ *
++ * Get the "WantsFORPARSING" flag from the registry
++ */
++
++ wcscpy (szRegPath, clsidW);
++ SHELL32_GUIDToStringW (*clsid, &szRegPath[6]);
++ wcscat (szRegPath, shellfolderW);
++ r = SHGetValueW (HKEY_CLASSES_ROOT, szRegPath,
++ wantsForParsingW, NULL, NULL, NULL);
++ if (r == ERROR_SUCCESS)
++ bWantsForParsing = TRUE;
++
++ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
++ bWantsForParsing)
++ {
++ /*
++ * We need the filesystem path to the destination folder
++ * Only the folder itself can know it
++ */
++ hr = SHELL32_GetDisplayNameOfChild (this, pidl,
++ dwFlags, pszPath, MAX_PATH);
++ }
++ else
++ {
++ LPWSTR p = pszPath;
++
++ /* parsing name like ::{...} */
++ p[0] = ':';
++ p[1] = ':';
++ p += 2;
++ p += SHELL32_GUIDToStringW(CLSID_MyComputer, p);
++
++ /* \:: */
++ p[0] = '\\';
++ p[1] = ':';
++ p[2] = ':';
++ p += 3;
++ SHELL32_GUIDToStringW(*clsid, p);
++ }
++ }
++ else
++ {
++ /* user friendly name */
++
++ if (_ILIsMyComputer(pidl) && sName)
++ wcscpy(pszPath, sName);
++ else
++ HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
++
++ TRACE("pszPath %s\n", debugstr_w(pszPath));
++ }
++ }
++ else
++ {
++ /* append my own path */
++ _ILSimpleGetTextW (pidl, pszPath, MAX_PATH);
++ }
++ }
++ else if (_ILIsDrive(pidl))
++ {
++
++ _ILSimpleGetTextW (pidl, pszPath, MAX_PATH); /* append my own path */
++ /* long view "lw_name (C:)" */
++ if (!(dwFlags & SHGDN_FORPARSING))
++ {
++ WCHAR wszDrive[18] = {0};
++ DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
++ static const WCHAR wszOpenBracket[] = {' ','(',0};
++ static const WCHAR wszCloseBracket[] = {')',0};
++
++ lstrcpynW(wszDrive, pszPath, 4);
++ pszPath[0] = L'\0';
++ GetVolumeInformationW (wszDrive, pszPath,
++ MAX_PATH - 7,
++ &dwVolumeSerialNumber,
++ &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
++ pszPath[MAX_PATH-1] = L'\0';
++ if (!wcslen(pszPath))
++ {
++ UINT DriveType, ResourceId;
++ DriveType = GetDriveTypeW(wszDrive);
++ switch(DriveType)
++ {
++ case DRIVE_FIXED:
++ ResourceId = IDS_DRIVE_FIXED;
++ break;
++ case DRIVE_REMOTE:
++ ResourceId = IDS_DRIVE_NETWORK;
++ break;
++ case DRIVE_CDROM:
++ ResourceId = IDS_DRIVE_CDROM;
++ break;
++ default:
++ ResourceId = 0;
++ }
++ if (ResourceId)
++ {
++ dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
++ if (dwFileSystemFlags > MAX_PATH - 7)
++ pszPath[MAX_PATH-7] = L'\0';
++ }
++ }
++ wcscat (pszPath, wszOpenBracket);
++ wszDrive[2] = L'\0';
++ wcscat (pszPath, wszDrive);
++ wcscat (pszPath, wszCloseBracket);
++ }
++ }
++ else
++ {
++ /* Neither a shell namespace extension nor a drive letter. */
++ ERR("Wrong pidl type\n");
++ CoTaskMemFree(pszPath);
++ return E_INVALIDARG;
++ }
++ }
++ else
++ {
++ /* Complex pidl. Let the child folder do the work */
++ hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
++ }
++
++ if (SUCCEEDED (hr))
++ {
++ strRet->uType = STRRET_WSTR;
++ strRet->pOleStr = pszPath;
++ }
++ else
++ CoTaskMemFree(pszPath);
++
++ TRACE ("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
++ return hr;
++}
++
++/**************************************************************************
++* ISF_MyComputer_fnSetNameOf
++* Changes the name of a file object or subfolder, possibly changing its item
++* identifier in the process.
++*
++* PARAMETERS
++* hwndOwner [in] Owner window for output
++* pidl [in] simple pidl of item to change
++* lpszName [in] the items new display name
++* dwFlags [in] SHGNO formatting flags
++* ppidlOut [out] simple pidl returned
++*/
++HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
++ LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
++{
++ LPWSTR sName;
++ HKEY hKey;
++ UINT length;
++ WCHAR szName[30];
++
++ TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
++ hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
++
++ if (_ILIsDrive(pidl))
++ {
++ if (_ILSimpleGetTextW(pidl, szName, sizeof(szName)/sizeof(WCHAR)))
++ {
++ SetVolumeLabelW(szName, lpName);
++ }
++ if (pPidlOut)
++ *pPidlOut = _ILCreateDrive(szName);
++ return S_OK;
++ }
++
++
++ if (pPidlOut != NULL)
++ {
++ *pPidlOut = _ILCreateMyComputer();
++ }
++
++ length = (wcslen(lpName) + 1) * sizeof(WCHAR);
++ sName = (LPWSTR)SHAlloc(length);
++
++ if (!sName)
++ {
++ return E_OUTOFMEMORY;
++ }
++
++ if (RegOpenKeyExW(HKEY_CURRENT_USER,
++ L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
++ 0,
++ KEY_WRITE,
++ &hKey) != ERROR_SUCCESS)
++ {
++ WARN("Error: failed to open registry key\n");
++ }
++ else
++ {
++ RegSetValueExW(hKey, NULL, 0, REG_SZ, (const LPBYTE)lpName, length);
++ RegCloseKey(hKey);
++ }
++
++ wcscpy(sName, lpName);
++ SHFree(sName);
++ sName = sName;
++ TRACE("result %s\n", debugstr_w(sName));
++ return S_OK;
++}
++
++HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
++{
++ FIXME ("(%p)\n", this);
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
++{
++ FIXME ("(%p)\n", this);
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
++{
++ TRACE ("(%p)\n", this);
++
++ if (pSort)
++ *pSort = 0;
++ if (pDisplay)
++ *pDisplay = 0;
++ return S_OK;
++}
++
++HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
++{
++ TRACE ("(%p)\n", this);
++
++ if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
++ return E_INVALIDARG;
++ *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
++ return S_OK;
++}
++
++HRESULT WINAPI CDrivesFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
++{
++ FIXME ("(%p)\n", this);
++ return E_NOTIMPL;
++}
++
++/* FIXME: drive size >4GB is rolling over */
++HRESULT WINAPI CDrivesFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS * psd)
++{
++ HRESULT hr;
++
++ TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
++
++ if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
++ return E_INVALIDARG;
++
++ if (!pidl)
++ {
++ psd->fmt = MyComputerSFHeader[iColumn].fmt;
++ psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
++ psd->str.uType = STRRET_CSTR;
++ LoadStringA (shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
++ psd->str.cStr, MAX_PATH);
++ return S_OK;
++ }
++ else
++ {
++ char szPath[MAX_PATH];
++ ULARGE_INTEGER ulBytes;
++
++ psd->str.cStr[0] = 0x00;
++ psd->str.uType = STRRET_CSTR;
++ switch (iColumn)
++ {
++ case 0: /* name */
++ hr = GetDisplayNameOf(pidl,
++ SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
++ break;
++ case 1: /* type */
++ _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
++ break;
++ case 2: /* total size */
++ if (_ILIsDrive (pidl))
++ {
++ _ILSimpleGetText (pidl, szPath, MAX_PATH);
++ GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
++ StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
++ }
++ break;
++ case 3: /* free size */
++ if (_ILIsDrive (pidl))
++ {
++ _ILSimpleGetText (pidl, szPath, MAX_PATH);
++ GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
++ StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
++ }
++ break;
++ }
++ hr = S_OK;
++ }
++
++ return hr;
++}
++
++HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
++{
++ FIXME ("(%p)\n", this);
++ return E_NOTIMPL;
++}
++
++/************************************************************************
++ * IMCFldr_PersistFolder2_GetClassID
++ */
++HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
++{
++ TRACE ("(%p)\n", this);
++
++ if (!lpClassId)
++ return E_POINTER;
++ *lpClassId = CLSID_MyComputer;
++
++ return S_OK;
++}
++
++/************************************************************************
++ * IMCFldr_PersistFolder2_Initialize
++ *
++ * NOTES: it makes no sense to change the pidl
++ */
++HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
++{
++ TRACE ("(%p)->(%p)\n", this, pidl);
++
++ if (pidlRoot)
++ SHFree((LPVOID)pidlRoot);
++
++ pidlRoot = ILClone(pidl);
++ return S_OK;
++}
++
++/**************************************************************************
++ * IPersistFolder2_fnGetCurFolder
++ */
++HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
++{
++ TRACE ("(%p)->(%p)\n", this, pidl);
++
++ if (!pidl)
++ return E_POINTER;
++ *pidl = ILClone (pidlRoot);
++ return S_OK;
++}
--- /dev/null
--- /dev/null
++/*
++ * UNIXFS - Shell namespace extension for the unix filesystem
++ *
++ * Copyright (C) 2005 Michael Jung
++ *
++ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/* Placeholder in ReactOS, we don't need this */
--- /dev/null
--- /dev/null
++/*
++ * 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>
++#include <windef.h>
++
++WINE_DEFAULT_DEBUG_CHANNEL(exec);
++
++static const WCHAR wszOpen[] = {'o','p','e','n',0};
++static const WCHAR wszExe[] = {'.','e','x','e',0};
++static const WCHAR wszILPtr[] = {':','%','p',0};
++static const WCHAR wszShell[] = {'\\','s','h','e','l','l','\\',0};
++static const WCHAR wszFolder[] = {'F','o','l','d','e','r',0};
++static const WCHAR wszEmpty[] = {0};
++
++#define SEE_MASK_CLASSALL (SEE_MASK_CLASSNAME | SEE_MASK_CLASSKEY)
++
++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, wszILPtr, 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++;
++ }
++ }
++
++ *res = '\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;
++
++ if (psei->fMask & SEE_MASK_NO_CONSOLE)
++ dwCreationFlags |= CREATE_NEW_CONSOLE;
++
++ 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)
++ {
++ TRACE("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[] = {'P','A','T','H','=',0};
++ 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)
++{
++ static const WCHAR wszKeyAppPaths[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',
++ '\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','A','p','p',' ','P','a','t','h','s','\\',0};
++ static const WCHAR wPath[] = {'P','a','t','h',0};
++ HKEY hkApp = 0;
++ WCHAR buffer[1024];
++ LONG len;
++ LONG res;
++ BOOL found = FALSE;
++
++ if (env) *env = NULL;
++ wcscpy(buffer, wszKeyAppPaths);
++ 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, wPath, NULL, NULL, (LPBYTE)buffer, &count) && buffer[0])
++ *env = SHELL_BuildEnvW( buffer );
++ }
++
++end:
++ if (hkApp) RegCloseKey(hkApp);
++ return found;
++}
++
++static UINT SHELL_FindExecutableByOperation(LPCWSTR lpOperation, LPWSTR key, LPWSTR filetype, LPWSTR command, LONG commandlen)
++{
++ static const WCHAR wCommand[] = {'\\','c','o','m','m','a','n','d',0};
++ HKEY hkeyClass;
++ WCHAR verb[MAX_PATH];
++
++ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, filetype, 0, 0x02000000, &hkeyClass))
++ return SE_ERR_NOASSOC;
++ if (!HCR_GetDefaultVerbW(hkeyClass, lpOperation, verb, sizeof(verb)/sizeof(verb[0])))
++ return SE_ERR_NOASSOC;
++ RegCloseKey(hkeyClass);
++
++ /* Looking for ...buffer\shell\<verb>\command */
++ wcscat(filetype, wszShell);
++ wcscat(filetype, verb);
++ wcscat(filetype, wCommand);
++
++ if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, command,
++ &commandlen) == ERROR_SUCCESS)
++ {
++ commandlen /= sizeof(WCHAR);
++ if (key) wcscpy(key, filetype);
++#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 */
++ tmp = strstrW(filetype, wCommand);
++ tmp[0] = '\0';
++ wcscat(filetype, wDdeexec);
++ if (RegQueryValueW(HKEY_CLASSES_ROOT, filetype, param,
++ ¶mlen) == 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
++ * lpOperation 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)
++ */
++static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpOperation,
++ LPWSTR lpResult, DWORD resultLen, LPWSTR key, WCHAR **env,LPITEMIDLIST pidl, LPCWSTR args)
++{
++ static const WCHAR wWindows[] = {'w','i','n','d','o','w','s',0};
++ static const WCHAR wPrograms[] = {'p','r','o','g','r','a','m','s',0};
++ static const WCHAR wExtensions[] = {'e','x','e',' ','p','i','f',' ','b','a','t',' ','c','m','d',' ','c','o','m',0};
++ WCHAR *extension = NULL; /* pointer to file extension */
++ WCHAR filetype[256]; /* registry name for this filetype */
++ LONG filetypelen = sizeof(filetype); /* 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;
++ /* Hey, isn't this value ignored? Why make this call? Shouldn't we return here? --dank*/
++ }
++
++ attribs = GetFileAttributesW(lpFile);
++ if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY))
++ {
++ wcscpy(filetype, wszFolder);
++ filetypelen = 6; /* strlen("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 '.') */
++ /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\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(wWindows, wPrograms, wExtensions, 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 */
++ if (RegQueryValueW(HKEY_CLASSES_ROOT, extension, filetype,
++ &filetypelen) == ERROR_SUCCESS)
++ {
++ filetypelen /= sizeof(WCHAR);
++ if (filetypelen == sizeof(filetype)/sizeof(WCHAR))
++ filetypelen--;
++
++ filetype[filetypelen] = '\0';
++ TRACE("File type: %s\n", debugstr_w(filetype));
++ }
++ else
++ {
++ *filetype = '\0';
++ filetypelen = 0;
++ }
++ }
++
++ if (*filetype)
++ {
++ /* pass the operation string to SHELL_FindExecutableByOperation() */
++ filetype[filetypelen] = '\0';
++ retval = SHELL_FindExecutableByOperation(lpOperation, key, filetype, 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 */
++ {
++ static const WCHAR wExtensions[] = {'e','x','t','e','n','s','i','o','n','s',0};
++
++ /* Toss the leading dot */
++ extension++;
++ if (GetProfileStringW(wExtensions, extension, wszEmpty, 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)
++{
++ static const WCHAR wApplication[] = {'\\','a','p','p','l','i','c','a','t','i','o','n',0};
++ static const WCHAR wTopic[] = {'\\','t','o','p','i','c',0};
++ WCHAR regkey[256];
++ WCHAR * endkey = regkey + wcslen(key);
++ WCHAR app[256], topic[256], ifexec[256], res[256];
++ LONG applen, topiclen, ifexeclen;
++ WCHAR * exec;
++ DWORD ddeInst = 0;
++ DWORD tid;
++ DWORD resultLen;
++ HSZ hszApp, hszTopic;
++ HCONV hConv;
++ HDDEDATA hDdeData;
++ unsigned ret = SE_ERR_NOASSOC;
++ BOOL unicode = !(GetVersion() & 0x80000000);
++
++ wcscpy(regkey, key);
++ 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[] = { '.','s','o',0 };
++ 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 == '"')
++ {
++ wcscpy(command, start+1);
++ if ((ptr = wcschr(command, '"')))
++ *ptr = 0;
++ ret = SearchPathW(NULL, command, wszExe, sizeof(fullpath)/sizeof(WCHAR), fullpath, &ptr);
++ }
++ else
++ {
++ LPWSTR p,space;
++ for (p=(LPWSTR)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;
++ }
++ 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;
++ }
++
++ wcscpy(endkey, wTopic);
++ topiclen = sizeof(topic);
++ if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, topic, &topiclen) != ERROR_SUCCESS)
++ {
++ static const WCHAR wSystem[] = {'S','y','s','t','e','m',0};
++ wcscpy(topic, wSystem);
++ }
++
++ 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)
++ {
++ static const WCHAR wIfexec[] = {'\\','i','f','e','x','e','c',0};
++ 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 */
++ }
++ strcpyW(endkey, wIfexec);
++ ifexeclen = sizeof(ifexec);
++ if (RegQueryValueW(HKEY_CLASSES_ROOT, regkey, ifexec, &ifexeclen) == ERROR_SUCCESS)
++ {
++ exec = ifexec;
++ }
++ }
++
++ 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");
++ 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;
++
++ 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)
++{
++ static const WCHAR wCommand[] = {'c','o','m','m','a','n','d',0};
++ static const WCHAR wDdeexec[] = {'d','d','e','e','x','e','c',0};
++ 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, wCommand));
++ assert(tmp);
++ wcscpy(tmp, wDdeexec);
++
++ 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_IShellFolder, (LPVOID*)&shf, &pidllast );
++ if ( FAILED( r ) )
++ goto end;
++
++ shf->GetUIObjectOf(NULL, 1, &pidllast,
++ IID_IDataObject, NULL, (LPVOID*) &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_IContextMenu, (LPVOID*) &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;
++ ici.fMask = CMIC_MASK_UNICODE | (sei->fMask & (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_IShellExtInit, (LPVOID*)&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_IObjectWithSite, (LPVOID*) &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 )
++{
++ static const WCHAR szcm[] = { 's','h','e','l','l','e','x','\\',
++ 'C','o','n','t','e','x','t','M','e','n','u','H','a','n','d','l','e','r','s',0 };
++ 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, szcm, &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_execute_class( LPCWSTR wszApplicationName, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc )
++{
++ static const WCHAR wSpace[] = {' ',0};
++ WCHAR execCmd[1024], wcmd[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;
++
++ 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, wSpace);
++ 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);
++}
++
++static BOOL SHELL_translate_idlist( LPSHELLEXECUTEINFOW sei, LPWSTR wszParameters, DWORD parametersLen, LPWSTR wszApplicationName, DWORD dwApplicationNameLen )
++{
++ static const WCHAR wExplorer[] = {'e','x','p','l','o','r','e','r','.','e','x','e',0};
++ WCHAR buffer[MAX_PATH];
++ BOOL appKnownSingular = FALSE;
++
++ /* last chance to translate IDList: now also allow CLSID paths */
++ if (SUCCEEDED(SHELL_GetPathFromIDListForExecuteW((LPCITEMIDLIST)sei->lpIDList, buffer, sizeof(buffer)))) {
++ 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, wszFolder,
++ 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;
++}
++
++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 const WCHAR wQuote[] = {'"',0};
++ static const WCHAR wSpace[] = {' ',0};
++ 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, wQuote);
++ strcatW(wszQuotedCmd, wcmd);
++ strcatW(wszQuotedCmd, wQuote);
++ if (wszParameters[0])
++ {
++ strcatW(wszQuotedCmd, wSpace);
++ strcatW(wszQuotedCmd, wszParameters);
++ }
++
++ TRACE("%s/%s => %s/%s\n", debugstr_w(wszApplicationName), debugstr_w(psei->lpVerb), debugstr_w(wszQuotedCmd), debugstr_w(lpstrProtocol));
++
++ if (*lpstrProtocol)
++ retval = execute_from_key(lpstrProtocol, wszApplicationName, env, psei->lpParameters, wcmd, execfunc, psei, psei_out);
++ else
++ retval = execfunc(wszQuotedCmd, env, FALSE, psei, psei_out);
++ HeapFree(GetProcessHeap(), 0, wszQuotedCmd);
++ return retval;
++}
++
++static UINT_PTR SHELL_execute_url( LPCWSTR lpFile, LPCWSTR wFile, LPCWSTR wcmd, LPSHELLEXECUTEINFOW psei, LPSHELLEXECUTEINFOW psei_out, SHELL_ExecuteW32 execfunc )
++{
++ static const WCHAR wShell[] = {'\\','s','h','e','l','l','\\',0};
++ static const WCHAR wCommand[] = {'\\','c','o','m','m','a','n','d',0};
++ 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));
++ /* Looking for ...protocol\shell\lpOperation\command */
++ len = iSize + lstrlenW(wShell) + lstrlenW(wCommand) + 1;
++ if (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);
++ strcatW(lpstrProtocol, psei->lpVerb? psei->lpVerb: wszOpen);
++ strcatW(lpstrProtocol, wCommand);
++
++ /* Remove File Protocol from lpFile */
++ /* In the case file://path/file */
++ if (!strncmpiW(lpFile, wFile, iSize))
++ {
++ lpFile += iSize;
++ while (*lpFile == ':') lpFile++;
++ }
++ retval = execute_from_key(lpstrProtocol, lpFile, NULL, psei->lpParameters,
++ wcmd, execfunc, psei, psei_out);
++ HeapFree(GetProcessHeap(), 0, lpstrProtocol);
++ return retval;
++}
++
++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]
++ */
++BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc )
++{
++ static const WCHAR wSpace[] = {' ',0};
++ static const WCHAR wWww[] = {'w','w','w',0};
++ static const WCHAR wFile[] = {'f','i','l','e',0};
++ static const WCHAR wHttp[] = {'h','t','t','p',':','/','/',0};
++ 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;
++ WCHAR lpstrProtocol[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] == '\"')
++ wszApplicationName[l-1] = '\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 = '\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 = '\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_IShellExecuteHookW, (LPVOID*)&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 );
++ }
++
++ /* expand environment strings */
++ len = ExpandEnvironmentStringsW(sei_tmp.lpFile, NULL, 0);
++ if (len>0)
++ {
++ LPWSTR buf;
++ 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.lpParameters)
++ {
++ len = ExpandEnvironmentStringsW(sei_tmp.lpParameters, NULL, 0);
++ if (len > 0)
++ {
++ LPWSTR buf;
++ 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;
++ }
++ }
++
++ 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] == '"')
++ {
++ LPWSTR src = wszApplicationName/*sei_tmp.lpFile*/ + 1;
++ LPWSTR dst = wfileName;
++ LPWSTR end;
++
++ /* copy the unquoted executable path to 'wfileName' */
++ while(*src && *src!='"')
++ *dst++ = *src++;
++
++ *dst = '\0';
++
++ if (*src == '"')
++ {
++ 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 = '\0';
++ }
++ 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, ' '))); 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 = '\0';
++
++ break;
++ }
++ }
++
++ lstrcpynW(wfileName, sei_tmp.lpFile,sizeof(wfileName)/sizeof(WCHAR));
++ }
++ }
++ else
++ lstrcpynW(wfileName, sei_tmp.lpFile,sizeof(wfileName)/sizeof(WCHAR));
++
++ lpFile = wfileName;
++
++ wcmd = wcmdBuffer;
++ len = lstrlenW(wszApplicationName) + 1;
++ if (sei_tmp.lpParameters[0])
++ len += 1 + lstrlenW(wszParameters);
++ if (len > wcmdLen)
++ {
++ wcmd = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
++ wcmdLen = len;
++ }
++ strcpyW(wcmd, wszApplicationName);
++ if (sei_tmp.lpParameters[0])
++ {
++ strcatW(wcmd, wSpace);
++ 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] = '\0';
++ retval = SHELL_FindExecutable(sei_tmp.lpDirectory, lpFile, sei_tmp.lpVerb, wcmd, wcmdLen, lpstrProtocol, &env, (LPITEMIDLIST)sei_tmp.lpIDList, sei_tmp.lpParameters);
++ if (retval > 32) /* Found */
++ {
++ retval = SHELL_quote_and_execute( wcmd, wszParameters, lpstrProtocol,
++ wszApplicationName, env, &sei_tmp,
++ sei, execfunc );
++ HeapFree( GetProcessHeap(), 0, env );
++ }
++ else if (PathIsDirectoryW(lpFile))
++ {
++ static const WCHAR wExplorer[] = {'e','x','p','l','o','r','e','r',0};
++ static const WCHAR wQuote[] = {'"',0};
++ WCHAR wExec[MAX_PATH];
++ WCHAR * lpQuotedFile = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * (strlenW(lpFile) + 3) );
++
++ if (lpQuotedFile)
++ {
++ retval = SHELL_FindExecutable( sei_tmp.lpDirectory, wExplorer,
++ wszOpen, wExec, MAX_PATH,
++ NULL, &env, NULL, NULL );
++ if (retval > 32)
++ {
++ strcpyW(lpQuotedFile, wQuote);
++ strcatW(lpQuotedFile, lpFile);
++ strcatW(lpQuotedFile, wQuote);
++ retval = SHELL_quote_and_execute( wExec, lpQuotedFile,
++ lpstrProtocol,
++ 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 */
++ {
++ retval = SHELL_execute_url( lpFile, wFile, wcmd, &sei_tmp, sei, execfunc );
++ }
++ /* Check if file specified is in the form www.??????.*** */
++ else if (!strncmpiW(lpFile, wWww, 3))
++ {
++ /* if so, append lpFile http:// and call ShellExecute */
++ WCHAR lpstrTmpFile[256];
++ strcpyW(lpstrTmpFile, wHttp);
++ 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]
++ */
++HINSTANCE WINAPI ShellExecuteA(HWND hWnd, LPCSTR lpOperation,LPCSTR lpFile,
++ LPCSTR lpParameters,LPCSTR lpDirectory, INT iShowCmd)
++{
++ SHELLEXECUTEINFOA sei;
++
++ TRACE("%p,%s,%s,%s,%s,%d\n",
++ hWnd, debugstr_a(lpOperation), debugstr_a(lpFile),
++ debugstr_a(lpParameters), debugstr_a(lpDirectory), iShowCmd);
++
++ sei.cbSize = sizeof(sei);
++ sei.fMask = SEE_MASK_FLAG_NO_UI;
++ sei.hwnd = hWnd;
++ sei.lpVerb = lpOperation;
++ 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 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 ShellExecuteExW (LPSHELLEXECUTEINFOW sei)
++{
++ return SHELL_execute( sei, SHELL_ExecuteW );
++}
++
++/*************************************************************************
++ * ShellExecuteW [SHELL32.294]
++ * from shellapi.h
++ * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpOperation,
++ * LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);
++ */
++HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, 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;
++ sei.lpVerb = lpOperation;
++ 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.
++ */
++EXTERN_C HINSTANCE WINAPI WOWShellExecute(HWND hWnd, LPCSTR lpOperation,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 = lpOperation ? __SHCloneStrAtoW(&wVerb, lpOperation) : 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);
++}
--- /dev/null
--- /dev/null
++/*
++ * SHFileOperation
++ *
++ * Copyright 2000 Juergen Schmied
++ * Copyright 2002 Andriy Palamarchuk
++ * Copyright 2004 Dietrich Teickner (from Odin)
++ * Copyright 2004 Rolf Kalbermatter
++ *
++ * 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 NO_SHLWAPI_STREAM
++#include <precomp.h>
++
++WINE_DEFAULT_DEBUG_CHANNEL(shell);
++
++#define IsAttrib(x, y) ((INVALID_FILE_ATTRIBUTES != (x)) && ((x) & (y)))
++#define IsAttribFile(x) (!((x) & FILE_ATTRIBUTE_DIRECTORY))
++#define IsAttribDir(x) IsAttrib(x, FILE_ATTRIBUTE_DIRECTORY)
++#define IsDotDir(x) ((x[0] == '.') && ((x[1] == 0) || ((x[1] == '.') && (x[2] == 0))))
++
++#define FO_MASK 0xF
++#define WM_FILE (WM_USER + 1)
++#define TIMER_ID (100)
++
++static const WCHAR wWildcardFile[] = {'*',0};
++static const WCHAR wWildcardChars[] = {'*','?',0};
++
++static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec);
++static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path);
++static DWORD SHNotifyDeleteFileW(LPCWSTR path);
++static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest);
++static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists);
++static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly);
++
++typedef struct
++{
++ SHFILEOPSTRUCTW *req;
++ DWORD dwYesToAllMask;
++ BOOL bManyItems;
++ BOOL bCancelled;
++} FILE_OPERATION;
++
++#define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026
++
++typedef struct
++{
++ DWORD attributes;
++ LPWSTR szDirectory;
++ LPWSTR szFilename;
++ LPWSTR szFullPath;
++ BOOL bFromWildcard;
++ BOOL bFromRelative;
++ BOOL bExists;
++} FILE_ENTRY;
++
++typedef struct
++{
++ FILE_ENTRY *feFiles;
++ DWORD num_alloc;
++ DWORD dwNumFiles;
++ BOOL bAnyFromWildcard;
++ BOOL bAnyDirectories;
++ BOOL bAnyDontExist;
++} FILE_LIST;
++
++typedef struct
++{
++ FILE_LIST * from;
++ FILE_LIST * to;
++ FILE_OPERATION * op;
++ DWORD Index;
++ HWND hDlgCtrl;
++ HWND hwndDlg;
++}FILE_OPERATION_CONTEXT;
++
++
++/* Confirm dialogs with an optional "Yes To All" as used in file operations confirmations
++ */
++static const WCHAR CONFIRM_MSG_PROP[] = {'W','I','N','E','_','C','O','N','F','I','R','M',0};
++
++struct confirm_msg_info
++{
++ LPWSTR lpszText;
++ LPWSTR lpszCaption;
++ HICON hIcon;
++ BOOL bYesToAll;
++};
++
++/* as some buttons may be hidden and the dialog height may change we may need
++ * to move the controls */
++static void confirm_msg_move_button(HWND hDlg, INT iId, INT *xPos, INT yOffset, BOOL bShow)
++{
++ HWND hButton = GetDlgItem(hDlg, iId);
++ RECT r;
++
++ if (bShow)
++ {
++ POINT pt;
++ int width;
++
++ GetWindowRect(hButton, &r);
++ width = r.right - r.left;
++ pt.x = r.left;
++ pt.y = r.top;
++ ScreenToClient(hDlg, &pt);
++ MoveWindow(hButton, *xPos - width, pt.y - yOffset, width, r.bottom - r.top, FALSE);
++ *xPos -= width + 5;
++ }
++ else
++ ShowWindow(hButton, SW_HIDE);
++}
++
++/* Note: we paint the text manually and don't use the static control to make
++ * sure the text has the same height as the one computed in WM_INITDIALOG
++ */
++static INT_PTR ConfirmMsgBox_Paint(HWND hDlg)
++{
++ PAINTSTRUCT ps;
++ HFONT hOldFont;
++ RECT r;
++ HDC hdc;
++
++ BeginPaint(hDlg, &ps);
++ hdc = ps.hdc;
++
++ GetClientRect(GetDlgItem(hDlg, IDD_MESSAGE), &r);
++ /* this will remap the rect to dialog coords */
++ MapWindowPoints(GetDlgItem(hDlg, IDD_MESSAGE), hDlg, (LPPOINT)&r, 2);
++ hOldFont = (HFONT)SelectObject(hdc, (HFONT)SendDlgItemMessageW(hDlg, IDD_MESSAGE, WM_GETFONT, 0, 0));
++ DrawTextW(hdc, (LPWSTR)GetPropW(hDlg, CONFIRM_MSG_PROP), -1, &r, DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_WORDBREAK);
++ SelectObject(hdc, hOldFont);
++ EndPaint(hDlg, &ps);
++
++ return TRUE;
++}
++
++static INT_PTR ConfirmMsgBox_Init(HWND hDlg, LPARAM lParam)
++{
++ struct confirm_msg_info *info = (struct confirm_msg_info *)lParam;
++ INT xPos, yOffset;
++ int width, height;
++ HFONT hOldFont;
++ HDC hdc;
++ RECT r;
++
++ SetWindowTextW(hDlg, info->lpszCaption);
++ ShowWindow(GetDlgItem(hDlg, IDD_MESSAGE), SW_HIDE);
++ SetPropW(hDlg, CONFIRM_MSG_PROP, info->lpszText);
++ SendDlgItemMessageW(hDlg, IDD_ICON, STM_SETICON, (WPARAM)info->hIcon, 0);
++
++ /* compute the text height and resize the dialog */
++ GetClientRect(GetDlgItem(hDlg, IDD_MESSAGE), &r);
++ hdc = GetDC(hDlg);
++ yOffset = r.bottom;
++ hOldFont = (HFONT)SelectObject(hdc, (HFONT)SendDlgItemMessageW(hDlg, IDD_MESSAGE, WM_GETFONT, 0, 0));
++ DrawTextW(hdc, info->lpszText, -1, &r, DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_WORDBREAK | DT_CALCRECT);
++ SelectObject(hdc, hOldFont);
++ yOffset -= r.bottom;
++ yOffset = min(yOffset, 35); /* don't make the dialog too small */
++ ReleaseDC(hDlg, hdc);
++
++ GetClientRect(hDlg, &r);
++ xPos = r.right - 7;
++ GetWindowRect(hDlg, &r);
++ width = r.right - r.left;
++ height = r.bottom - r.top - yOffset;
++ MoveWindow(hDlg, (GetSystemMetrics(SM_CXSCREEN) - width)/2,
++ (GetSystemMetrics(SM_CYSCREEN) - height)/2, width, height, FALSE);
++
++ confirm_msg_move_button(hDlg, IDCANCEL, &xPos, yOffset, info->bYesToAll);
++ confirm_msg_move_button(hDlg, IDNO, &xPos, yOffset, TRUE);
++ confirm_msg_move_button(hDlg, IDD_YESTOALL, &xPos, yOffset, info->bYesToAll);
++ confirm_msg_move_button(hDlg, IDYES, &xPos, yOffset, TRUE);
++
++ return TRUE;
++}
++
++static INT_PTR CALLBACK ConfirmMsgBoxProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
++{
++ switch (uMsg)
++ {
++ case WM_INITDIALOG:
++ return ConfirmMsgBox_Init(hDlg, lParam);
++ case WM_PAINT:
++ return ConfirmMsgBox_Paint(hDlg);
++ case WM_COMMAND:
++ EndDialog(hDlg, wParam);
++ break;
++ case WM_CLOSE:
++ EndDialog(hDlg, IDCANCEL);
++ break;
++ }
++ return FALSE;
++}
++
++int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll)
++{
++ static const WCHAR wszTemplate[] = {'S','H','E','L','L','_','Y','E','S','T','O','A','L','L','_','M','S','G','B','O','X',0};
++ struct confirm_msg_info info;
++
++ info.lpszText = lpszText;
++ info.lpszCaption = lpszCaption;
++ info.hIcon = hIcon;
++ info.bYesToAll = bYesToAll;
++ return DialogBoxParamW(shell32_hInstance, wszTemplate, hWnd, ConfirmMsgBoxProc, (LPARAM)&info);
++}
++
++/* confirmation dialogs content */
++typedef struct
++{
++ HINSTANCE hIconInstance;
++ UINT icon_resource_id;
++ UINT caption_resource_id, text_resource_id;
++} SHELL_ConfirmIDstruc;
++
++static BOOL SHELL_ConfirmIDs(int nKindOfDialog, SHELL_ConfirmIDstruc *ids)
++{
++ ids->hIconInstance = shell32_hInstance;
++ switch (nKindOfDialog)
++ {
++ case ASK_DELETE_FILE:
++ ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
++ ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
++ ids->text_resource_id = IDS_DELETEITEM_TEXT;
++ return TRUE;
++
++ case ASK_DELETE_FOLDER:
++ ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
++ ids->caption_resource_id = IDS_DELETEFOLDER_CAPTION;
++ ids->text_resource_id = IDS_DELETEITEM_TEXT;
++ return TRUE;
++
++ case ASK_DELETE_MULTIPLE_ITEM:
++ ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
++ ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
++ ids->text_resource_id = IDS_DELETEMULTIPLE_TEXT;
++ return TRUE;
++
++ case ASK_TRASH_FILE:
++ ids->icon_resource_id = IDI_SHELL_TRASH_FILE;
++ ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
++ ids->text_resource_id = IDS_TRASHITEM_TEXT;
++ return TRUE;
++
++ case ASK_TRASH_FOLDER:
++ ids->icon_resource_id = IDI_SHELL_TRASH_FILE;
++ ids->caption_resource_id = IDS_DELETEFOLDER_CAPTION;
++ ids->text_resource_id = IDS_TRASHFOLDER_TEXT;
++ return TRUE;
++
++ case ASK_TRASH_MULTIPLE_ITEM:
++ ids->icon_resource_id = IDI_SHELL_TRASH_FILE;
++ ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
++ ids->text_resource_id = IDS_TRASHMULTIPLE_TEXT;
++ return TRUE;
++
++ case ASK_CANT_TRASH_ITEM:
++ ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
++ ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
++ ids->text_resource_id = IDS_CANTTRASH_TEXT;
++ return TRUE;
++
++ case ASK_DELETE_SELECTED:
++ ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
++ ids->caption_resource_id = IDS_DELETEITEM_CAPTION;
++ ids->text_resource_id = IDS_DELETESELECTED_TEXT;
++ return TRUE;
++
++ case ASK_OVERWRITE_FILE:
++ ids->hIconInstance = NULL;
++ ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
++ ids->caption_resource_id = IDS_OVERWRITEFILE_CAPTION;
++ ids->text_resource_id = IDS_OVERWRITEFILE_TEXT;
++ return TRUE;
++
++ case ASK_OVERWRITE_FOLDER:
++ ids->hIconInstance = NULL;
++ ids->icon_resource_id = IDI_SHELL_CONFIRM_DELETE;
++ ids->caption_resource_id = IDS_OVERWRITEFILE_CAPTION;
++ ids->text_resource_id = IDS_OVERWRITEFOLDER_TEXT;
++ return TRUE;
++
++ default:
++ FIXME(" Unhandled nKindOfDialog %d stub\n", nKindOfDialog);
++ }
++ return FALSE;
++}
++
++static BOOL SHELL_ConfirmDialogW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir, FILE_OPERATION *op)
++{
++ WCHAR szCaption[255], szText[255], szBuffer[MAX_PATH + 256];
++ SHELL_ConfirmIDstruc ids;
++ DWORD_PTR args[1];
++ HICON hIcon;
++ int ret;
++
++ assert(nKindOfDialog >= 0 && nKindOfDialog < 32);
++ if (op && (op->dwYesToAllMask & (1 << nKindOfDialog)))
++ return TRUE;
++
++ if (!SHELL_ConfirmIDs(nKindOfDialog, &ids)) return FALSE;
++
++ LoadStringW(shell32_hInstance, ids.caption_resource_id, szCaption, sizeof(szCaption)/sizeof(WCHAR));
++ LoadStringW(shell32_hInstance, ids.text_resource_id, szText, sizeof(szText)/sizeof(WCHAR));
++
++ args[0] = (DWORD_PTR)szDir;
++ FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ARGUMENT_ARRAY,
++ szText, 0, 0, szBuffer, sizeof(szBuffer), (va_list*)args);
++ hIcon = LoadIconW(ids.hIconInstance, (LPWSTR)MAKEINTRESOURCE(ids.icon_resource_id));
++
++ ret = SHELL_ConfirmMsgBox(hWnd, szBuffer, szCaption, hIcon, op && op->bManyItems);
++ if (op)
++ {
++ if (ret == IDD_YESTOALL)
++ {
++ op->dwYesToAllMask |= (1 << nKindOfDialog);
++ ret = IDYES;
++ }
++ if (ret == IDCANCEL)
++ op->bCancelled = TRUE;
++ if (ret != IDYES)
++ op->req->fAnyOperationsAborted = TRUE;
++ }
++ return ret == IDYES;
++}
++
++BOOL SHELL_ConfirmYesNoW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir)
++{
++ return SHELL_ConfirmDialogW(hWnd, nKindOfDialog, szDir, NULL);
++}
++
++static DWORD SHELL32_AnsiToUnicodeBuf(LPCSTR aPath, LPWSTR *wPath, DWORD minChars)
++{
++ DWORD len = MultiByteToWideChar(CP_ACP, 0, aPath, -1, NULL, 0);
++
++ if (len < minChars)
++ len = minChars;
++
++ *wPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
++ if (*wPath)
++ {
++ MultiByteToWideChar(CP_ACP, 0, aPath, -1, *wPath, len);
++ return NO_ERROR;
++ }
++ return E_OUTOFMEMORY;
++}
++
++static void SHELL32_FreeUnicodeBuf(LPWSTR wPath)
++{
++ HeapFree(GetProcessHeap(), 0, wPath);
++}
++
++EXTERN_C HRESULT WINAPI SHIsFileAvailableOffline(LPCWSTR path, LPDWORD status)
++{
++ FIXME("(%s, %p) stub\n", debugstr_w(path), status);
++ return E_FAIL;
++}
++
++/**************************************************************************
++ * SHELL_DeleteDirectory() [internal]
++ *
++ * Asks for confirmation when bShowUI is true and deletes the directory and
++ * all its subdirectories and files if necessary.
++ */
++BOOL SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pszDir, BOOL bShowUI)
++{
++ BOOL ret = TRUE;
++ HANDLE hFind;
++ WIN32_FIND_DATAW wfd;
++ WCHAR szTemp[MAX_PATH];
++
++ /* Make sure the directory exists before eventually prompting the user */
++ PathCombineW(szTemp, pszDir, wWildcardFile);
++ hFind = FindFirstFileW(szTemp, &wfd);
++ if (hFind == INVALID_HANDLE_VALUE)
++ return FALSE;
++
++ if (!bShowUI || (ret = SHELL_ConfirmDialogW(hwnd, ASK_DELETE_FOLDER, pszDir, NULL)))
++ {
++ do
++ {
++ if (IsDotDir(wfd.cFileName))
++ continue;
++ PathCombineW(szTemp, pszDir, wfd.cFileName);
++ if (FILE_ATTRIBUTE_DIRECTORY & wfd.dwFileAttributes)
++ ret = SHELL_DeleteDirectoryW(hwnd, szTemp, FALSE);
++ else
++ ret = (SHNotifyDeleteFileW(szTemp) == ERROR_SUCCESS);
++ } while (ret && FindNextFileW(hFind, &wfd));
++ }
++ FindClose(hFind);
++ if (ret)
++ ret = (SHNotifyRemoveDirectoryW(pszDir) == ERROR_SUCCESS);
++ return ret;
++}
++
++/**************************************************************************
++ * Win32CreateDirectory [SHELL32.93]
++ *
++ * Creates a directory. Also triggers a change notify if one exists.
++ *
++ * PARAMS
++ * path [I] path to directory to create
++ *
++ * RETURNS
++ * TRUE if successful, FALSE otherwise
++ */
++
++static DWORD SHNotifyCreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
++{
++ TRACE("(%s, %p)\n", debugstr_w(path), sec);
++
++ if (CreateDirectoryW(path, sec))
++ {
++ SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, path, NULL);
++ return ERROR_SUCCESS;
++ }
++ return GetLastError();
++}
++
++/**********************************************************************/
++
++EXTERN_C BOOL WINAPI Win32CreateDirectoryW(LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
++{
++ return (SHNotifyCreateDirectoryW(path, sec) == ERROR_SUCCESS);
++}
++
++/************************************************************************
++ * Win32RemoveDirectory [SHELL32.94]
++ *
++ * Deletes a directory. Also triggers a change notify if one exists.
++ *
++ * PARAMS
++ * path [I] path to directory to delete
++ *
++ * RETURNS
++ * TRUE if successful, FALSE otherwise
++ */
++static DWORD SHNotifyRemoveDirectoryW(LPCWSTR path)
++{
++ BOOL ret;
++ TRACE("(%s)\n", debugstr_w(path));
++
++ ret = RemoveDirectoryW(path);
++ if (!ret)
++ {
++ /* Directory may be write protected */
++ DWORD dwAttr = GetFileAttributesW(path);
++ if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY))
++ if (SetFileAttributesW(path, dwAttr & ~FILE_ATTRIBUTE_READONLY))
++ ret = RemoveDirectoryW(path);
++ }
++ if (ret)
++ {
++ SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW, path, NULL);
++ return ERROR_SUCCESS;
++ }
++ return GetLastError();
++}
++
++/***********************************************************************/
++
++EXTERN_C BOOL WINAPI Win32RemoveDirectoryW(LPCWSTR path)
++{
++ return (SHNotifyRemoveDirectoryW(path) == ERROR_SUCCESS);
++}
++
++/************************************************************************
++ * Win32DeleteFile [SHELL32.164]
++ *
++ * Deletes a file. Also triggers a change notify if one exists.
++ *
++ * PARAMS
++ * path [I] path to file to delete
++ *
++ * RETURNS
++ * TRUE if successful, FALSE otherwise
++ */
++static DWORD SHNotifyDeleteFileW(LPCWSTR path)
++{
++ BOOL ret;
++
++ TRACE("(%s)\n", debugstr_w(path));
++
++ ret = DeleteFileW(path);
++ if (!ret)
++ {
++ /* File may be write protected or a system file */
++ DWORD dwAttr = GetFileAttributesW(path);
++ if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
++ if (SetFileAttributesW(path, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
++ ret = DeleteFileW(path);
++ }
++ if (ret)
++ {
++ SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW, path, NULL);
++ return ERROR_SUCCESS;
++ }
++ return GetLastError();
++}
++
++/***********************************************************************/
++
++EXTERN_C DWORD WINAPI Win32DeleteFileW(LPCWSTR path)
++{
++ return (SHNotifyDeleteFileW(path) == ERROR_SUCCESS);
++}
++
++/************************************************************************
++ * SHNotifyMoveFile [internal]
++ *
++ * Moves a file. Also triggers a change notify if one exists.
++ *
++ * PARAMS
++ * src [I] path to source file to move
++ * dest [I] path to target file to move to
++ *
++ * RETURNS
++ * ERORR_SUCCESS if successful
++ */
++static DWORD SHNotifyMoveFileW(LPCWSTR src, LPCWSTR dest)
++{
++ BOOL ret;
++
++ TRACE("(%s %s)\n", debugstr_w(src), debugstr_w(dest));
++
++ ret = MoveFileExW(src, dest, MOVEFILE_REPLACE_EXISTING);
++
++ /* MOVEFILE_REPLACE_EXISTING fails with dirs, so try MoveFile */
++ if (!ret)
++ ret = MoveFileW(src, dest);
++
++ if (!ret)
++ {
++ DWORD dwAttr;
++
++ dwAttr = SHFindAttrW(dest, FALSE);
++ if (INVALID_FILE_ATTRIBUTES == dwAttr)
++ {
++ /* Source file may be write protected or a system file */
++ dwAttr = GetFileAttributesW(src);
++ if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
++ if (SetFileAttributesW(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
++ ret = MoveFileW(src, dest);
++ }
++ }
++ if (ret)
++ {
++ SHChangeNotify(SHCNE_RENAMEITEM, SHCNF_PATHW, src, dest);
++ return ERROR_SUCCESS;
++ }
++ return GetLastError();
++}
++
++static DWORD WINAPI SHOperationProgressRoutine(LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER StreamSize, LARGE_INTEGER StreamBytesTransferred, DWORD dwStreamNumber, DWORD dwCallbackReason, HANDLE hSourceFile, HANDLE hDestinationFile, LPVOID lpData)
++{
++ FILE_OPERATION_CONTEXT * Context;
++ LARGE_INTEGER Progress;
++
++ /* get context */
++ Context = (FILE_OPERATION_CONTEXT*)lpData;
++
++ if (TotalBytesTransferred.QuadPart)
++ {
++ Progress.QuadPart = (TotalBytesTransferred.QuadPart * 100) / TotalFileSize.QuadPart;
++ }
++ else
++ {
++ Progress.QuadPart = 1;
++ }
++
++ /* update progress bar */
++ SendMessageW(Context->hDlgCtrl, PBM_SETPOS, (WPARAM)Progress.u.LowPart, 0);
++
++ if (TotalBytesTransferred.QuadPart == TotalFileSize.QuadPart)
++ {
++ /* file was copied */
++ Context->Index++;
++ PostMessageW(Context->hwndDlg, WM_FILE, 0, 0);
++ }
++
++ return PROGRESS_CONTINUE;
++}
++
++BOOL
++QueueFile(
++ FILE_OPERATION_CONTEXT * Context)
++{
++ FILE_ENTRY * from, *to = NULL;
++ BOOL bRet = FALSE;
++
++ if (Context->Index >= Context->from->dwNumFiles)
++ return FALSE;
++
++ /* get current file */
++ from = &Context->from->feFiles[Context->Index];
++
++ if (Context->op->req->wFunc != FO_DELETE)
++ to = &Context->to->feFiles[Context->Index];
++
++ /* update status */
++ SendDlgItemMessageW(Context->hwndDlg, 14001, WM_SETTEXT, 0, (LPARAM)from->szFullPath);
++
++ if (Context->op->req->wFunc == FO_COPY)
++ {
++ bRet = CopyFileExW(from->szFullPath, to->szFullPath, SHOperationProgressRoutine, (LPVOID)Context, &Context->op->bCancelled, 0);
++ }
++ else if (Context->op->req->wFunc == FO_MOVE)
++ {
++ //bRet = MoveFileWithProgressW(from->szFullPath, to->szFullPath, SHOperationProgressRoutine, (LPVOID)Context, MOVEFILE_COPY_ALLOWED);
++ }
++ else if (Context->op->req->wFunc == FO_DELETE)
++ {
++ bRet = DeleteFile(from->szFullPath);
++ }
++
++ return bRet;
++}
++
++static INT_PTR CALLBACK SHOperationDialog(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
++{
++ FILE_OPERATION_CONTEXT * Context;
++
++ Context = (FILE_OPERATION_CONTEXT*) GetWindowLongPtr(hwndDlg, DWLP_USER);
++
++ switch(uMsg)
++ {
++ case WM_INITDIALOG:
++ SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG)lParam);
++
++ /* get context */
++ Context = (FILE_OPERATION_CONTEXT*)lParam;
++
++ /* store progress bar handle */
++ Context->hDlgCtrl = GetDlgItem(hwndDlg, 14000);
++
++ /* store window handle */
++ Context->hwndDlg = hwndDlg;
++
++ /* set progress bar range */
++ (void)SendMessageW(Context->hDlgCtrl, (UINT) PBM_SETRANGE, 0, MAKELPARAM(0, 100));
++
++ /* start file queueing */
++ SetTimer(hwndDlg, TIMER_ID, 1000, NULL);
++ //QueueFile(Context);
++
++ return TRUE;
++
++ case WM_CLOSE:
++ Context->op->bCancelled = TRUE;
++ EndDialog(hwndDlg, Context->op->bCancelled);
++ return TRUE;
++
++ case WM_COMMAND:
++ if (LOWORD(wParam) == 14002)
++ {
++ Context->op->bCancelled = TRUE;
++ EndDialog(hwndDlg, Context->op->bCancelled);
++ return TRUE;
++ }; break;
++
++ case WM_TIMER:
++ if (wParam == TIMER_ID)
++ {
++ QueueFile(Context);
++ KillTimer(hwndDlg, TIMER_ID);
++ }; break;
++
++ case WM_FILE:
++ if (!QueueFile(Context))
++ EndDialog(hwndDlg, Context->op->bCancelled);
++ default:
++ break;
++ }
++ return FALSE;
++}
++
++HRESULT
++SHShowFileOperationDialog(FILE_OPERATION *op, FILE_LIST *flFrom, FILE_LIST *flTo)
++{
++ HWND hwnd;
++ BOOL bRet;
++ MSG msg;
++ FILE_OPERATION_CONTEXT Context;
++
++ Context.from = flFrom;
++ Context.to = flTo;
++ Context.op = op;
++ Context.Index = 0;
++ Context.op->bCancelled = FALSE;
++
++ hwnd = CreateDialogParam(shell32_hInstance, MAKEINTRESOURCE(IDD_SH_FILE_COPY), NULL, SHOperationDialog, (LPARAM)&Context);
++ if (hwnd == NULL)
++ {
++ ERR("Failed to create dialog\n");
++ return E_FAIL;
++ }
++ ShowWindow(hwnd, SW_SHOWNORMAL);
++
++ while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
++ {
++ if (!IsWindow(hwnd) || !IsDialogMessage(hwnd, &msg))
++ {
++ TranslateMessage(&msg);
++ DispatchMessage(&msg);
++ }
++ }
++
++ return NOERROR;
++}
++
++
++/************************************************************************
++ * SHNotifyCopyFile [internal]
++ *
++ * Copies a file. Also triggers a change notify if one exists.
++ *
++ * PARAMS
++ * src [I] path to source file to move
++ * dest [I] path to target file to move to
++ * bFailIfExists [I] if TRUE, the target file will not be overwritten if
++ * a file with this name already exists
++ *
++ * RETURNS
++ * ERROR_SUCCESS if successful
++ */
++static DWORD SHNotifyCopyFileW(LPCWSTR src, LPCWSTR dest, BOOL bFailIfExists)
++{
++ BOOL ret;
++ DWORD attribs;
++
++ TRACE("(%s %s %s)\n", debugstr_w(src), debugstr_w(dest), bFailIfExists ? "failIfExists" : "");
++
++ /* Destination file may already exist with read only attribute */
++ attribs = GetFileAttributesW(dest);
++ if (IsAttrib(attribs, FILE_ATTRIBUTE_READONLY))
++ SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY);
++
++ if (GetFileAttributesW(dest) & FILE_ATTRIBUTE_READONLY)
++ {
++ SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY);
++ if (GetFileAttributesW(dest) & FILE_ATTRIBUTE_READONLY)
++ {
++ TRACE("[shell32, SHNotifyCopyFileW] STILL SHIT\n");
++ }
++ }
++
++ ret = CopyFileW(src, dest, bFailIfExists);
++ if (ret)
++ {
++ SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, dest, NULL);
++ return ERROR_SUCCESS;
++ }
++
++ return GetLastError();
++}
++
++/*************************************************************************
++ * SHCreateDirectory [SHELL32.165]
++ *
++ * This function creates a file system folder whose fully qualified path is
++ * given by path. If one or more of the intermediate folders do not exist,
++ * they will be created as well.
++ *
++ * PARAMS
++ * hWnd [I]
++ * path [I] path of directory to create
++ *
++ * RETURNS
++ * ERROR_SUCCESS or one of the following values:
++ * ERROR_BAD_PATHNAME if the path is relative
++ * ERROR_FILE_EXISTS when a file with that name exists
++ * ERROR_PATH_NOT_FOUND can't find the path, probably invalid
++ * ERROR_INVALID_NAME if the path contains invalid chars
++ * ERROR_ALREADY_EXISTS when the directory already exists
++ * ERROR_FILENAME_EXCED_RANGE if the filename was to long to process
++ *
++ * NOTES
++ * exported by ordinal
++ * Win9x exports ANSI
++ * WinNT/2000 exports Unicode
++ */
++int WINAPI SHCreateDirectory(HWND hWnd, LPCWSTR path)
++{
++ return SHCreateDirectoryExW(hWnd, path, NULL);
++}
++
++/*************************************************************************
++ * SHCreateDirectoryExA [SHELL32.@]
++ *
++ * This function creates a file system folder whose fully qualified path is
++ * given by path. If one or more of the intermediate folders do not exist,
++ * they will be created as well.
++ *
++ * PARAMS
++ * hWnd [I]
++ * path [I] path of directory to create
++ * sec [I] security attributes to use or NULL
++ *
++ * RETURNS
++ * ERROR_SUCCESS or one of the following values:
++ * ERROR_BAD_PATHNAME or ERROR_PATH_NOT_FOUND if the path is relative
++ * ERROR_INVALID_NAME if the path contains invalid chars
++ * ERROR_FILE_EXISTS when a file with that name exists
++ * ERROR_ALREADY_EXISTS when the directory already exists
++ * ERROR_FILENAME_EXCED_RANGE if the filename was to long to process
++ *
++ * FIXME: Not implemented yet;
++ * SHCreateDirectoryEx also verifies that the files in the directory will be visible
++ * if the path is a network path to deal with network drivers which might have a limited
++ * but unknown maximum path length. If not:
++ *
++ * If hWnd is set to a valid window handle, a message box is displayed warning
++ * the user that the files may not be accessible. If the user chooses not to
++ * proceed, the function returns ERROR_CANCELLED.
++ *
++ * If hWnd is set to NULL, no user interface is displayed and the function
++ * returns ERROR_CANCELLED.
++ */
++int WINAPI SHCreateDirectoryExA(HWND hWnd, LPCSTR path, LPSECURITY_ATTRIBUTES sec)
++{
++ LPWSTR wPath;
++ DWORD retCode;
++
++ TRACE("(%s, %p)\n", debugstr_a(path), sec);
++
++ retCode = SHELL32_AnsiToUnicodeBuf(path, &wPath, 0);
++ if (!retCode)
++ {
++ retCode = SHCreateDirectoryExW(hWnd, wPath, sec);
++ SHELL32_FreeUnicodeBuf(wPath);
++ }
++ return retCode;
++}
++
++/*************************************************************************
++ * SHCreateDirectoryExW [SHELL32.@]
++ *
++ * See SHCreateDirectoryExA.
++ */
++int WINAPI SHCreateDirectoryExW(HWND hWnd, LPCWSTR path, LPSECURITY_ATTRIBUTES sec)
++{
++ int ret = ERROR_BAD_PATHNAME;
++ TRACE("(%p, %s, %p)\n", hWnd, debugstr_w(path), sec);
++
++ if (PathIsRelativeW(path))
++ {
++ SetLastError(ret);
++ }
++ else
++ {
++ ret = SHNotifyCreateDirectoryW(path, sec);
++ /* Refuse to work on certain error codes before trying to create directories recursively */
++ if (ret != ERROR_SUCCESS &&
++ ret != ERROR_FILE_EXISTS &&
++ ret != ERROR_ALREADY_EXISTS &&
++ ret != ERROR_FILENAME_EXCED_RANGE)
++ {
++ WCHAR *pEnd, *pSlash, szTemp[MAX_PATH + 1]; /* extra for PathAddBackslash() */
++
++ lstrcpynW(szTemp, path, MAX_PATH);
++ pEnd = PathAddBackslashW(szTemp);
++ pSlash = szTemp + 3;
++
++ while (*pSlash)
++ {
++ while (*pSlash && *pSlash != '\\') pSlash++;
++ if (*pSlash)
++ {
++ *pSlash = 0; /* terminate path at separator */
++
++ ret = SHNotifyCreateDirectoryW(szTemp, pSlash + 1 == pEnd ? sec : NULL);
++ }
++ *pSlash++ = '\\'; /* put the separator back */
++ }
++ }
++
++ if (ret && hWnd && (ERROR_CANCELLED != ret))
++ {
++ /* We failed and should show a dialog box */
++ FIXME("Show system error message, creating path %s, failed with error %d\n", debugstr_w(path), ret);
++ ret = ERROR_CANCELLED; /* Error has been already presented to user (not really yet!) */
++ }
++ }
++
++ return ret;
++}
++
++/*************************************************************************
++ * SHFindAttrW [internal]
++ *
++ * Get the Attributes for a file or directory. The difference to GetAttributes()
++ * is that this function will also work for paths containing wildcard characters
++ * in its filename.
++
++ * PARAMS
++ * path [I] path of directory or file to check
++ * fileOnly [I] TRUE if only files should be found
++ *
++ * RETURNS
++ * INVALID_FILE_ATTRIBUTES if the path does not exist, the actual attributes of
++ * the first file or directory found otherwise
++ */
++static DWORD SHFindAttrW(LPCWSTR pName, BOOL fileOnly)
++{
++ WIN32_FIND_DATAW wfd;
++ BOOL b_FileMask = fileOnly && (NULL != StrPBrkW(pName, wWildcardChars));
++ DWORD dwAttr = INVALID_FILE_ATTRIBUTES;
++ HANDLE hFind = FindFirstFileW(pName, &wfd);
++
++ TRACE("%s %d\n", debugstr_w(pName), fileOnly);
++ if (INVALID_HANDLE_VALUE != hFind)
++ {
++ do
++ {
++ if (b_FileMask && IsAttribDir(wfd.dwFileAttributes))
++ continue;
++ dwAttr = wfd.dwFileAttributes;
++ break;
++ } while (FindNextFileW(hFind, &wfd));
++
++ FindClose(hFind);
++ }
++ return dwAttr;
++}
++
++/*************************************************************************
++ *
++ * SHNameTranslate HelperFunction for SHFileOperationA
++ *
++ * Translates a list of 0 terminated ASCII strings into Unicode. If *wString
++ * is NULL, only the necessary size of the string is determined and returned,
++ * otherwise the ASCII strings are copied into it and the buffer is increased
++ * to point to the location after the final 0 termination char.
++ */
++static DWORD SHNameTranslate(LPWSTR* wString, LPCWSTR* pWToFrom, BOOL more)
++{
++ DWORD size = 0, aSize = 0;
++ LPCSTR aString = (LPCSTR)*pWToFrom;
++
++ if (aString)
++ {
++ do
++ {
++ size = lstrlenA(aString) + 1;
++ aSize += size;
++ aString += size;
++ } while ((size != 1) && more);
++
++ /* The two sizes might be different in the case of multibyte chars */
++ size = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, 0);
++ if (*wString) /* only in the second loop */
++ {
++ MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, size);
++ *pWToFrom = *wString;
++ *wString += size;
++ }
++ }
++ return size;
++}
++/*************************************************************************
++ * SHFileOperationA [SHELL32.@]
++ *
++ * Function to copy, move, delete and create one or more files with optional
++ * user prompts.
++ *
++ * PARAMS
++ * lpFileOp [I/O] pointer to a structure containing all the necessary information
++ *
++ * RETURNS
++ * Success: ERROR_SUCCESS.
++ * Failure: ERROR_CANCELLED.
++ *
++ * NOTES
++ * exported by name
++ */
++int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp)
++{
++ SHFILEOPSTRUCTW nFileOp = *((LPSHFILEOPSTRUCTW)lpFileOp);
++ int retCode = 0;
++ DWORD size;
++ LPWSTR ForFree = NULL, /* we change wString in SHNameTranslate and can't use it for freeing */
++ wString = NULL; /* we change this in SHNameTranslate */
++
++ TRACE("\n");
++ if (FO_DELETE == (nFileOp.wFunc & FO_MASK))
++ nFileOp.pTo = NULL; /* we need a NULL or a valid pointer for translation */
++ if (!(nFileOp.fFlags & FOF_SIMPLEPROGRESS))
++ nFileOp.lpszProgressTitle = NULL; /* we need a NULL or a valid pointer for translation */
++ while (1) /* every loop calculate size, second translate also, if we have storage for this */
++ {
++ size = SHNameTranslate(&wString, &nFileOp.lpszProgressTitle, FALSE); /* no loop */
++ size += SHNameTranslate(&wString, &nFileOp.pFrom, TRUE); /* internal loop */
++ size += SHNameTranslate(&wString, &nFileOp.pTo, TRUE); /* internal loop */
++
++ if (ForFree)
++ {
++ retCode = SHFileOperationW(&nFileOp);
++ HeapFree(GetProcessHeap(), 0, ForFree); /* we cannot use wString, it was changed */
++ break;
++ }
++ else
++ {
++ wString = ForFree = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
++ if (ForFree) continue;
++ retCode = ERROR_OUTOFMEMORY;
++ nFileOp.fAnyOperationsAborted = TRUE;
++ SetLastError(retCode);
++ return retCode;
++ }
++ }
++
++ lpFileOp->hNameMappings = nFileOp.hNameMappings;
++ lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
++ return retCode;
++}
++
++static void __inline grow_list(FILE_LIST *list)
++{
++ FILE_ENTRY *newx = (FILE_ENTRY *)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, list->feFiles,
++ list->num_alloc * 2 * sizeof(*newx) );
++ list->feFiles = newx;
++ list->num_alloc *= 2;
++}
++
++/* adds a file to the FILE_ENTRY struct
++ */
++static void add_file_to_entry(FILE_ENTRY *feFile, LPCWSTR szFile)
++{
++ DWORD dwLen = lstrlenW(szFile) + 1;
++ LPCWSTR ptr;
++
++ feFile->szFullPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
++ lstrcpyW(feFile->szFullPath, szFile);
++
++ ptr = StrRChrW(szFile, NULL, '\\');
++ if (ptr)
++ {
++ dwLen = ptr - szFile + 1;
++ feFile->szDirectory = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
++ lstrcpynW(feFile->szDirectory, szFile, dwLen);
++
++ dwLen = lstrlenW(feFile->szFullPath) - dwLen + 1;
++ feFile->szFilename = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
++ lstrcpyW(feFile->szFilename, ptr + 1); /* skip over backslash */
++ }
++ feFile->bFromWildcard = FALSE;
++}
++
++static LPWSTR wildcard_to_file(LPCWSTR szWildCard, LPCWSTR szFileName)
++{
++ LPCWSTR ptr;
++ LPWSTR szFullPath;
++ DWORD dwDirLen, dwFullLen;
++
++ ptr = StrRChrW(szWildCard, NULL, '\\');
++ dwDirLen = ptr - szWildCard + 1;
++
++ dwFullLen = dwDirLen + lstrlenW(szFileName) + 1;
++ szFullPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwFullLen * sizeof(WCHAR));
++
++ lstrcpynW(szFullPath, szWildCard, dwDirLen + 1);
++ lstrcatW(szFullPath, szFileName);
++
++ return szFullPath;
++}
++
++static void parse_wildcard_files(FILE_LIST *flList, LPCWSTR szFile, LPDWORD pdwListIndex)
++{
++ WIN32_FIND_DATAW wfd;
++ HANDLE hFile = FindFirstFileW(szFile, &wfd);
++ FILE_ENTRY *file;
++ LPWSTR szFullPath;
++ BOOL res;
++
++ if (hFile == INVALID_HANDLE_VALUE) return;
++
++ for (res = TRUE; res; res = FindNextFileW(hFile, &wfd))
++ {
++ if (IsDotDir(wfd.cFileName))
++ continue;
++
++ if (*pdwListIndex >= flList->num_alloc)
++ grow_list( flList );
++
++ szFullPath = wildcard_to_file(szFile, wfd.cFileName);
++ file = &flList->feFiles[(*pdwListIndex)++];
++ add_file_to_entry(file, szFullPath);
++ file->bFromWildcard = TRUE;
++ file->attributes = wfd.dwFileAttributes;
++
++ if (IsAttribDir(file->attributes))
++ flList->bAnyDirectories = TRUE;
++
++ HeapFree(GetProcessHeap(), 0, szFullPath);
++ }
++
++ FindClose(hFile);
++}
++
++/* takes the null-separated file list and fills out the FILE_LIST */
++static HRESULT parse_file_list(FILE_LIST *flList, LPCWSTR szFiles)
++{
++ LPCWSTR ptr = szFiles;
++ WCHAR szCurFile[MAX_PATH];
++ DWORD i = 0;
++
++ if (!szFiles)
++ return ERROR_INVALID_PARAMETER;
++
++ flList->bAnyFromWildcard = FALSE;
++ flList->bAnyDirectories = FALSE;
++ flList->bAnyDontExist = FALSE;
++ flList->num_alloc = 32;
++ flList->dwNumFiles = 0;
++
++ /* empty list */
++ if (!szFiles[0])
++ return ERROR_ACCESS_DENIED;
++
++ flList->feFiles = (FILE_ENTRY *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
++ flList->num_alloc * sizeof(FILE_ENTRY));
++
++ while (*ptr)
++ {
++ if (i >= flList->num_alloc) grow_list( flList );
++
++ /* change relative to absolute path */
++ if (PathIsRelativeW(ptr))
++ {
++ GetCurrentDirectoryW(MAX_PATH, szCurFile);
++ PathCombineW(szCurFile, szCurFile, ptr);
++ flList->feFiles[i].bFromRelative = TRUE;
++ }
++ else
++ {
++ lstrcpyW(szCurFile, ptr);
++ flList->feFiles[i].bFromRelative = FALSE;
++ }
++
++ /* parse wildcard files if they are in the filename */
++ if (StrPBrkW(szCurFile, wWildcardChars))
++ {
++ parse_wildcard_files(flList, szCurFile, &i);
++ flList->bAnyFromWildcard = TRUE;
++ i--;
++ }
++ else
++ {
++ FILE_ENTRY *file = &flList->feFiles[i];
++ add_file_to_entry(file, szCurFile);
++ file->attributes = GetFileAttributesW( file->szFullPath );
++ file->bExists = (file->attributes != INVALID_FILE_ATTRIBUTES);
++
++ if (!file->bExists)
++ flList->bAnyDontExist = TRUE;
++
++ if (IsAttribDir(file->attributes))
++ flList->bAnyDirectories = TRUE;
++ }
++
++ /* advance to the next string */
++ ptr += lstrlenW(ptr) + 1;
++ i++;
++ }
++ flList->dwNumFiles = i;
++
++ return S_OK;
++}
++
++/* free the FILE_LIST */
++static void destroy_file_list(FILE_LIST *flList)
++{
++ DWORD i;
++
++ if (!flList || !flList->feFiles)
++ return;
++
++ for (i = 0; i < flList->dwNumFiles; i++)
++ {
++ HeapFree(GetProcessHeap(), 0, flList->feFiles[i].szDirectory);
++ HeapFree(GetProcessHeap(), 0, flList->feFiles[i].szFilename);
++ HeapFree(GetProcessHeap(), 0, flList->feFiles[i].szFullPath);
++ }
++
++ HeapFree(GetProcessHeap(), 0, flList->feFiles);
++}
++
++static void copy_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWSTR szDestPath)
++{
++ WCHAR szFrom[MAX_PATH], szTo[MAX_PATH];
++ SHFILEOPSTRUCTW fileOp;
++
++ static const WCHAR wildCardFiles[] = {'*','.','*',0};
++
++ if (IsDotDir(feFrom->szFilename))
++ return;
++
++ if (PathFileExistsW(szDestPath))
++ PathCombineW(szTo, szDestPath, feFrom->szFilename);
++ else
++ lstrcpyW(szTo, szDestPath);
++
++ if (!(op->req->fFlags & FOF_NOCONFIRMATION) && PathFileExistsW(szTo))
++ {
++ if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FOLDER, feFrom->szFilename, op))
++ {
++ /* Vista returns an ERROR_CANCELLED even if user pressed "No" */
++ if (!op->bManyItems)
++ op->bCancelled = TRUE;
++ return;
++ }
++ }
++
++ szTo[lstrlenW(szTo) + 1] = '\0';
++ SHNotifyCreateDirectoryW(szTo, NULL);
++
++ PathCombineW(szFrom, feFrom->szFullPath, wildCardFiles);
++ szFrom[lstrlenW(szFrom) + 1] = '\0';
++
++ fileOp = *op->req;
++ fileOp.pFrom = szFrom;
++ fileOp.pTo = szTo;
++ fileOp.fFlags &= ~FOF_MULTIDESTFILES; /* we know we're copying to one dir */
++
++ /* Don't ask the user about overwriting files when he accepted to overwrite the
++ folder. FIXME: this is not exactly what Windows does - e.g. there would be
++ an additional confirmation for a nested folder */
++ fileOp.fFlags |= FOF_NOCONFIRMATION;
++
++ SHFileOperationW(&fileOp);
++}
++
++static BOOL copy_file_to_file(FILE_OPERATION *op, const WCHAR *szFrom, const WCHAR *szTo)
++{
++ if (!(op->req->fFlags & FOF_NOCONFIRMATION) && PathFileExistsW(szTo))
++ {
++ if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FILE, PathFindFileNameW(szTo), op))
++ return 0;
++ }
++
++ return SHNotifyCopyFileW(szFrom, szTo, FALSE) == 0;
++}
++
++/* copy a file or directory to another directory */
++static void copy_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo)
++{
++ if (!PathFileExistsW(feTo->szFullPath))
++ SHNotifyCreateDirectoryW(feTo->szFullPath, NULL);
++
++ if (IsAttribFile(feFrom->attributes))
++ {
++ WCHAR szDestPath[MAX_PATH];
++
++ PathCombineW(szDestPath, feTo->szFullPath, feFrom->szFilename);
++ copy_file_to_file(op, feFrom->szFullPath, szDestPath);
++ }
++ else if (!(op->req->fFlags & FOF_FILESONLY && feFrom->bFromWildcard))
++ copy_dir_to_dir(op, feFrom, feTo->szFullPath);
++}
++
++static void create_dest_dirs(LPCWSTR szDestDir)
++{
++ WCHAR dir[MAX_PATH];
++ LPCWSTR ptr = StrChrW(szDestDir, '\\');
++
++ /* make sure all directories up to last one are created */
++ while (ptr && (ptr = StrChrW(ptr + 1, '\\')))
++ {
++ lstrcpynW(dir, szDestDir, ptr - szDestDir + 1);
++
++ if (!PathFileExistsW(dir))
++ SHNotifyCreateDirectoryW(dir, NULL);
++ }
++
++ /* create last directory */
++ if (!PathFileExistsW(szDestDir))
++ SHNotifyCreateDirectoryW(szDestDir, NULL);
++}
++
++/* the FO_COPY operation */
++static HRESULT copy_files(FILE_OPERATION *op, const FILE_LIST *flFrom, FILE_LIST *flTo)
++{
++ DWORD i;
++ const FILE_ENTRY *entryToCopy;
++ const FILE_ENTRY *fileDest = &flTo->feFiles[0];
++
++ if (flFrom->bAnyDontExist)
++ return ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
++
++ if (flTo->dwNumFiles == 0)
++ {
++ /* If the destination is empty, SHFileOperation should use the current directory */
++ WCHAR curdir[MAX_PATH+1];
++
++ GetCurrentDirectoryW(MAX_PATH, curdir);
++ curdir[lstrlenW(curdir)+1] = 0;
++
++ destroy_file_list(flTo);
++ ZeroMemory(flTo, sizeof(FILE_LIST));
++ parse_file_list(flTo, curdir);
++ fileDest = &flTo->feFiles[0];
++ }
++
++ if (op->req->fFlags & FOF_MULTIDESTFILES)
++ {
++ if (flFrom->bAnyFromWildcard)
++ return ERROR_CANCELLED;
++
++ if (flFrom->dwNumFiles != flTo->dwNumFiles)
++ {
++ if (flFrom->dwNumFiles != 1 && !IsAttribDir(fileDest->attributes))
++ return ERROR_CANCELLED;
++
++ /* Free all but the first entry. */
++ for (i = 1; i < flTo->dwNumFiles; i++)
++ {
++ HeapFree(GetProcessHeap(), 0, flTo->feFiles[i].szDirectory);
++ HeapFree(GetProcessHeap(), 0, flTo->feFiles[i].szFilename);
++ HeapFree(GetProcessHeap(), 0, flTo->feFiles[i].szFullPath);
++ }
++
++ flTo->dwNumFiles = 1;
++ }
++ else if (IsAttribDir(fileDest->attributes))
++ {
++ for (i = 1; i < flTo->dwNumFiles; i++)
++ if (!IsAttribDir(flTo->feFiles[i].attributes) ||
++ !IsAttribDir(flFrom->feFiles[i].attributes))
++ {
++ return ERROR_CANCELLED;
++ }
++ }
++ }
++ else if (flFrom->dwNumFiles != 1)
++ {
++ if (flTo->dwNumFiles != 1 && !IsAttribDir(fileDest->attributes))
++ return ERROR_CANCELLED;
++
++ if (PathFileExistsW(fileDest->szFullPath) &&
++ IsAttribFile(fileDest->attributes))
++ {
++ return ERROR_CANCELLED;
++ }
++
++ if (flTo->dwNumFiles == 1 && fileDest->bFromRelative &&
++ !PathFileExistsW(fileDest->szFullPath))
++ {
++ return ERROR_CANCELLED;
++ }
++ }
++
++ for (i = 0; i < flFrom->dwNumFiles; i++)
++ {
++ entryToCopy = &flFrom->feFiles[i];
++
++ if ((op->req->fFlags & FOF_MULTIDESTFILES) &&
++ flTo->dwNumFiles > 1)
++ {
++ fileDest = &flTo->feFiles[i];
++ }
++
++ if (IsAttribDir(entryToCopy->attributes) &&
++ !lstrcmpiW(entryToCopy->szFullPath, fileDest->szDirectory))
++ {
++ return ERROR_SUCCESS;
++ }
++
++ create_dest_dirs(fileDest->szDirectory);
++
++ if (!lstrcmpiW(entryToCopy->szFullPath, fileDest->szFullPath))
++ {
++ if (IsAttribFile(entryToCopy->attributes))
++ return ERROR_NO_MORE_SEARCH_HANDLES;
++ else
++ return ERROR_SUCCESS;
++ }
++
++ if ((flFrom->dwNumFiles > 1 && flTo->dwNumFiles == 1) ||
++ IsAttribDir(fileDest->attributes))
++ {
++ copy_to_dir(op, entryToCopy, fileDest);
++ }
++ else if (IsAttribDir(entryToCopy->attributes))
++ {
++ copy_dir_to_dir(op, entryToCopy, fileDest->szFullPath);
++ }
++ else
++ {
++ if (!copy_file_to_file(op, entryToCopy->szFullPath, fileDest->szFullPath))
++ {
++ op->req->fAnyOperationsAborted = TRUE;
++ return ERROR_CANCELLED;
++ }
++ }
++
++ /* Vista return code. XP would return e.g. ERROR_FILE_NOT_FOUND, ERROR_ALREADY_EXISTS */
++ if (op->bCancelled)
++ return ERROR_CANCELLED;
++ }
++
++ /* Vista return code. On XP if the used pressed "No" for the last item,
++ * ERROR_ARENA_TRASHED would be returned */
++ return ERROR_SUCCESS;
++}
++
++static BOOL confirm_delete_list(HWND hWnd, DWORD fFlags, BOOL fTrash, const FILE_LIST *flFrom)
++{
++ if (flFrom->dwNumFiles > 1)
++ {
++ WCHAR tmp[8];
++ const WCHAR format[] = {'%','d',0};
++
++ wnsprintfW(tmp, sizeof(tmp)/sizeof(tmp[0]), format, flFrom->dwNumFiles);
++ return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_MULTIPLE_ITEM:ASK_DELETE_MULTIPLE_ITEM), tmp, NULL);
++ }
++ else
++ {
++ const FILE_ENTRY *fileEntry = &flFrom->feFiles[0];
++
++ if (IsAttribFile(fileEntry->attributes))
++ return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_FILE:ASK_DELETE_FILE), fileEntry->szFullPath, NULL);
++ else if (!(fFlags & FOF_FILESONLY && fileEntry->bFromWildcard))
++ return SHELL_ConfirmDialogW(hWnd, (fTrash?ASK_TRASH_FOLDER:ASK_DELETE_FOLDER), fileEntry->szFullPath, NULL);
++ }
++ return TRUE;
++}
++
++/* the FO_DELETE operation */
++static HRESULT delete_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom)
++{
++ const FILE_ENTRY *fileEntry;
++ DWORD i;
++ BOOL bPathExists;
++ BOOL bTrash;
++
++ if (!flFrom->dwNumFiles)
++ return ERROR_SUCCESS;
++
++ /* Windows also checks only the first item */
++ bTrash = (lpFileOp->fFlags & FOF_ALLOWUNDO)
++ && TRASH_CanTrashFile(flFrom->feFiles[0].szFullPath);
++
++ if (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) || (!bTrash && lpFileOp->fFlags & FOF_WANTNUKEWARNING))
++ if (!confirm_delete_list(lpFileOp->hwnd, lpFileOp->fFlags, bTrash, flFrom))
++ {
++ lpFileOp->fAnyOperationsAborted = TRUE;
++ return 0;
++ }
++
++ for (i = 0; i < flFrom->dwNumFiles; i++)
++ {
++ bPathExists = TRUE;
++ fileEntry = &flFrom->feFiles[i];
++
++ if (!IsAttribFile(fileEntry->attributes) &&
++ (lpFileOp->fFlags & FOF_FILESONLY && fileEntry->bFromWildcard))
++ continue;
++
++ if (bTrash)
++ {
++ BOOL bDelete;
++ if (TRASH_TrashFile(fileEntry->szFullPath))
++ continue;
++
++ /* Note: Windows silently deletes the file in such a situation, we show a dialog */
++ if (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) || (lpFileOp->fFlags & FOF_WANTNUKEWARNING))
++ bDelete = SHELL_ConfirmDialogW(lpFileOp->hwnd, ASK_CANT_TRASH_ITEM, fileEntry->szFullPath, NULL);
++ else
++ bDelete = TRUE;
++
++ if (!bDelete)
++ {
++ lpFileOp->fAnyOperationsAborted = TRUE;
++ break;
++ }
++ }
++
++ /* delete the file or directory */
++ if (IsAttribFile(fileEntry->attributes))
++ bPathExists = DeleteFileW(fileEntry->szFullPath);
++ else
++ bPathExists = SHELL_DeleteDirectoryW(lpFileOp->hwnd, fileEntry->szFullPath, FALSE);
++
++ if (!bPathExists)
++ {
++ DWORD err = GetLastError();
++
++ if (ERROR_FILE_NOT_FOUND == err)
++ {
++ // This is a windows 2003 server specific value which ahs been removed.
++ // Later versions of windows return ERROR_FILE_NOT_FOUND.
++ return 1026;
++ }
++ else
++ {
++ return err;
++ }
++ }
++ }
++
++ return ERROR_SUCCESS;
++}
++
++static void move_dir_to_dir(LPSHFILEOPSTRUCTW lpFileOp, const FILE_ENTRY *feFrom, LPCWSTR szDestPath)
++{
++ WCHAR szFrom[MAX_PATH], szTo[MAX_PATH];
++ SHFILEOPSTRUCTW fileOp;
++
++ static const WCHAR wildCardFiles[] = {'*','.','*',0};
++
++ if (IsDotDir(feFrom->szFilename))
++ return;
++
++ SHNotifyCreateDirectoryW(szDestPath, NULL);
++
++ PathCombineW(szFrom, feFrom->szFullPath, wildCardFiles);
++ szFrom[lstrlenW(szFrom) + 1] = '\0';
++
++ lstrcpyW(szTo, szDestPath);
++ szTo[lstrlenW(szDestPath) + 1] = '\0';
++
++ fileOp = *lpFileOp;
++ fileOp.pFrom = szFrom;
++ fileOp.pTo = szTo;
++
++ SHFileOperationW(&fileOp);
++}
++
++/* moves a file or directory to another directory */
++static void move_to_dir(LPSHFILEOPSTRUCTW lpFileOp, const FILE_ENTRY *feFrom, const FILE_ENTRY *feTo)
++{
++ WCHAR szDestPath[MAX_PATH];
++
++ PathCombineW(szDestPath, feTo->szFullPath, feFrom->szFilename);
++
++ if (IsAttribFile(feFrom->attributes))
++ SHNotifyMoveFileW(feFrom->szFullPath, szDestPath);
++ else if (!(lpFileOp->fFlags & FOF_FILESONLY && feFrom->bFromWildcard))
++ move_dir_to_dir(lpFileOp, feFrom, szDestPath);
++}
++
++/* the FO_MOVE operation */
++static HRESULT move_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, const FILE_LIST *flTo)
++{
++ DWORD i;
++ const FILE_ENTRY *entryToMove;
++ const FILE_ENTRY *fileDest;
++
++ if (!flFrom->dwNumFiles || !flTo->dwNumFiles)
++ return ERROR_CANCELLED;
++
++ if (!(lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
++ flTo->dwNumFiles > 1 && flFrom->dwNumFiles > 1)
++ {
++ return ERROR_CANCELLED;
++ }
++
++ if (!(lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
++ !flFrom->bAnyDirectories &&
++ flFrom->dwNumFiles > flTo->dwNumFiles)
++ {
++ return ERROR_CANCELLED;
++ }
++
++ if (!PathFileExistsW(flTo->feFiles[0].szDirectory))
++ return ERROR_CANCELLED;
++
++ if ((lpFileOp->fFlags & FOF_MULTIDESTFILES) &&
++ flFrom->dwNumFiles != flTo->dwNumFiles)
++ {
++ return ERROR_CANCELLED;
++ }
++
++ fileDest = &flTo->feFiles[0];
++ for (i = 0; i < flFrom->dwNumFiles; i++)
++ {
++ entryToMove = &flFrom->feFiles[i];
++
++ if (lpFileOp->fFlags & FOF_MULTIDESTFILES)
++ fileDest = &flTo->feFiles[i];
++
++ if (!PathFileExistsW(fileDest->szDirectory))
++ return ERROR_CANCELLED;
++
++ if (fileDest->bExists && IsAttribDir(fileDest->attributes))
++ move_to_dir(lpFileOp, entryToMove, fileDest);
++ else
++ SHNotifyMoveFileW(entryToMove->szFullPath, fileDest->szFullPath);
++ }
++
++ return ERROR_SUCCESS;
++}
++
++/* the FO_RENAME files */
++static HRESULT rename_files(LPSHFILEOPSTRUCTW lpFileOp, const FILE_LIST *flFrom, const FILE_LIST *flTo)
++{
++ const FILE_ENTRY *feFrom;
++ const FILE_ENTRY *feTo;
++
++ if (flFrom->dwNumFiles != 1)
++ return ERROR_GEN_FAILURE;
++
++ if (flTo->dwNumFiles != 1)
++ return ERROR_CANCELLED;
++
++ feFrom = &flFrom->feFiles[0];
++ feTo= &flTo->feFiles[0];
++
++ /* fail if destination doesn't exist */
++ if (!feFrom->bExists)
++ return ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
++
++ /* fail if destination already exists */
++ if (feTo->bExists)
++ return ERROR_ALREADY_EXISTS;
++
++ return SHNotifyMoveFileW(feFrom->szFullPath, feTo->szFullPath);
++}
++
++/* alert the user if an unsupported flag is used */
++static void check_flags(FILEOP_FLAGS fFlags)
++{
++ WORD wUnsupportedFlags = FOF_NO_CONNECTED_ELEMENTS |
++ FOF_NOCOPYSECURITYATTRIBS | FOF_NORECURSEREPARSE |
++ FOF_RENAMEONCOLLISION | FOF_WANTMAPPINGHANDLE;
++
++ if (fFlags & wUnsupportedFlags)
++ FIXME("Unsupported flags: %04x\n", fFlags);
++}
++
++/*************************************************************************
++ * SHFileOperationW [SHELL32.@]
++ *
++ * See SHFileOperationA
++ */
++int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
++{
++ FILE_OPERATION op;
++ FILE_LIST flFrom, flTo;
++ int ret = 0;
++
++ if (!lpFileOp)
++ return ERROR_INVALID_PARAMETER;
++
++ check_flags(lpFileOp->fFlags);
++
++ ZeroMemory(&flFrom, sizeof(FILE_LIST));
++ ZeroMemory(&flTo, sizeof(FILE_LIST));
++
++ if ((ret = parse_file_list(&flFrom, lpFileOp->pFrom)))
++ return ret;
++
++ if (lpFileOp->wFunc != FO_DELETE)
++ parse_file_list(&flTo, lpFileOp->pTo);
++
++ ZeroMemory(&op, sizeof(op));
++ op.req = lpFileOp;
++ op.bManyItems = (flFrom.dwNumFiles > 1);
++
++ switch (lpFileOp->wFunc)
++ {
++ case FO_COPY:
++ ret = copy_files(&op, &flFrom, &flTo);
++ break;
++ case FO_DELETE:
++ ret = delete_files(lpFileOp, &flFrom);
++ break;
++ case FO_MOVE:
++ ret = move_files(lpFileOp, &flFrom, &flTo);
++ break;
++ case FO_RENAME:
++ ret = rename_files(lpFileOp, &flFrom, &flTo);
++ break;
++ default:
++ ret = ERROR_INVALID_PARAMETER;
++ break;
++ }
++
++ destroy_file_list(&flFrom);
++
++ if (lpFileOp->wFunc != FO_DELETE)
++ destroy_file_list(&flTo);
++
++ if (ret == ERROR_CANCELLED)
++ lpFileOp->fAnyOperationsAborted = TRUE;
++
++ return ret;
++}
++
++#define SHDSA_GetItemCount(hdsa) (*(int*)(hdsa))
++
++/*************************************************************************
++ * SHFreeNameMappings [shell32.246]
++ *
++ * Free the mapping handle returned by SHFileOperation if FOF_WANTSMAPPINGHANDLE
++ * was specified.
++ *
++ * PARAMS
++ * hNameMapping [I] handle to the name mappings used during renaming of files
++ *
++ * RETURNS
++ * Nothing
++ */
++void WINAPI SHFreeNameMappings(HANDLE hNameMapping)
++{
++ if (hNameMapping)
++ {
++ int i = SHDSA_GetItemCount((HDSA)hNameMapping) - 1;
++
++ for (; i>= 0; i--)
++ {
++ LPSHNAMEMAPPINGW lp = (SHNAMEMAPPINGW *)DSA_GetItemPtr((HDSA)hNameMapping, i);
++
++ SHFree(lp->pszOldPath);
++ SHFree(lp->pszNewPath);
++ }
++ DSA_Destroy((HDSA)hNameMapping);
++ }
++}
++
++/*************************************************************************
++ * SheGetDirA [SHELL32.@]
++ *
++ * drive = 0: returns the current directory path
++ * drive > 0: returns the current directory path of the specified drive
++ * drive=1 -> A: drive=2 -> B: ...
++ * returns 0 if successful
++*/
++EXTERN_C DWORD WINAPI SheGetDirA(DWORD drive, LPSTR buffer)
++{
++ WCHAR org_path[MAX_PATH];
++ DWORD ret;
++ char drv_path[3];
++
++ /* change current directory to the specified drive */
++ if (drive) {
++ strcpy(drv_path, "A:");
++ drv_path[0] += (char)drive-1;
++
++ GetCurrentDirectoryW(MAX_PATH, org_path);
++
++ SetCurrentDirectoryA(drv_path);
++ }
++
++ /* query current directory path of the specified drive */
++ ret = GetCurrentDirectoryA(MAX_PATH, buffer);
++
++ /* back to the original drive */
++ if (drive)
++ SetCurrentDirectoryW(org_path);
++
++ if (!ret)
++ return GetLastError();
++
++ return 0;
++}
++
++/*************************************************************************
++ * SheGetDirW [SHELL32.@]
++ *
++ * drive = 0: returns the current directory path
++ * drive > 0: returns the current directory path of the specified drive
++ * drive=1 -> A: drive=2 -> B: ...
++ * returns 0 if successful
++ */
++EXTERN_C DWORD WINAPI SheGetDirW(DWORD drive, LPWSTR buffer)
++{
++ WCHAR org_path[MAX_PATH];
++ DWORD ret;
++ char drv_path[3];
++
++ /* change current directory to the specified drive */
++ if (drive)
++ {
++ strcpy(drv_path, "A:");
++ drv_path[0] += (char)drive-1;
++
++ GetCurrentDirectoryW(MAX_PATH, org_path);
++
++ SetCurrentDirectoryA(drv_path);
++ }
++
++ /* query current directory path of the specified drive */
++ ret = GetCurrentDirectoryW(MAX_PATH, buffer);
++
++ /* back to the original drive */
++ if (drive)
++ SetCurrentDirectoryW(org_path);
++
++ if (!ret)
++ return GetLastError();
++
++ return 0;
++}
++
++/*************************************************************************
++ * SheChangeDirA [SHELL32.@]
++ *
++ * changes the current directory to the specified path
++ * and returns 0 if successful
++ */
++EXTERN_C DWORD WINAPI SheChangeDirA(LPSTR path)
++{
++ if (SetCurrentDirectoryA(path))
++ return 0;
++ else
++ return GetLastError();
++}
++
++/*************************************************************************
++ * SheChangeDirW [SHELL32.@]
++ *
++ * changes the current directory to the specified path
++ * and returns 0 if successful
++ */
++EXTERN_C DWORD WINAPI SheChangeDirW(LPWSTR path)
++{
++ if (SetCurrentDirectoryW(path))
++ return 0;
++ else
++ return GetLastError();
++}
++
++/*************************************************************************
++ * IsNetDrive [SHELL32.66]
++ */
++EXTERN_C int WINAPI IsNetDrive(int drive)
++{
++ char root[4];
++ strcpy(root, "A:\\");
++ root[0] += (char)drive;
++ return (GetDriveTypeA(root) == DRIVE_REMOTE);
++}
++
++
++/*************************************************************************
++ * RealDriveType [SHELL32.524]
++ */
++EXTERN_C INT WINAPI RealDriveType(INT drive, BOOL bQueryNet)
++{
++ char root[] = "A:\\";
++ root[0] += (char)drive;
++ return GetDriveTypeA(root);
++}
++
++/***********************************************************************
++ * SHPathPrepareForWriteW (SHELL32.@)
++ */
++EXTERN_C HRESULT WINAPI SHPathPrepareForWriteW(HWND hwnd, IUnknown *modless, LPCWSTR path, DWORD flags)
++{
++ DWORD res;
++ DWORD err;
++ LPCWSTR realpath;
++ int len;
++ WCHAR* last_slash;
++ WCHAR* temppath=NULL;
++
++ TRACE("%p %p %s 0x%80x\n", hwnd, modless, debugstr_w(path), flags);
++
++ if (flags & ~(SHPPFW_DIRCREATE|SHPPFW_ASKDIRCREATE|SHPPFW_IGNOREFILENAME))
++ FIXME("unimplemented flags 0x%08x\n", flags);
++
++ /* cut off filename if necessary */
++ if (flags & SHPPFW_IGNOREFILENAME)
++ {
++ last_slash = StrRChrW(path, NULL, '\\');
++ if (last_slash == NULL)
++ len = 1;
++ else
++ len = last_slash - path + 1;
++ temppath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
++ if (!temppath)
++ return E_OUTOFMEMORY;
++ StrCpyNW(temppath, path, len);
++ realpath = temppath;
++ }
++ else
++ {
++ realpath = path;
++ }
++
++ /* try to create the directory if asked to */
++ if (flags & (SHPPFW_DIRCREATE|SHPPFW_ASKDIRCREATE))
++ {
++ if (flags & SHPPFW_ASKDIRCREATE)
++ FIXME("treating SHPPFW_ASKDIRCREATE as SHPPFW_DIRCREATE\n");
++
++ SHCreateDirectoryExW(0, realpath, NULL);
++ }
++
++ /* check if we can access the directory */
++ res = GetFileAttributesW(realpath);
++
++ HeapFree(GetProcessHeap(), 0, temppath);
++
++ if (res == INVALID_FILE_ATTRIBUTES)
++ {
++ err = GetLastError();
++ if (err == ERROR_FILE_NOT_FOUND)
++ return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
++ return HRESULT_FROM_WIN32(err);
++ }
++ else if (res & FILE_ATTRIBUTE_DIRECTORY)
++ return S_OK;
++ else
++ return HRESULT_FROM_WIN32(ERROR_DIRECTORY);
++}
++
++/***********************************************************************
++ * SHPathPrepareForWriteA (SHELL32.@)
++ */
++EXTERN_C HRESULT WINAPI SHPathPrepareForWriteA(HWND hwnd, IUnknown *modless, LPCSTR path, DWORD flags)
++{
++ WCHAR wpath[MAX_PATH];
++ MultiByteToWideChar( CP_ACP, 0, path, -1, wpath, MAX_PATH);
++ return SHPathPrepareForWriteW(hwnd, modless, wpath, flags);
++}
--- /dev/null
--- /dev/null
++/*
++ * ShellView
++ *
++ * Copyright 1998,1999 <juergen.schmied@debitel.net>
++ *
++ * This is the view visualizing the data provided by the shellfolder.
++ * No direct access to data from pidls should be done from here.
++ *
++ * 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
++ *
++ * FIXME: The order by part of the background context menu should be
++ * built according to the columns shown.
++ *
++ * FIXME: CheckToolbar: handle the "new folder" and "folder up" button
++ *
++ * FIXME: ShellView_FillList: consider sort orders
++ */
++
++/*
++TODO:
++1. Load/Save the view state from/into the stream provided by the ShellBrowser.
++2. Let the shell folder sort items.
++3. Code to merge menus in the shellbrowser is incorrect.
++4. Move the background context menu creation into shell view. It should store the
++ shell view HWND to send commands.
++5. Send init, measure, and draw messages to context menu during tracking.
++6. Shell view should do SetCommandTarget on internet toolbar.
++7. When editing starts on item, set edit text to for editing value.
++8. When shell view is called back for item info, let listview save the value.
++9. Shell view should update status bar.
++10. Fix shell view to handle view mode popup exec.
++11. The background context menu should have a pidl just like foreground menus. This
++ causes crashes when dynamic handlers try to use the NULL pidl.
++12. The SHELLDLL_DefView should not be filled with blue unconditionally. This causes
++ annoying flashing of blue even on XP, and is not correct.
++13. Reorder of columns doesn't work - might be bug in comctl32
++*/
++
++#include <precomp.h>
++
++WINE_DEFAULT_DEBUG_CHANNEL(shell);
++
++#undef SV_CLASS_NAME
++
++static const WCHAR SV_CLASS_NAME[] = {'S','H','E','L','L','D','L','L','_','D','e','f','V','i','e','w',0};
++
++typedef struct
++{ BOOL bIsAscending;
++ INT nHeaderID;
++ INT nLastHeaderID;
++}LISTVIEW_SORT_INFO, *LPLISTVIEW_SORT_INFO;
++
++#define SHV_CHANGE_NOTIFY WM_USER + 0x1111
++
++class CDefView :
++ public CWindowImpl<CDefView, CWindow, CControlWinTraits>,
++ public CComObjectRootEx<CComMultiThreadModelNoCS>,
++ public IShellView,
++ public IFolderView,
++ public IOleCommandTarget,
++ public IDropTarget,
++ public IDropSource,
++ public IViewObject,
++ public IServiceProvider
++{
++private:
++ CComPtr<IShellFolder> pSFParent;
++ CComPtr<IShellFolder2> pSF2Parent;
++ CComPtr<IShellBrowser> pShellBrowser;
++ CComPtr<ICommDlgBrowser> pCommDlgBrowser;
++ HWND hWndList; /* ListView control */
++ HWND hWndParent;
++ FOLDERSETTINGS FolderSettings;
++ HMENU hMenu;
++ UINT uState;
++ UINT cidl;
++ LPITEMIDLIST *apidl;
++ LISTVIEW_SORT_INFO ListViewSortInfo;
++ ULONG hNotify; /* change notification handle */
++ HANDLE hAccel;
++ DWORD dwAspects;
++ DWORD dwAdvf;
++ CComPtr<IAdviseSink> pAdvSink;
++ // for drag and drop
++ CComPtr<IDropTarget> pCurDropTarget; /* The sub-item, which is currently dragged over */
++ CComPtr<IDataObject> pCurDataObject; /* The dragged data-object */
++ LONG iDragOverItem; /* Dragged over item's index, iff pCurDropTarget != NULL */
++ UINT cScrollDelay; /* Send a WM_*SCROLL msg every 250 ms during drag-scroll */
++ POINT ptLastMousePos; /* Mouse position at last DragOver call */
++ //
++ CComPtr<IContextMenu2> pCM;
++public:
++ CDefView();
++ ~CDefView();
++ HRESULT WINAPI Initialize(IShellFolder *shellFolder);
++ HRESULT IncludeObject(LPCITEMIDLIST pidl);
++ HRESULT OnDefaultCommand();
++ HRESULT OnStateChange(UINT uFlags);
++ void CheckToolbar();
++ void SetStyle(DWORD dwAdd, DWORD dwRemove);
++ BOOL CreateList();
++ BOOL InitList();
++ static INT CALLBACK CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData);
++ static INT CALLBACK ListViewCompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData);
++ int LV_FindItemByPidl(LPCITEMIDLIST pidl);
++ BOOLEAN LV_AddItem(LPCITEMIDLIST pidl);
++ BOOLEAN LV_DeleteItem(LPCITEMIDLIST pidl);
++ BOOLEAN LV_RenameItem(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew);
++ static INT CALLBACK fill_list(LPVOID ptr, LPVOID arg);
++ HRESULT FillList();
++ HMENU BuildFileMenu();
++ void MergeFileMenu(HMENU hSubMenu);
++ void MergeViewMenu(HMENU hSubMenu);
++ UINT GetSelections();
++ HRESULT OpenSelectedItems();
++ void OnDeactivate();
++ void DoActivate(UINT uState);
++ HRESULT drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
++
++ // *** IOleWindow methods ***
++ virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
++ virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
++
++ // *** IShellView methods ***
++ virtual HRESULT STDMETHODCALLTYPE TranslateAccelerator(MSG *pmsg);
++ virtual HRESULT STDMETHODCALLTYPE EnableModeless(BOOL fEnable);
++ virtual HRESULT STDMETHODCALLTYPE UIActivate(UINT uState);
++ virtual HRESULT STDMETHODCALLTYPE Refresh();
++ virtual HRESULT STDMETHODCALLTYPE CreateViewWindow(IShellView *psvPrevious, LPCFOLDERSETTINGS pfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd);
++ virtual HRESULT STDMETHODCALLTYPE DestroyViewWindow();
++ virtual HRESULT STDMETHODCALLTYPE GetCurrentInfo(LPFOLDERSETTINGS pfs);
++ virtual HRESULT STDMETHODCALLTYPE AddPropertySheetPages(DWORD dwReserved, LPFNSVADDPROPSHEETPAGE pfn, LPARAM lparam);
++ virtual HRESULT STDMETHODCALLTYPE SaveViewState();
++ virtual HRESULT STDMETHODCALLTYPE SelectItem(LPCITEMIDLIST pidlItem, SVSIF uFlags);
++ virtual HRESULT STDMETHODCALLTYPE GetItemObject(UINT uItem, REFIID riid, void **ppv);
++
++ // *** IFolderView methods ***
++ virtual HRESULT STDMETHODCALLTYPE GetCurrentViewMode(UINT *pViewMode);
++ virtual HRESULT STDMETHODCALLTYPE SetCurrentViewMode(UINT ViewMode);
++ virtual HRESULT STDMETHODCALLTYPE GetFolder(REFIID riid, void **ppv);
++ virtual HRESULT STDMETHODCALLTYPE Item(int iItemIndex, LPITEMIDLIST *ppidl);
++ virtual HRESULT STDMETHODCALLTYPE ItemCount(UINT uFlags, int *pcItems);
++ virtual HRESULT STDMETHODCALLTYPE Items(UINT uFlags, REFIID riid, void **ppv);
++ virtual HRESULT STDMETHODCALLTYPE GetSelectionMarkedItem(int *piItem);
++ virtual HRESULT STDMETHODCALLTYPE GetFocusedItem(int *piItem);
++ virtual HRESULT STDMETHODCALLTYPE GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt);
++ virtual HRESULT STDMETHODCALLTYPE GetSpacing(POINT *ppt);
++ virtual HRESULT STDMETHODCALLTYPE GetDefaultSpacing(POINT *ppt);
++ virtual HRESULT STDMETHODCALLTYPE GetAutoArrange();
++ virtual HRESULT STDMETHODCALLTYPE SelectItem(int iItem, DWORD dwFlags);
++ virtual HRESULT STDMETHODCALLTYPE SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags);
++
++ // *** IOleCommandTarget methods ***
++ virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText);
++ virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
++
++ // *** IDropTarget methods ***
++ virtual HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
++ virtual HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
++ virtual HRESULT STDMETHODCALLTYPE DragLeave();
++ virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
++
++ // *** IDropSource methods ***
++ virtual HRESULT STDMETHODCALLTYPE QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
++ virtual HRESULT STDMETHODCALLTYPE GiveFeedback(DWORD dwEffect);
++
++ // *** IViewObject methods ***
++ virtual HRESULT STDMETHODCALLTYPE Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd,
++ HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds,
++ BOOL ( STDMETHODCALLTYPE *pfnContinue )(ULONG_PTR dwContinue), ULONG_PTR dwContinue);
++ virtual HRESULT STDMETHODCALLTYPE GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect,
++ DVTARGETDEVICE *ptd, HDC hicTargetDev, LOGPALETTE **ppColorSet);
++ virtual HRESULT STDMETHODCALLTYPE Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze);
++ virtual HRESULT STDMETHODCALLTYPE Unfreeze(DWORD dwFreeze);
++ virtual HRESULT STDMETHODCALLTYPE SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink);
++ virtual HRESULT STDMETHODCALLTYPE GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink);
++
++ // *** IServiceProvider methods ***
++ virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
++
++ // message handlers
++ LRESULT OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++ LRESULT OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled);
++
++ static ATL::CWndClassInfo& GetWndClassInfo()
++ {
++ static ATL::CWndClassInfo wc =
++ {
++ { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, StartWindowProc,
++ 0, 0, NULL, NULL,
++ LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_BACKGROUND + 1), NULL, SV_CLASS_NAME, NULL },
++ NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
++ };
++ return wc;
++ }
++
++ virtual WNDPROC GetWindowProc()
++ {
++ return WindowProc;
++ }
++
++ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
++ {
++ CDefView *pThis;
++ LRESULT result;
++
++ // must hold a reference during message handling
++ pThis = reinterpret_cast<CDefView *>(hWnd);
++ pThis->AddRef();
++ result = CWindowImpl<CDefView, CWindow, CControlWinTraits>::WindowProc(hWnd, uMsg, wParam, lParam);
++ pThis->Release();
++ return result;
++ }
++
++BEGIN_MSG_MAP(CDefView)
++ MESSAGE_HANDLER(WM_SIZE, OnSize)
++ MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
++ MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
++ MESSAGE_HANDLER(WM_CREATE, OnCreate)
++ MESSAGE_HANDLER(WM_ACTIVATE, OnActivate)
++ MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
++ MESSAGE_HANDLER(WM_COMMAND, OnCommand)
++ MESSAGE_HANDLER(SHV_CHANGE_NOTIFY, OnChangeNotify)
++ MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
++ MESSAGE_HANDLER(WM_DRAWITEM, OnCustomItem)
++ MESSAGE_HANDLER(WM_MEASUREITEM, OnCustomItem)
++ MESSAGE_HANDLER(WM_SHOWWINDOW, OnShowWindow)
++ MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
++ MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
++ MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
++ MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSysColorChange)
++ MESSAGE_HANDLER(CWM_GETISHELLBROWSER, OnGetShellBrowser)
++END_MSG_MAP()
++
++BEGIN_COM_MAP(CDefView)
++ COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
++ COM_INTERFACE_ENTRY_IID(IID_IShellView, IShellView)
++ COM_INTERFACE_ENTRY_IID(IID_IFolderView, IFolderView)
++ COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
++ COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
++ COM_INTERFACE_ENTRY_IID(IID_IDropSource, IDropSource)
++ COM_INTERFACE_ENTRY_IID(IID_IViewObject, IViewObject)
++ COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
++END_COM_MAP()
++};
++
++/* ListView Header ID's */
++#define LISTVIEW_COLUMN_NAME 0
++#define LISTVIEW_COLUMN_SIZE 1
++#define LISTVIEW_COLUMN_TYPE 2
++#define LISTVIEW_COLUMN_TIME 3
++#define LISTVIEW_COLUMN_ATTRIB 4
++
++/*menu items */
++#define IDM_VIEW_FILES (FCIDM_SHVIEWFIRST + 0x500)
++#define IDM_VIEW_IDW (FCIDM_SHVIEWFIRST + 0x501)
++#define IDM_MYFILEITEM (FCIDM_SHVIEWFIRST + 0x502)
++
++#define ID_LISTVIEW 1
++
++/*windowsx.h */
++#define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
++#define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
++#define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp)
++
++/*
++ Items merged into the toolbar and the filemenu
++*/
++typedef struct
++{ int idCommand;
++ int iImage;
++ int idButtonString;
++ int idMenuString;
++ BYTE bState;
++ BYTE bStyle;
++} MYTOOLINFO, *LPMYTOOLINFO;
++
++static const MYTOOLINFO Tools[] =
++{
++{ FCIDM_SHVIEW_BIGICON, 0, 0, IDS_VIEW_LARGE, TBSTATE_ENABLED, BTNS_BUTTON },
++{ FCIDM_SHVIEW_SMALLICON, 0, 0, IDS_VIEW_SMALL, TBSTATE_ENABLED, BTNS_BUTTON },
++{ FCIDM_SHVIEW_LISTVIEW, 0, 0, IDS_VIEW_LIST, TBSTATE_ENABLED, BTNS_BUTTON },
++{ FCIDM_SHVIEW_REPORTVIEW, 0, 0, IDS_VIEW_DETAILS, TBSTATE_ENABLED, BTNS_BUTTON },
++{ -1, 0, 0, 0, 0, 0}
++};
++
++typedef void (CALLBACK *PFNSHGETSETTINGSPROC)(LPSHELLFLAGSTATE lpsfs, DWORD dwMask);
++
++CDefView::CDefView()
++{
++ hWndList = NULL;
++ hWndParent = NULL;
++ FolderSettings.fFlags = 0;
++ FolderSettings.ViewMode = 0;
++ hMenu = NULL;
++ uState = 0;
++ cidl = 0;
++ apidl = NULL;
++ ListViewSortInfo.bIsAscending = FALSE;
++ ListViewSortInfo.nHeaderID = 0;
++ ListViewSortInfo.nLastHeaderID = 0;
++ hNotify = 0;
++ hAccel = NULL;
++ dwAspects = 0;
++ dwAdvf = 0;
++ iDragOverItem = 0;
++ cScrollDelay = 0;
++ ptLastMousePos.x = 0;
++ ptLastMousePos.y = 0;
++}
++
++CDefView::~CDefView()
++{
++ TRACE(" destroying IShellView(%p)\n", this);
++
++ SHFree(apidl);
++}
++
++HRESULT WINAPI CDefView::Initialize(IShellFolder *shellFolder)
++{
++ pSFParent = shellFolder;
++ shellFolder->QueryInterface(IID_IShellFolder2, (LPVOID *)&pSF2Parent);
++
++ return S_OK;
++}
++
++/**********************************************************
++ *
++ * ##### helperfunctions for communication with ICommDlgBrowser #####
++ */
++HRESULT CDefView::IncludeObject(LPCITEMIDLIST pidl)
++{
++ HRESULT ret = S_OK;
++
++ if (pCommDlgBrowser.p != NULL)
++ {
++ TRACE("ICommDlgBrowser::IncludeObject pidl=%p\n", pidl);
++ ret = pCommDlgBrowser->IncludeObject((IShellView *)this, pidl);
++ TRACE("--0x%08x\n", ret);
++ }
++
++ return ret;
++}
++
++HRESULT CDefView::OnDefaultCommand()
++{
++ HRESULT ret = S_FALSE;
++
++ if (pCommDlgBrowser.p != NULL)
++ {
++ TRACE("ICommDlgBrowser::OnDefaultCommand\n");
++ ret = pCommDlgBrowser->OnDefaultCommand((IShellView *)this);
++ TRACE("-- returns %08x\n", ret);
++ }
++
++ return ret;
++}
++
++HRESULT CDefView::OnStateChange(UINT uFlags)
++{
++ HRESULT ret = S_FALSE;
++
++ if (pCommDlgBrowser.p != NULL)
++ {
++ TRACE("ICommDlgBrowser::OnStateChange flags=%x\n", uFlags);
++ ret = pCommDlgBrowser->OnStateChange((IShellView *)this, uFlags);
++ TRACE("--\n");
++ }
++
++ return ret;
++}
++/**********************************************************
++ * set the toolbar of the filedialog buttons
++ *
++ * - activates the buttons from the shellbrowser according to
++ * the view state
++ */
++void CDefView::CheckToolbar()
++{
++ LRESULT result;
++
++ TRACE("\n");
++
++ if (pCommDlgBrowser != NULL)
++ {
++ pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
++ FCIDM_TB_SMALLICON, (FolderSettings.ViewMode==FVM_LIST)? TRUE : FALSE, &result);
++ pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_CHECKBUTTON,
++ FCIDM_TB_REPORTVIEW, (FolderSettings.ViewMode==FVM_DETAILS)? TRUE : FALSE, &result);
++ pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
++ FCIDM_TB_SMALLICON, TRUE, &result);
++ pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON,
++ FCIDM_TB_REPORTVIEW, TRUE, &result);
++ }
++}
++
++/**********************************************************
++ *
++ * ##### helperfunctions for initializing the view #####
++ */
++/**********************************************************
++ * change the style of the listview control
++ */
++void CDefView::SetStyle(DWORD dwAdd, DWORD dwRemove)
++{
++ DWORD tmpstyle;
++
++ TRACE("(%p)\n", this);
++
++ tmpstyle = ::GetWindowLongPtrW(hWndList, GWL_STYLE);
++ ::SetWindowLongPtrW(hWndList, GWL_STYLE, dwAdd | (tmpstyle & ~dwRemove));
++}
++
++/**********************************************************
++* ShellView_CreateList()
++*
++* - creates the list view window
++*/
++BOOL CDefView::CreateList()
++{ DWORD dwStyle, dwExStyle;
++
++ TRACE("%p\n",this);
++
++ dwStyle = WS_TABSTOP | WS_VISIBLE | WS_CHILDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
++ LVS_SHAREIMAGELISTS | LVS_EDITLABELS | LVS_AUTOARRANGE;
++ dwExStyle = WS_EX_CLIENTEDGE;
++
++ if (FolderSettings.fFlags & FWF_DESKTOP)
++ dwStyle |= LVS_ALIGNLEFT;
++ else
++ dwStyle |= LVS_ALIGNTOP;
++
++ switch (FolderSettings.ViewMode)
++ {
++ case FVM_ICON:
++ dwStyle |= LVS_ICON;
++ break;
++
++ case FVM_DETAILS:
++ dwStyle |= LVS_REPORT;
++ break;
++
++ case FVM_SMALLICON:
++ dwStyle |= LVS_SMALLICON;
++ break;
++
++ case FVM_LIST:
++ dwStyle |= LVS_LIST;
++ break;
++
++ default:
++ dwStyle |= LVS_LIST;
++ break;
++ }
++
++ if (FolderSettings.fFlags & FWF_AUTOARRANGE)
++ dwStyle |= LVS_AUTOARRANGE;
++
++ if (FolderSettings.fFlags & FWF_DESKTOP)
++ FolderSettings.fFlags |= FWF_NOCLIENTEDGE | FWF_NOSCROLL;
++
++ if (FolderSettings.fFlags & FWF_SINGLESEL)
++ dwStyle |= LVS_SINGLESEL;
++
++ if (FolderSettings.fFlags & FWF_NOCLIENTEDGE)
++ dwExStyle &= ~WS_EX_CLIENTEDGE;
++
++ hWndList=CreateWindowExW( dwExStyle,
++ WC_LISTVIEWW,
++ NULL,
++ dwStyle,
++ 0,0,0,0,
++ m_hWnd,
++ (HMENU)ID_LISTVIEW,
++ shell32_hInstance,
++ NULL);
++
++ if (!hWndList)
++ return FALSE;
++
++ ListViewSortInfo.bIsAscending = TRUE;
++ ListViewSortInfo.nHeaderID = -1;
++ ListViewSortInfo.nLastHeaderID = -1;
++
++ if (FolderSettings.fFlags & FWF_DESKTOP)
++ {
++ /*
++ * FIXME: look at the registry value
++ * HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ListviewShadow
++ * and activate drop shadows if necessary
++ */
++ if (1)
++ {
++ SendMessageW(hWndList, LVM_SETTEXTBKCOLOR, 0, CLR_NONE);
++ SendMessageW(hWndList, LVM_SETBKCOLOR, 0, CLR_NONE);
++ }
++ else
++ {
++ SendMessageW(hWndList, LVM_SETTEXTBKCOLOR, 0, GetSysColor(COLOR_DESKTOP));
++ SendMessageW(hWndList, LVM_SETBKCOLOR, 0, GetSysColor(COLOR_DESKTOP));
++ }
++
++ SendMessageW(hWndList, LVM_SETTEXTCOLOR, 0, RGB(255,255,255));
++ }
++
++ /* UpdateShellSettings(); */
++ return TRUE;
++}
++
++/**********************************************************
++* ShellView_InitList()
++*
++* - adds all needed columns to the shellview
++*/
++BOOL CDefView::InitList()
++{
++ LVCOLUMNW lvColumn;
++ SHELLDETAILS sd;
++ WCHAR szTemp[50];
++
++ TRACE("%p\n",this);
++
++ SendMessageW(hWndList, LVM_DELETEALLITEMS, 0, 0);
++
++ lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;
++ lvColumn.pszText = szTemp;
++
++ if (pSF2Parent)
++ {
++ for (int i=0; 1; i++)
++ {
++ if (FAILED(pSF2Parent->GetDetailsOf(NULL, i, &sd)))
++ break;
++
++ lvColumn.fmt = sd.fmt;
++ lvColumn.cx = sd.cxChar*8; /* chars->pixel */
++ StrRetToStrNW( szTemp, 50, &sd.str, NULL);
++ SendMessageW(hWndList, LVM_INSERTCOLUMNW, i, (LPARAM) &lvColumn);
++ }
++ }
++ else
++ {
++ FIXME("no SF2\n");
++ }
++
++ SendMessageW(hWndList, LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)ShellSmallIconList);
++ SendMessageW(hWndList, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)ShellBigIconList);
++
++ return TRUE;
++}
++
++/**********************************************************
++* ShellView_CompareItems()
++*
++* NOTES
++* internal, CALLBACK for DSA_Sort
++*/
++INT CALLBACK CDefView::CompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData)
++{
++ int ret;
++ TRACE("pidl1=%p pidl2=%p lpsf=%p\n", lParam1, lParam2, (LPVOID) lpData);
++
++ if (!lpData)
++ return 0;
++
++ ret = (SHORT)SCODE_CODE(((IShellFolder *)lpData)->CompareIDs(0, (LPITEMIDLIST)lParam1, (LPITEMIDLIST)lParam2));
++ TRACE("ret=%i\n",ret);
++
++ return ret;
++}
++
++/*************************************************************************
++ * ShellView_ListViewCompareItems
++ *
++ * Compare Function for the Listview (FileOpen Dialog)
++ *
++ * PARAMS
++ * lParam1 [I] the first ItemIdList to compare with
++ * lParam2 [I] the second ItemIdList to compare with
++ * lpData [I] The column ID for the header Ctrl to process
++ *
++ * RETURNS
++ * A negative value if the first item should precede the second,
++ * a positive value if the first item should follow the second,
++ * or zero if the two items are equivalent
++ *
++ * NOTES
++ * FIXME: function does what ShellView_CompareItems is supposed to do.
++ * unify it and figure out how to use the undocumented first parameter
++ * of IShellFolder_CompareIDs to do the job this function does and
++ * move this code to IShellFolder.
++ * make LISTVIEW_SORT_INFO obsolete
++ * the way this function works is only usable if we had only
++ * filesystemfolders (25/10/99 jsch)
++ */
++INT CALLBACK CDefView::ListViewCompareItems(LPVOID lParam1, LPVOID lParam2, LPARAM lpData)
++{
++ INT nDiff=0;
++ FILETIME fd1, fd2;
++ char strName1[MAX_PATH], strName2[MAX_PATH];
++ BOOL bIsFolder1, bIsFolder2,bIsBothFolder;
++ LPITEMIDLIST pItemIdList1 = (LPITEMIDLIST) lParam1;
++ LPITEMIDLIST pItemIdList2 = (LPITEMIDLIST) lParam2;
++ LISTVIEW_SORT_INFO *pSortInfo = (LPLISTVIEW_SORT_INFO) lpData;
++
++
++ bIsFolder1 = _ILIsFolder(pItemIdList1);
++ bIsFolder2 = _ILIsFolder(pItemIdList2);
++ bIsBothFolder = bIsFolder1 && bIsFolder2;
++
++ /* When sorting between a File and a Folder, the Folder gets sorted first */
++ if ( (bIsFolder1 || bIsFolder2) && !bIsBothFolder)
++ {
++ nDiff = bIsFolder1 ? -1 : 1;
++ }
++ else
++ {
++ /* Sort by Time: Folders or Files can be sorted */
++
++ if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_TIME)
++ {
++ _ILGetFileDateTime(pItemIdList1, &fd1);
++ _ILGetFileDateTime(pItemIdList2, &fd2);
++ nDiff = CompareFileTime(&fd2, &fd1);
++ }
++ /* Sort by Attribute: Folder or Files can be sorted */
++ else if(pSortInfo->nHeaderID == LISTVIEW_COLUMN_ATTRIB)
++ {
++ _ILGetFileAttributes(pItemIdList1, strName1, MAX_PATH);
++ _ILGetFileAttributes(pItemIdList2, strName2, MAX_PATH);
++ nDiff = lstrcmpiA(strName1, strName2);
++ }
++ /* Sort by FileName: Folder or Files can be sorted */
++ else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_NAME || bIsBothFolder)
++ {
++ /* Sort by Text */
++ _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH);
++ _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH);
++ nDiff = lstrcmpiA(strName1, strName2);
++ }
++ /* Sort by File Size, Only valid for Files */
++ else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_SIZE)
++ {
++ nDiff = (INT)(_ILGetFileSize(pItemIdList1, NULL, 0) - _ILGetFileSize(pItemIdList2, NULL, 0));
++ }
++ /* Sort by File Type, Only valid for Files */
++ else if (pSortInfo->nHeaderID == LISTVIEW_COLUMN_TYPE)
++ {
++ /* Sort by Type */
++ _ILGetFileType(pItemIdList1, strName1, MAX_PATH);
++ _ILGetFileType(pItemIdList2, strName2, MAX_PATH);
++ nDiff = lstrcmpiA(strName1, strName2);
++ }
++ }
++ /* If the Date, FileSize, FileType, Attrib was the same, sort by FileName */
++
++ if (nDiff == 0)
++ {
++ _ILSimpleGetText(pItemIdList1, strName1, MAX_PATH);
++ _ILSimpleGetText(pItemIdList2, strName2, MAX_PATH);
++ nDiff = lstrcmpiA(strName1, strName2);
++ }
++
++ if (!pSortInfo->bIsAscending)
++ {
++ nDiff = -nDiff;
++ }
++
++ return nDiff;
++}
++
++/**********************************************************
++* LV_FindItemByPidl()
++*/
++int CDefView::LV_FindItemByPidl(LPCITEMIDLIST pidl)
++{
++ LVITEMW lvItem;
++ lvItem.iSubItem = 0;
++ lvItem.mask = LVIF_PARAM;
++
++ for (lvItem.iItem = 0;
++ SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
++ lvItem.iItem++)
++ {
++ LPITEMIDLIST currentpidl = (LPITEMIDLIST) lvItem.lParam;
++ HRESULT hr = pSFParent->CompareIDs(0, pidl, currentpidl);
++
++ if (SUCCEEDED(hr) && !HRESULT_CODE(hr))
++ {
++ return lvItem.iItem;
++ }
++ }
++ return -1;
++}
++
++/**********************************************************
++* LV_AddItem()
++*/
++BOOLEAN CDefView::LV_AddItem(LPCITEMIDLIST pidl)
++{
++ LVITEMW lvItem;
++
++ TRACE("(%p)(pidl=%p)\n", this, pidl);
++
++ lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM; /*set the mask*/
++ lvItem.iItem = ListView_GetItemCount(hWndList); /*add the item to the end of the list*/
++ lvItem.iSubItem = 0;
++ lvItem.lParam = (LPARAM) ILClone(ILFindLastID(pidl)); /*set the item's data*/
++ lvItem.pszText = LPSTR_TEXTCALLBACKW; /*get text on a callback basis*/
++ lvItem.iImage = I_IMAGECALLBACK; /*get the image on a callback basis*/
++
++ if (SendMessageW(hWndList, LVM_INSERTITEMW, 0, (LPARAM)&lvItem) == -1)
++ return FALSE;
++ else
++ return TRUE;
++}
++
++/**********************************************************
++* LV_DeleteItem()
++*/
++BOOLEAN CDefView::LV_DeleteItem(LPCITEMIDLIST pidl)
++{
++ int nIndex;
++
++ TRACE("(%p)(pidl=%p)\n", this, pidl);
++
++ nIndex = LV_FindItemByPidl(ILFindLastID(pidl));
++
++ return (-1 == ListView_DeleteItem(hWndList, nIndex)) ? FALSE : TRUE;
++}
++
++/**********************************************************
++* LV_RenameItem()
++*/
++BOOLEAN CDefView::LV_RenameItem(LPCITEMIDLIST pidlOld, LPCITEMIDLIST pidlNew)
++{
++ int nItem;
++ LVITEMW lvItem;
++
++ TRACE("(%p)(pidlold=%p pidlnew=%p)\n", this, pidlOld, pidlNew);
++
++ nItem = LV_FindItemByPidl(ILFindLastID(pidlOld));
++
++ if ( -1 != nItem )
++ {
++ lvItem.mask = LVIF_PARAM; /* only the pidl */
++ lvItem.iItem = nItem;
++ SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
++
++ SHFree((LPITEMIDLIST)lvItem.lParam);
++ lvItem.mask = LVIF_PARAM;
++ lvItem.iItem = nItem;
++ lvItem.lParam = (LPARAM) ILClone(ILFindLastID(pidlNew)); /* set the item's data */
++ SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
++ SendMessageW(hWndList, LVM_UPDATE, nItem, 0);
++ return TRUE; /* FIXME: better handling */
++ }
++
++ return FALSE;
++}
++
++/**********************************************************
++* ShellView_FillList()
++*
++* - gets the objectlist from the shellfolder
++* - sorts the list
++* - fills the list into the view
++*/
++INT CALLBACK CDefView::fill_list( LPVOID ptr, LPVOID arg )
++{
++ LPITEMIDLIST pidl = (LPITEMIDLIST)ptr;
++ CDefView *pThis = (CDefView *)arg;
++ /* in a commdlg This works as a filemask*/
++ if (pThis->IncludeObject(pidl) == S_OK)
++ pThis->LV_AddItem(pidl);
++
++ SHFree(pidl);
++ return TRUE;
++}
++
++HRESULT CDefView::FillList()
++{
++ LPENUMIDLIST pEnumIDList;
++ LPITEMIDLIST pidl;
++ DWORD dwFetched;
++ HRESULT hRes;
++ HDPA hdpa;
++
++ TRACE("%p\n",this);
++
++ /* get the itemlist from the shfolder*/
++ hRes = pSFParent->EnumObjects(m_hWnd, SHCONTF_NONFOLDERS | SHCONTF_FOLDERS, &pEnumIDList);
++ if (hRes != S_OK)
++ {
++ if (hRes==S_FALSE)
++ return(NOERROR);
++ return(hRes);
++ }
++
++ /* create a pointer array */
++ hdpa = DPA_Create(16);
++ if (!hdpa)
++ {
++ return(E_OUTOFMEMORY);
++ }
++
++ /* copy the items into the array*/
++ while((S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && dwFetched)
++ {
++ if (DPA_InsertPtr(hdpa, 0x7fff, pidl) == -1)
++ {
++ SHFree(pidl);
++ }
++ }
++
++ /* sort the array */
++ DPA_Sort(hdpa, CompareItems, (LPARAM)pSFParent.p);
++
++ /*turn the listview's redrawing off*/
++ SendMessageA(hWndList, WM_SETREDRAW, FALSE, 0);
++
++ DPA_DestroyCallback( hdpa, fill_list, (void *)this);
++
++ /*turn the listview's redrawing back on and force it to draw*/
++ SendMessageA(hWndList, WM_SETREDRAW, TRUE, 0);
++
++ pEnumIDList->Release(); /* destroy the list*/
++
++ return S_OK;
++}
++
++LRESULT CDefView::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ ::UpdateWindow(hWndList);
++ bHandled = FALSE;
++ return 0;
++}
++
++LRESULT CDefView::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ return SendMessageW(hWndList, uMsg, 0, 0);
++}
++
++LRESULT CDefView::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ RevokeDragDrop(m_hWnd);
++ SHChangeNotifyDeregister(hNotify);
++ bHandled = FALSE;
++ return 0;
++}
++
++LRESULT CDefView::OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ if (FolderSettings.fFlags & (FWF_DESKTOP | FWF_TRANSPARENT))
++ return SendMessageW(GetParent(), WM_ERASEBKGND, wParam, lParam); /* redirect to parent */
++
++ bHandled = FALSE;
++ return 0;
++}
++
++LRESULT CDefView::OnSysColorChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ /* Forward WM_SYSCOLORCHANGE to common controls */
++ return SendMessageW(hWndList, uMsg, 0, 0);
++}
++
++LRESULT CDefView::OnGetShellBrowser(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ return (LRESULT)pShellBrowser.p;
++}
++
++/**********************************************************
++* ShellView_OnCreate()
++*/
++LRESULT CDefView::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ CComPtr<IDropTarget> pdt;
++ SHChangeNotifyEntry ntreg;
++ CComPtr<IPersistFolder2> ppf2;
++
++ TRACE("%p\n",this);
++
++ if(CreateList())
++ {
++ if(InitList())
++ {
++ FillList();
++ }
++ }
++
++ if (SUCCEEDED(this->QueryInterface(IID_IDropTarget, (LPVOID*)&pdt)))
++ RegisterDragDrop(m_hWnd, pdt);
++
++ /* register for receiving notifications */
++ pSFParent->QueryInterface(IID_IPersistFolder2, (LPVOID*)&ppf2);
++ if (ppf2)
++ {
++ ppf2->GetCurFolder((LPITEMIDLIST*)&ntreg.pidl);
++ ntreg.fRecursive = TRUE;
++ hNotify = SHChangeNotifyRegister(m_hWnd, SHCNF_IDLIST, SHCNE_ALLEVENTS, SHV_CHANGE_NOTIFY, 1, &ntreg);
++ SHFree((LPITEMIDLIST)ntreg.pidl);
++ }
++
++ hAccel = LoadAcceleratorsA(shell32_hInstance, "shv_accel");
++
++ return S_OK;
++}
++
++/**********************************************************
++ * #### Handling of the menus ####
++ */
++
++/**********************************************************
++* ShellView_BuildFileMenu()
++*/
++HMENU CDefView::BuildFileMenu()
++{ WCHAR szText[MAX_PATH];
++ MENUITEMINFOW mii;
++ int nTools,i;
++ HMENU hSubMenu;
++
++ TRACE("(%p)\n",this);
++
++ hSubMenu = CreatePopupMenu();
++ if (hSubMenu)
++ {
++ /*get the number of items in our global array*/
++ for(nTools = 0; Tools[nTools].idCommand != -1; nTools++){}
++
++ /*add the menu items*/
++ for(i = 0; i < nTools; i++)
++ {
++ LoadStringW(shell32_hInstance, Tools[i].idMenuString, szText, MAX_PATH);
++
++ ZeroMemory(&mii, sizeof(mii));
++ mii.cbSize = sizeof(mii);
++ mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
++
++ if(BTNS_SEP != Tools[i].bStyle) /* no separator*/
++ {
++ mii.fType = MFT_STRING;
++ mii.fState = MFS_ENABLED;
++ mii.dwTypeData = szText;
++ mii.wID = Tools[i].idCommand;
++ }
++ else
++ {
++ mii.fType = MFT_SEPARATOR;
++ }
++ /* tack This item onto the end of the menu */
++ InsertMenuItemW(hSubMenu, (UINT)-1, TRUE, &mii);
++ }
++ }
++
++ TRACE("-- return (menu=%p)\n",hSubMenu);
++ return hSubMenu;
++}
++
++/**********************************************************
++* ShellView_MergeFileMenu()
++*/
++void CDefView::MergeFileMenu(HMENU hSubMenu)
++{
++ TRACE("(%p)->(submenu=%p) stub\n",this,hSubMenu);
++
++ if (hSubMenu)
++ { /*insert This item at the beginning of the menu */
++ _InsertMenuItemW(hSubMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
++ _InsertMenuItemW(hSubMenu, 0, TRUE, IDM_MYFILEITEM, MFT_STRING, L"dummy45", MFS_ENABLED);
++ }
++
++ TRACE("--\n");
++}
++
++/**********************************************************
++* ShellView_MergeViewMenu()
++*/
++void CDefView::MergeViewMenu(HMENU hSubMenu)
++{
++ TRACE("(%p)->(submenu=%p)\n",this,hSubMenu);
++
++ if (hSubMenu)
++ {
++ /*add a separator at the correct position in the menu*/
++ MENUITEMINFOW mii;
++ static WCHAR view[] = L"View";
++
++ _InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED);
++
++ ZeroMemory(&mii, sizeof(mii));
++ mii.cbSize = sizeof(mii);
++ mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_DATA;
++ mii.fType = MFT_STRING;
++ mii.dwTypeData = view;
++ mii.hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
++ InsertMenuItemW(hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS, FALSE, &mii);
++ }
++}
++
++/**********************************************************
++* ShellView_GetSelections()
++*
++* - fills the this->apidl list with the selected objects
++*
++* RETURNS
++* number of selected items
++*/
++UINT CDefView::GetSelections()
++{
++ LVITEMW lvItem;
++ UINT i = 0;
++
++ SHFree(apidl);
++
++ cidl = ListView_GetSelectedCount(hWndList);
++ apidl = (LPITEMIDLIST*)SHAlloc(cidl * sizeof(LPITEMIDLIST));
++
++ TRACE("selected=%i\n", cidl);
++
++ if (apidl)
++ {
++ TRACE("-- Items selected =%u\n", cidl);
++
++ lvItem.mask = LVIF_STATE | LVIF_PARAM;
++ lvItem.stateMask = LVIS_SELECTED;
++ lvItem.iItem = 0;
++ lvItem.iSubItem = 0;
++ lvItem.state = 0;
++
++ while(SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM)&lvItem) && (i < cidl))
++ {
++ if(lvItem.state & LVIS_SELECTED)
++ {
++ apidl[i] = (LPITEMIDLIST)lvItem.lParam;
++ i++;
++ if (i == cidl)
++ break;
++ TRACE("-- selected Item found\n");
++ }
++ lvItem.iItem++;
++ }
++ }
++
++ return cidl;
++}
++
++/**********************************************************
++ * ShellView_OpenSelectedItems()
++ */
++HRESULT CDefView::OpenSelectedItems()
++{
++ static UINT CF_IDLIST = 0;
++ HRESULT hr;
++ CComPtr<IDataObject> selection;
++ CComPtr<IContextMenu> cm;
++ HMENU hmenu;
++ FORMATETC fetc;
++ STGMEDIUM stgm;
++ LPIDA pIDList;
++ LPCITEMIDLIST parent_pidl;
++ WCHAR parent_path[MAX_PATH];
++ LPCWSTR parent_dir = NULL;
++ SFGAOF attribs;
++ int i;
++ CMINVOKECOMMANDINFOEX ici;
++ MENUITEMINFOW info;
++
++ if (0 == GetSelections())
++ {
++ return S_OK;
++ }
++
++ hr = pSFParent->GetUIObjectOf(m_hWnd, cidl,
++ (LPCITEMIDLIST*)apidl, IID_IContextMenu,
++ 0, (LPVOID *)&cm);
++
++ if (SUCCEEDED(hr))
++ {
++ hmenu = CreatePopupMenu();
++ if (hmenu)
++ {
++ hr = IUnknown_SetSite(cm, (IShellView *)this);
++ if (SUCCEEDED(cm->QueryContextMenu(hmenu, 0, 0x20, 0x7fff, CMF_DEFAULTONLY)))
++ {
++ INT def = -1, n = GetMenuItemCount(hmenu);
++
++ for ( i = 0; i < n; i++ )
++ {
++ memset( &info, 0, sizeof info );
++ info.cbSize = sizeof info;
++ info.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID;
++ if (GetMenuItemInfoW( hmenu, i, TRUE, &info))
++ {
++ if (info.fState & MFS_DEFAULT)
++ {
++ def = info.wID;
++ break;
++ }
++ }
++ }
++ if (def != -1)
++ {
++ memset( &ici, 0, sizeof ici );
++ ici.cbSize = sizeof ici;
++ ici.lpVerb = MAKEINTRESOURCEA( def );
++ ici.hwnd = m_hWnd;
++
++ if (cm->InvokeCommand((LPCMINVOKECOMMANDINFO) &ici ) == S_OK)
++ {
++ DestroyMenu( hmenu );
++ hr = IUnknown_SetSite(cm, NULL);
++ return S_OK;
++ }
++ }
++
++ }
++ DestroyMenu( hmenu );
++ hr = IUnknown_SetSite(cm, NULL);
++ }
++ cm->Release();
++ }
++
++
++
++ hr = pSFParent->GetUIObjectOf(m_hWnd, cidl,
++ (LPCITEMIDLIST*)apidl, IID_IDataObject,
++ 0, (LPVOID *)&selection);
++
++
++
++ if (FAILED(hr))
++ return hr;
++
++ if (0 == CF_IDLIST)
++ {
++ CF_IDLIST = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
++ }
++
++ fetc.cfFormat = CF_IDLIST;
++ fetc.ptd = NULL;
++ fetc.dwAspect = DVASPECT_CONTENT;
++ fetc.lindex = -1;
++ fetc.tymed = TYMED_HGLOBAL;
++
++ hr = selection->QueryGetData(&fetc);
++ if (FAILED(hr))
++ return hr;
++
++ hr = selection->GetData(&fetc, &stgm);
++ if (FAILED(hr))
++ return hr;
++
++ pIDList = (LPIDA)GlobalLock(stgm.hGlobal);
++
++ parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pIDList+pIDList->aoffset[0]);
++ hr = pSFParent->GetAttributesOf(1, &parent_pidl, &attribs);
++ if (SUCCEEDED(hr) && (attribs & SFGAO_FILESYSTEM) &&
++ SHGetPathFromIDListW(parent_pidl, parent_path))
++ {
++ parent_dir = parent_path;
++ }
++
++ for (i = pIDList->cidl; i > 0; --i)
++ {
++ LPCITEMIDLIST pidl;
++
++ pidl = (LPCITEMIDLIST)((LPBYTE)pIDList+pIDList->aoffset[i]);
++
++ attribs = SFGAO_FOLDER;
++ hr = pSFParent->GetAttributesOf(1, &pidl, &attribs);
++
++ if (SUCCEEDED(hr) && ! (attribs & SFGAO_FOLDER))
++ {
++ SHELLEXECUTEINFOW shexinfo;
++
++ shexinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
++ shexinfo.fMask = SEE_MASK_INVOKEIDLIST; /* SEE_MASK_IDLIST is also possible. */
++ shexinfo.hwnd = NULL;
++ shexinfo.lpVerb = NULL;
++ shexinfo.lpFile = NULL;
++ shexinfo.lpParameters = NULL;
++ shexinfo.lpDirectory = parent_dir;
++ shexinfo.nShow = SW_NORMAL;
++ shexinfo.lpIDList = ILCombine(parent_pidl, pidl);
++
++ ShellExecuteExW(&shexinfo); /* Discard error/success info */
++
++ ILFree((LPITEMIDLIST)shexinfo.lpIDList);
++ }
++ }
++
++ GlobalUnlock(stgm.hGlobal);
++ ReleaseStgMedium(&stgm);
++
++ return S_OK;
++}
++
++/**********************************************************
++ * ShellView_DoContextMenu()
++ */
++LRESULT CDefView::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ WORD x;
++ WORD y;
++ BOOL bDefault;
++ UINT uCommand;
++ DWORD wFlags;
++ HMENU hMenu;
++ BOOL fExplore;
++ HWND hwndTree;
++ CMINVOKECOMMANDINFO cmi;
++ HRESULT hResult;
++
++ // for some reason I haven't figured out, we sometimes recurse into this method
++ if (pCM != NULL)
++ return 0;
++
++ x = LOWORD(lParam);
++ y = HIWORD(lParam);
++ bDefault = FALSE;
++
++ TRACE("(%p)->(0x%08x 0x%08x 0x%08x) stub\n",this, x, y, bDefault);
++
++ fExplore = FALSE;
++ hwndTree = NULL;
++
++ /* look, what's selected and create a context menu object of it*/
++ if (GetSelections())
++ {
++ pSFParent->GetUIObjectOf(hWndParent, cidl, (LPCITEMIDLIST*)apidl, IID_IContextMenu, NULL, (LPVOID *)&pCM);
++
++ if (pCM)
++ {
++ TRACE("-- pContextMenu\n");
++ hMenu = CreatePopupMenu();
++
++ if (hMenu)
++ {
++ hResult = IUnknown_SetSite(pCM, (IShellView *)this);
++
++ /* See if we are in Explore or Open mode. If the browser's tree is present, we are in Explore mode.*/
++ if (SUCCEEDED(pShellBrowser->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree)
++ {
++ TRACE("-- explore mode\n");
++ fExplore = TRUE;
++ }
++
++ /* build the flags depending on what we can do with the selected item */
++ wFlags = CMF_NORMAL | (cidl != 1 ? 0 : CMF_CANRENAME) | (fExplore ? CMF_EXPLORE : 0);
++
++ /* let the ContextMenu merge its items in */
++ if (SUCCEEDED(pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, wFlags )))
++ {
++ if (FolderSettings.fFlags & FWF_DESKTOP)
++ SetMenuDefaultItem(hMenu, FCIDM_SHVIEW_OPEN, MF_BYCOMMAND);
++
++ if (bDefault)
++ {
++ TRACE("-- get menu default command\n");
++ uCommand = GetMenuDefaultItem(hMenu, FALSE, GMDI_GOINTOPOPUPS);
++ }
++ else
++ {
++ TRACE("-- track popup\n");
++ uCommand = TrackPopupMenu( hMenu,TPM_LEFTALIGN | TPM_RETURNCMD,x,y,0,m_hWnd,NULL);
++ }
++
++ if (uCommand > 0)
++ {
++ TRACE("-- uCommand=%u\n", uCommand);
++
++ if (uCommand==FCIDM_SHVIEW_OPEN && pCommDlgBrowser.p != NULL)
++ {
++ TRACE("-- dlg: OnDefaultCommand\n");
++ if (OnDefaultCommand() != S_OK)
++ {
++ OpenSelectedItems();
++ }
++ }
++ else
++ {
++ TRACE("-- explore -- invoke command\n");
++ ZeroMemory(&cmi, sizeof(cmi));
++ cmi.cbSize = sizeof(cmi);
++ cmi.hwnd = hWndParent; /* this window has to answer CWM_GETISHELLBROWSER */
++ cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
++ pCM->InvokeCommand(&cmi);
++ }
++ }
++
++ hResult = IUnknown_SetSite(pCM, NULL);
++ DestroyMenu(hMenu);
++ }
++ }
++ pCM.Release();
++ }
++ }
++ else /* background context menu */
++ {
++ hMenu = CreatePopupMenu();
++
++ CDefFolderMenu_Create2(NULL, NULL, cidl, (LPCITEMIDLIST*)apidl, pSFParent, NULL, 0, NULL, (IContextMenu**)&pCM);
++ pCM->QueryContextMenu(hMenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, 0);
++
++ uCommand = TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_RETURNCMD,x,y,0,m_hWnd,NULL);
++ DestroyMenu(hMenu);
++
++ TRACE("-- (%p)->(uCommand=0x%08x )\n",this, uCommand);
++
++ ZeroMemory(&cmi, sizeof(cmi));
++ cmi.cbSize = sizeof(cmi);
++ cmi.lpVerb = (LPCSTR)MAKEINTRESOURCEA(uCommand);
++ cmi.hwnd = hWndParent;
++ pCM->InvokeCommand(&cmi);
++
++ pCM.Release();
++ }
++
++ return 0;
++}
++
++/**********************************************************
++ * ##### message handling #####
++ */
++
++/**********************************************************
++* ShellView_OnSize()
++*/
++LRESULT CDefView::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ WORD wWidth;
++ WORD wHeight;
++
++ wWidth = LOWORD(lParam);
++ wHeight = HIWORD(lParam);
++
++ TRACE("%p width=%u height=%u\n", this, wWidth, wHeight);
++
++ /*resize the ListView to fit our window*/
++ if (hWndList)
++ {
++ ::MoveWindow(hWndList, 0, 0, wWidth, wHeight, TRUE);
++ }
++
++ return 0;
++}
++
++/**********************************************************
++* ShellView_OnDeactivate()
++*
++* NOTES
++* internal
++*/
++void CDefView::OnDeactivate()
++{
++ TRACE("%p\n",this);
++
++ if (uState != SVUIA_DEACTIVATE)
++ {
++ if (hMenu)
++ {
++ pShellBrowser->SetMenuSB(0, 0, 0);
++ pShellBrowser->RemoveMenusSB(hMenu);
++ DestroyMenu(hMenu);
++ hMenu = 0;
++ }
++
++ uState = SVUIA_DEACTIVATE;
++ }
++}
++
++void CDefView::DoActivate(UINT uState)
++{
++ OLEMENUGROUPWIDTHS omw = { {0, 0, 0, 0, 0, 0} };
++ MENUITEMINFOA mii;
++ CHAR szText[MAX_PATH];
++
++ TRACE("%p uState=%x\n", this, uState);
++
++ /*don't do anything if the state isn't really changing */
++ if (uState == uState)
++ {
++ return;
++ }
++
++ OnDeactivate();
++
++ /*only do This if we are active */
++ if(uState != SVUIA_DEACTIVATE)
++ {
++ /*merge the menus */
++ hMenu = CreateMenu();
++
++ if(hMenu)
++ {
++ pShellBrowser->InsertMenusSB(hMenu, &omw);
++ TRACE("-- after fnInsertMenusSB\n");
++
++ /*build the top level menu get the menu item's text*/
++ strcpy(szText,"dummy 31");
++
++ ZeroMemory(&mii, sizeof(mii));
++ mii.cbSize = sizeof(mii);
++ mii.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_STATE;
++ mii.fType = MFT_STRING;
++ mii.fState = MFS_ENABLED;
++ mii.dwTypeData = szText;
++ mii.hSubMenu = BuildFileMenu();
++
++ /*insert our menu into the menu bar*/
++ if (mii.hSubMenu)
++ {
++ InsertMenuItemA(hMenu, FCIDM_MENU_HELP, FALSE, &mii);
++ }
++
++ /*get the view menu so we can merge with it*/
++ ZeroMemory(&mii, sizeof(mii));
++ mii.cbSize = sizeof(mii);
++ mii.fMask = MIIM_SUBMENU;
++
++ if (GetMenuItemInfoA(hMenu, FCIDM_MENU_VIEW, FALSE, &mii))
++ {
++ MergeViewMenu(mii.hSubMenu);
++ }
++
++ /*add the items that should only be added if we have the focus*/
++ if (SVUIA_ACTIVATE_FOCUS == uState)
++ {
++ /*get the file menu so we can merge with it */
++ ZeroMemory(&mii, sizeof(mii));
++ mii.cbSize = sizeof(mii);
++ mii.fMask = MIIM_SUBMENU;
++
++ if (GetMenuItemInfoA(hMenu, FCIDM_MENU_FILE, FALSE, &mii))
++ {
++ MergeFileMenu(mii.hSubMenu);
++ }
++ }
++
++ TRACE("-- before fnSetMenuSB\n");
++ pShellBrowser->SetMenuSB(hMenu, 0, m_hWnd);
++ }
++ }
++ uState = uState;
++ TRACE("--\n");
++}
++
++/**********************************************************
++* ShellView_OnActivate()
++*/
++LRESULT CDefView::OnActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ DoActivate(SVUIA_ACTIVATE_FOCUS);
++ return 0;
++}
++
++/**********************************************************
++* ShellView_OnSetFocus()
++*
++*/
++LRESULT CDefView::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ TRACE("%p\n", this);
++
++ /* Tell the browser one of our windows has received the focus. This
++ should always be done before merging menus (OnActivate merges the
++ menus) if one of our windows has the focus.*/
++
++ pShellBrowser->OnViewWindowActive((IShellView *)this);
++ DoActivate(SVUIA_ACTIVATE_FOCUS);
++
++ /* Set the focus to the listview */
++ ::SetFocus(hWndList);
++
++ /* Notify the ICommDlgBrowser interface */
++ OnStateChange(CDBOSC_SETFOCUS);
++
++ return 0;
++}
++
++/**********************************************************
++* ShellView_OnKillFocus()
++*/
++LRESULT CDefView::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ TRACE("(%p) stub\n", this);
++
++ DoActivate(SVUIA_ACTIVATE_NOFOCUS);
++ /* Notify the ICommDlgBrowser */
++ OnStateChange(CDBOSC_KILLFOCUS);
++
++ return 0;
++}
++
++/**********************************************************
++* ShellView_OnCommand()
++*
++* NOTES
++* the CmdID's are the ones from the context menu
++*/
++LRESULT CDefView::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ DWORD dwCmdID;
++ DWORD dwCmd;
++ HWND hwndCmd;
++
++ dwCmdID = GET_WM_COMMAND_ID(wParam, lParam);
++ dwCmd = GET_WM_COMMAND_CMD(wParam, lParam);
++ hwndCmd = GET_WM_COMMAND_HWND(wParam, lParam);
++
++ TRACE("(%p)->(0x%08x 0x%08x %p) stub\n",this, dwCmdID, dwCmd, hwndCmd);
++
++ switch (dwCmdID)
++ {
++ case FCIDM_SHVIEW_SMALLICON:
++ FolderSettings.ViewMode = FVM_SMALLICON;
++ SetStyle (LVS_SMALLICON, LVS_TYPEMASK);
++ CheckToolbar();
++ break;
++
++ case FCIDM_SHVIEW_BIGICON:
++ FolderSettings.ViewMode = FVM_ICON;
++ SetStyle (LVS_ICON, LVS_TYPEMASK);
++ CheckToolbar();
++ break;
++
++ case FCIDM_SHVIEW_LISTVIEW:
++ FolderSettings.ViewMode = FVM_LIST;
++ SetStyle (LVS_LIST, LVS_TYPEMASK);
++ CheckToolbar();
++ break;
++
++ case FCIDM_SHVIEW_REPORTVIEW:
++ FolderSettings.ViewMode = FVM_DETAILS;
++ SetStyle (LVS_REPORT, LVS_TYPEMASK);
++ CheckToolbar();
++ break;
++
++ /* the menu-ID's for sorting are 0x30... see shrec.rc */
++ case 0x30:
++ case 0x31:
++ case 0x32:
++ case 0x33:
++ ListViewSortInfo.nHeaderID = (LPARAM) (dwCmdID - 0x30);
++ ListViewSortInfo.bIsAscending = TRUE;
++ ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
++ SendMessageA(hWndList, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (LPARAM)ListViewCompareItems);
++ break;
++
++ default:
++ TRACE("-- COMMAND 0x%04x unhandled\n", dwCmdID);
++ }
++
++ return 0;
++}
++
++/**********************************************************
++* ShellView_OnNotify()
++*/
++
++LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ UINT CtlID;
++ LPNMHDR lpnmh;
++ LPNMLISTVIEW lpnmlv;
++ NMLVDISPINFOW *lpdi;
++ LPITEMIDLIST pidl;
++ BOOL unused;
++
++ CtlID = wParam;
++ lpnmh = (LPNMHDR)lParam;
++ lpnmlv = (LPNMLISTVIEW)lpnmh;
++ lpdi = (NMLVDISPINFOW *)lpnmh;
++
++ TRACE("%p CtlID=%u lpnmh->code=%x\n",this,CtlID,lpnmh->code);
++
++ switch (lpnmh->code)
++ {
++ case NM_SETFOCUS:
++ TRACE("-- NM_SETFOCUS %p\n", this);
++ OnSetFocus(0, 0, 0, unused);
++ break;
++
++ case NM_KILLFOCUS:
++ TRACE("-- NM_KILLFOCUS %p\n", this);
++ OnDeactivate();
++ /* Notify the ICommDlgBrowser interface */
++ OnStateChange(CDBOSC_KILLFOCUS);
++ break;
++
++ case NM_CUSTOMDRAW:
++ TRACE("-- NM_CUSTOMDRAW %p\n", this);
++ return CDRF_DODEFAULT;
++
++ case NM_RELEASEDCAPTURE:
++ TRACE("-- NM_RELEASEDCAPTURE %p\n", this);
++ break;
++
++ case NM_CLICK:
++ TRACE("-- NM_CLICK %p\n", this);
++ break;
++
++ case NM_RCLICK:
++ TRACE("-- NM_RCLICK %p\n", this);
++ break;
++
++ case NM_DBLCLK:
++ TRACE("-- NM_DBLCLK %p\n", this);
++ if (OnDefaultCommand() != S_OK) OpenSelectedItems();
++ break;
++
++ case NM_RETURN:
++ TRACE("-- NM_RETURN %p\n", this);
++ if (OnDefaultCommand() != S_OK) OpenSelectedItems();
++ break;
++
++ case HDN_ENDTRACKW:
++ TRACE("-- HDN_ENDTRACKW %p\n", this);
++ /*nColumn1 = ListView_GetColumnWidth(hWndList, 0);
++ nColumn2 = ListView_GetColumnWidth(hWndList, 1);*/
++ break;
++
++ case LVN_DELETEITEM:
++ TRACE("-- LVN_DELETEITEM %p\n", this);
++ SHFree((LPITEMIDLIST)lpnmlv->lParam); /*delete the pidl because we made a copy of it*/
++ break;
++
++ case LVN_DELETEALLITEMS:
++ TRACE("-- LVN_DELETEALLITEMS %p\n", this);
++ return FALSE;
++
++ case LVN_INSERTITEM:
++ TRACE("-- LVN_INSERTITEM (STUB)%p\n", this);
++ break;
++
++ case LVN_ITEMACTIVATE:
++ TRACE("-- LVN_ITEMACTIVATE %p\n", this);
++ OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
++ break;
++
++ case LVN_COLUMNCLICK:
++ ListViewSortInfo.nHeaderID = lpnmlv->iSubItem;
++ if (ListViewSortInfo.nLastHeaderID == ListViewSortInfo.nHeaderID)
++ {
++ ListViewSortInfo.bIsAscending = !ListViewSortInfo.bIsAscending;
++ }
++ else
++ {
++ ListViewSortInfo.bIsAscending = TRUE;
++ }
++ ListViewSortInfo.nLastHeaderID = ListViewSortInfo.nHeaderID;
++
++ SendMessageW(lpnmlv->hdr.hwndFrom, LVM_SORTITEMS, (WPARAM) &ListViewSortInfo, (LPARAM)ListViewCompareItems);
++ break;
++
++ case LVN_GETDISPINFOA:
++ case LVN_GETDISPINFOW:
++ TRACE("-- LVN_GETDISPINFO %p\n", this);
++ pidl = (LPITEMIDLIST)lpdi->item.lParam;
++
++ if (lpdi->item.mask & LVIF_TEXT) /* text requested */
++ {
++ if (pSF2Parent)
++ {
++ SHELLDETAILS sd;
++ pSF2Parent->GetDetailsOf(pidl, lpdi->item.iSubItem, &sd);
++ if (lpnmh->code == LVN_GETDISPINFOA)
++ {
++ /* shouldn't happen */
++ NMLVDISPINFOA *lpdiA = (NMLVDISPINFOA *)lpnmh;
++ StrRetToStrNA( lpdiA->item.pszText, lpdiA->item.cchTextMax, &sd.str, NULL);
++ TRACE("-- text=%s\n",lpdiA->item.pszText);
++ }
++ else /* LVN_GETDISPINFOW */
++ {
++ StrRetToStrNW( lpdi->item.pszText, lpdi->item.cchTextMax, &sd.str, NULL);
++ TRACE("-- text=%s\n",debugstr_w(lpdi->item.pszText));
++ }
++ }
++ else
++ {
++ FIXME("no SF2\n");
++ }
++ }
++ if(lpdi->item.mask & LVIF_IMAGE) /* image requested */
++ {
++ lpdi->item.iImage = SHMapPIDLToSystemImageListIndex(pSFParent, pidl, 0);
++ }
++ lpdi->item.mask |= LVIF_DI_SETITEM;
++ break;
++
++ case LVN_ITEMCHANGED:
++ TRACE("-- LVN_ITEMCHANGED %p\n", this);
++ OnStateChange(CDBOSC_SELCHANGE); /* the browser will get the IDataObject now */
++ break;
++
++ case LVN_BEGINDRAG:
++ case LVN_BEGINRDRAG:
++ TRACE("-- LVN_BEGINDRAG\n");
++
++ if (GetSelections())
++ {
++ IDataObject * pda;
++ DWORD dwAttributes = SFGAO_CANLINK;
++ DWORD dwEffect = DROPEFFECT_COPY | DROPEFFECT_MOVE;
++
++ if (SUCCEEDED(pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, IID_IDataObject,0,(LPVOID *)&pda)))
++ {
++ IDropSource * pds = (IDropSource *)this; /* own DropSource interface */
++
++ if (SUCCEEDED(pSFParent->GetAttributesOf(cidl, (LPCITEMIDLIST*)apidl, &dwAttributes)))
++ {
++ if (dwAttributes & SFGAO_CANLINK)
++ {
++ dwEffect |= DROPEFFECT_LINK;
++ }
++ }
++
++ if (pds)
++ {
++ DWORD dwEffect2;
++ DoDragDrop(pda, pds, dwEffect, &dwEffect2);
++ }
++ pda->Release();
++ }
++ }
++ break;
++
++ case LVN_BEGINLABELEDITW:
++ {
++ DWORD dwAttr = SFGAO_CANRENAME;
++ pidl = (LPITEMIDLIST)lpdi->item.lParam;
++
++ TRACE("-- LVN_BEGINLABELEDITW %p\n", this);
++
++ pSFParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &dwAttr);
++ if (SFGAO_CANRENAME & dwAttr)
++ {
++ return FALSE;
++ }
++ return TRUE;
++ }
++
++ case LVN_ENDLABELEDITW:
++ {
++ TRACE("-- LVN_ENDLABELEDITW %p\n", this);
++ if (lpdi->item.pszText)
++ {
++ HRESULT hr;
++ LVITEMW lvItem;
++
++ lvItem.iItem = lpdi->item.iItem;
++ lvItem.iSubItem = 0;
++ lvItem.mask = LVIF_PARAM;
++ SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
++
++ pidl = (LPITEMIDLIST)lpdi->item.lParam;
++ hr = pSFParent->SetNameOf(0, pidl, lpdi->item.pszText, SHGDN_INFOLDER, &pidl);
++
++ if (SUCCEEDED(hr) && pidl)
++ {
++ lvItem.mask = LVIF_PARAM;
++ lvItem.lParam = (LPARAM)pidl;
++ SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
++
++ return TRUE;
++ }
++ }
++
++ return FALSE;
++ }
++
++ case LVN_KEYDOWN:
++ {
++ /* MSG msg;
++ msg.hwnd = m_hWnd;
++ msg.message = WM_KEYDOWN;
++ msg.wParam = plvKeyDown->wVKey;
++ msg.lParam = 0;
++ msg.time = 0;
++ msg.pt = 0;*/
++
++ LPNMLVKEYDOWN plvKeyDown = (LPNMLVKEYDOWN) lpnmh;
++ SHORT ctrl = GetKeyState(VK_CONTROL) & 0x8000;
++
++ /* initiate a rename of the selected file or directory */
++ if (plvKeyDown->wVKey == VK_F2)
++ {
++ /* see how many files are selected */
++ int i = ListView_GetSelectedCount(hWndList);
++
++ /* get selected item */
++ if (i == 1)
++ {
++ /* get selected item */
++ i = ListView_GetNextItem(hWndList, -1, LVNI_SELECTED);
++
++ SendMessageW(hWndList, LVM_ENSUREVISIBLE, i, 0);
++ SendMessageW(hWndList, LVM_EDITLABELW, i, 0);
++ }
++ }
++ #if 0
++ TranslateAccelerator(m_hWnd, hAccel, &msg)
++ #endif
++ else if(plvKeyDown->wVKey == VK_DELETE)
++ {
++ UINT i;
++ int item_index;
++ LVITEMA item;
++ LPITEMIDLIST* pItems;
++ ISFHelper *psfhlp;
++
++ pSFParent->QueryInterface(IID_ISFHelper,
++ (LPVOID*)&psfhlp);
++
++ if (psfhlp == NULL)
++ break;
++
++ if (!(i = ListView_GetSelectedCount(hWndList)))
++ break;
++
++ /* allocate memory for the pidl array */
++ pItems = (LPITEMIDLIST *)HeapAlloc(GetProcessHeap(), 0,
++ sizeof(LPITEMIDLIST) * i);
++
++ /* retrieve all selected items */
++ i = 0;
++ item_index = -1;
++ while (ListView_GetSelectedCount(hWndList) > i)
++ {
++ /* get selected item */
++ item_index = ListView_GetNextItem(hWndList,
++ item_index, LVNI_SELECTED);
++ item.iItem = item_index;
++ item.mask = LVIF_PARAM;
++ SendMessageA(hWndList, LVM_GETITEMA, 0, (LPARAM) &item);
++
++ /* get item pidl */
++ pItems[i] = (LPITEMIDLIST)item.lParam;
++
++ i++;
++ }
++
++ /* perform the item deletion */
++ psfhlp->DeleteItems(i, (LPCITEMIDLIST*)pItems);
++
++ /* free pidl array memory */
++ HeapFree(GetProcessHeap(), 0, pItems);
++ }
++ /* Initiate a refresh */
++ else if (plvKeyDown->wVKey == VK_F5)
++ {
++ Refresh();
++ }
++ else if (plvKeyDown->wVKey == VK_BACK)
++ {
++ LPSHELLBROWSER lpSb;
++ if ((lpSb = (LPSHELLBROWSER)SendMessageW(hWndParent, CWM_GETISHELLBROWSER, 0, 0)))
++ {
++ lpSb->BrowseObject(NULL, SBSP_PARENT);
++ }
++ }
++ else if (plvKeyDown->wVKey == 'C' && ctrl)
++ {
++ if (GetSelections())
++ {
++ CComPtr<IDataObject> pda;
++
++ if (SUCCEEDED(pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, IID_IDataObject, 0, (LPVOID *)&pda)))
++ {
++ HRESULT hr = OleSetClipboard(pda);
++ if (FAILED(hr))
++ {
++ WARN("OleSetClipboard failed");
++ }
++ }
++ }
++ break;
++ }
++ else if(plvKeyDown->wVKey == 'V' && ctrl)
++ {
++ CComPtr<IDataObject> pda;
++ STGMEDIUM medium;
++ FORMATETC formatetc;
++ LPITEMIDLIST * apidl;
++ LPITEMIDLIST pidl;
++ CComPtr<IShellFolder> psfFrom;
++ CComPtr<IShellFolder> psfDesktop;
++ CComPtr<IShellFolder> psfTarget;
++ LPIDA lpcida;
++ CComPtr<ISFHelper> psfhlpdst;
++ CComPtr<ISFHelper> psfhlpsrc;
++ HRESULT hr;
++
++ hr = OleGetClipboard(&pda);
++ if (hr != S_OK)
++ {
++ ERR("Failed to get clipboard with %lx\n", hr);
++ return E_FAIL;
++ }
++
++ InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
++ hr = pda->GetData(&formatetc, &medium);
++
++ if (FAILED(hr))
++ {
++ ERR("Failed to get clipboard data with %lx\n", hr);
++ return E_FAIL;
++ }
++
++ /* lock the handle */
++ lpcida = (LPIDA)GlobalLock(medium.hGlobal);
++ if (!lpcida)
++ {
++ ERR("failed to lock pidl\n");
++ ReleaseStgMedium(&medium);
++ return E_FAIL;
++ }
++
++ /* convert the data into pidl */
++ apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
++
++ if (!apidl)
++ {
++ ERR("failed to copy pidl\n");
++ return E_FAIL;
++ }
++
++ if (FAILED(SHGetDesktopFolder(&psfDesktop)))
++ {
++ ERR("failed to get desktop folder\n");
++ SHFree(pidl);
++ _ILFreeaPidl(apidl, lpcida->cidl);
++ ReleaseStgMedium(&medium);
++ return E_FAIL;
++ }
++
++ if (_ILIsDesktop(pidl))
++ {
++ /* use desktop shellfolder */
++ psfFrom = psfDesktop;
++ }
++ else if (FAILED(psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom)))
++ {
++ ERR("no IShellFolder\n");
++
++ SHFree(pidl);
++ _ILFreeaPidl(apidl, lpcida->cidl);
++ ReleaseStgMedium(&medium);
++
++ return E_FAIL;
++ }
++
++ psfTarget = pSFParent;
++
++
++ /* get source and destination shellfolder */
++ if (FAILED(psfTarget->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpdst)))
++ {
++ ERR("no IID_ISFHelper for destination\n");
++
++ SHFree(pidl);
++ _ILFreeaPidl(apidl, lpcida->cidl);
++ ReleaseStgMedium(&medium);
++
++ return E_FAIL;
++ }
++
++ if (FAILED(psfFrom->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpsrc)))
++ {
++ ERR("no IID_ISFHelper for source\n");
++
++ SHFree(pidl);
++ _ILFreeaPidl(apidl, lpcida->cidl);
++ ReleaseStgMedium(&medium);
++ return E_FAIL;
++ }
++
++ /* FIXXME
++ * do we want to perform a copy or move ???
++ */
++ hr = psfhlpdst->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl);
++
++ SHFree(pidl);
++ _ILFreeaPidl(apidl, lpcida->cidl);
++ ReleaseStgMedium(&medium);
++
++ TRACE("paste end hr %x\n", hr);
++ break;
++ }
++ else
++ FIXME("LVN_KEYDOWN key=0x%08x\n",plvKeyDown->wVKey);
++ }
++ break;
++
++ default:
++ TRACE("-- %p WM_COMMAND %x unhandled\n", this, lpnmh->code);
++ break;
++ }
++
++ return 0;
++}
++
++/**********************************************************
++* ShellView_OnChange()
++*/
++LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ LPITEMIDLIST *Pidls;
++
++ Pidls = (LPITEMIDLIST *)wParam;
++
++ TRACE("(%p)(%p,%p,0x%08x)\n", this, Pidls[0], Pidls[1], lParam);
++
++ switch (lParam)
++ {
++ case SHCNE_MKDIR:
++ case SHCNE_CREATE:
++ LV_AddItem(Pidls[0]);
++ break;
++
++ case SHCNE_RMDIR:
++ case SHCNE_DELETE:
++ LV_DeleteItem(Pidls[0]);
++ break;
++
++ case SHCNE_RENAMEFOLDER:
++ case SHCNE_RENAMEITEM:
++ LV_RenameItem(Pidls[0], Pidls[1]);
++ break;
++
++ case SHCNE_UPDATEITEM:
++ break;
++ }
++
++ return TRUE;
++}
++
++/**********************************************************
++* ShellView_DoMeasureItem
++*/
++LRESULT CDefView::OnCustomItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
++{
++ if (!pCM.p)
++ {
++ /* no menu */
++ ERR("no menu!!!\n");
++ return FALSE;
++ }
++
++ if (pCM.p->HandleMenuMsg(uMsg, (WPARAM)m_hWnd, lParam) == S_OK)
++ return TRUE;
++ else
++ return FALSE;
++}
++
++/**********************************************************
++*
++*
++* The INTERFACE of the IShellView object
++*
++*
++**********************************************************
++*/
++
++/**********************************************************
++* ShellView_GetWindow
++*/
++HRESULT WINAPI CDefView::GetWindow(HWND *phWnd)
++{
++ TRACE("(%p)\n",this);
++
++ *phWnd = m_hWnd;
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDefView::ContextSensitiveHelp(BOOL fEnterMode)
++{
++ FIXME("(%p) stub\n",this);
++
++ return E_NOTIMPL;
++}
++
++/**********************************************************
++* IShellView_TranslateAccelerator
++*
++* FIXME:
++* use the accel functions
++*/
++HRESULT WINAPI CDefView::TranslateAccelerator(LPMSG lpmsg)
++{
++#if 0
++ FIXME("(%p)->(%p: hwnd=%x msg=%x lp=%x wp=%x) stub\n",this,lpmsg, lpmsg->hwnd, lpmsg->message, lpmsg->lParam, lpmsg->wParam);
++#endif
++
++ if (lpmsg->message >= WM_KEYFIRST && lpmsg->message >= WM_KEYLAST)
++ {
++ TRACE("-- key=0x04%lx\n",lpmsg->wParam) ;
++ }
++
++ return S_FALSE; /* not handled */
++}
++
++HRESULT WINAPI CDefView::EnableModeless(BOOL fEnable)
++{
++ FIXME("(%p) stub\n",this);
++
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDefView::UIActivate(UINT uState)
++{
++/*
++ CHAR szName[MAX_PATH];
++*/
++ LRESULT lResult;
++ int nPartArray[1] = {-1};
++
++ TRACE("(%p)->(state=%x) stub\n",this, uState);
++
++ /*don't do anything if the state isn't really changing*/
++ if (uState == uState)
++ {
++ return S_OK;
++ }
++
++ /*OnActivate handles the menu merging and internal state*/
++ DoActivate(uState);
++
++ /*only do This if we are active*/
++ if (uState != SVUIA_DEACTIVATE)
++ {
++
++ /*
++ GetFolderPath is not a method of IShellFolder
++ IShellFolder_GetFolderPath( pSFParent, szName, sizeof(szName) );
++ */
++ /* set the number of parts */
++ pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETPARTS, 1, (LPARAM)nPartArray, &lResult);
++
++ /* set the text for the parts */
++ /*
++ pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXTA, 0, (LPARAM)szName, &lResult);
++ */
++ }
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDefView::Refresh()
++{
++ TRACE("(%p)\n",this);
++
++ SendMessageW(hWndList, LVM_DELETEALLITEMS, 0, 0);
++ FillList();
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDefView::CreateViewWindow(IShellView *lpPrevView, LPCFOLDERSETTINGS lpfs, IShellBrowser *psb, RECT *prcView, HWND *phWnd)
++{
++ *phWnd = 0;
++
++ TRACE("(%p)->(shlview=%p set=%p shlbrs=%p rec=%p hwnd=%p) incomplete\n",this, lpPrevView,lpfs, psb, prcView, phWnd);
++
++ if (lpfs != NULL)
++ TRACE("-- vmode=%x flags=%x\n", lpfs->ViewMode, lpfs->fFlags);
++ if (prcView != NULL)
++ TRACE("-- left=%i top=%i right=%i bottom=%i\n", prcView->left, prcView->top, prcView->right, prcView->bottom);
++
++ /* Validate the Shell Browser */
++ if (psb == NULL)
++ return E_UNEXPECTED;
++
++ /*set up the member variables*/
++ pShellBrowser = psb;
++ FolderSettings = *lpfs;
++
++ /*get our parent window*/
++ pShellBrowser->GetWindow(&hWndParent);
++
++ /* try to get the ICommDlgBrowserInterface, adds a reference !!! */
++ pCommDlgBrowser = NULL;
++ if (SUCCEEDED(pShellBrowser->QueryInterface(IID_ICommDlgBrowser, (LPVOID *)&pCommDlgBrowser)))
++ {
++ TRACE("-- CommDlgBrowser\n");
++ }
++
++ Create(hWndParent, prcView, NULL, WS_CHILD | WS_TABSTOP, 0, 0U);
++ if (m_hWnd == NULL)
++ return E_FAIL;
++
++ *phWnd = m_hWnd;
++
++ CheckToolbar();
++
++ if (!*phWnd)
++ return E_FAIL;
++
++ SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
++ UpdateWindow();
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDefView::DestroyViewWindow()
++{
++ TRACE("(%p)\n",this);
++
++ /*Make absolutely sure all our UI is cleaned up.*/
++ UIActivate(SVUIA_DEACTIVATE);
++
++ if (hMenu)
++ {
++ DestroyMenu(hMenu);
++ }
++
++ DestroyWindow();
++ pShellBrowser.Release();
++ pCommDlgBrowser.Release();
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDefView::GetCurrentInfo(LPFOLDERSETTINGS lpfs)
++{
++ TRACE("(%p)->(%p) vmode=%x flags=%x\n",this, lpfs,
++ FolderSettings.ViewMode, FolderSettings.fFlags);
++
++ if (!lpfs)
++ return E_INVALIDARG;
++
++ *lpfs = FolderSettings;
++ return NOERROR;
++}
++
++HRESULT WINAPI CDefView::AddPropertySheetPages(DWORD dwReserved,LPFNADDPROPSHEETPAGE lpfn, LPARAM lparam)
++{
++ FIXME("(%p) stub\n",this);
++
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDefView::SaveViewState()
++{
++ FIXME("(%p) stub\n",this);
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDefView::SelectItem(LPCITEMIDLIST pidl, UINT uFlags)
++{
++ int i;
++
++ TRACE("(%p)->(pidl=%p, 0x%08x) stub\n",this, pidl, uFlags);
++
++ i = LV_FindItemByPidl(pidl);
++
++ if (i != -1)
++ {
++ LVITEMW lvItem;
++
++ if(uFlags & SVSI_ENSUREVISIBLE)
++ SendMessageW(hWndList, LVM_ENSUREVISIBLE, i, 0);
++
++ lvItem.mask = LVIF_STATE;
++ lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
++ lvItem.iItem = 0;
++ lvItem.iSubItem = 0;
++
++ while (SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem))
++ {
++ if (lvItem.iItem == i)
++ {
++ if (uFlags & SVSI_SELECT)
++ lvItem.state |= LVIS_SELECTED;
++ else
++ lvItem.state &= ~LVIS_SELECTED;
++
++ if (uFlags & SVSI_FOCUSED)
++ lvItem.state &= ~LVIS_FOCUSED;
++ }
++ else
++ {
++ if (uFlags & SVSI_DESELECTOTHERS)
++ lvItem.state &= ~LVIS_SELECTED;
++ }
++
++ SendMessageW(hWndList, LVM_SETITEMW, 0, (LPARAM) &lvItem);
++ lvItem.iItem++;
++ }
++
++
++ if(uFlags & SVSI_EDIT)
++ SendMessageW(hWndList, LVM_EDITLABELW, i, 0);
++ }
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDefView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppvOut)
++{
++ HRESULT hr = E_FAIL;
++
++ TRACE("(%p)->(uItem=0x%08x,\n\tIID=%s, ppv=%p)\n",this, uItem, debugstr_guid(&riid), ppvOut);
++
++ *ppvOut = NULL;
++
++ switch (uItem)
++ {
++ case SVGIO_BACKGROUND:
++ if (IsEqualIID(riid, IID_IContextMenu))
++ {
++ //*ppvOut = ISvBgCm_Constructor(pSFParent, FALSE);
++ CDefFolderMenu_Create2(NULL, NULL, cidl, (LPCITEMIDLIST*)apidl, pSFParent, NULL, 0, NULL, (IContextMenu**)ppvOut);
++ if (!ppvOut)
++ hr = E_OUTOFMEMORY;
++ }
++ break;
++
++ case SVGIO_SELECTION:
++ GetSelections();
++ hr = pSFParent->GetUIObjectOf(m_hWnd, cidl, (LPCITEMIDLIST*)apidl, riid, 0, ppvOut);
++ break;
++ }
++
++ TRACE("-- (%p)->(interface=%p)\n",this, *ppvOut);
++
++ return hr;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::GetCurrentViewMode(UINT *pViewMode)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::SetCurrentViewMode(UINT ViewMode)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::GetFolder(REFIID riid, void **ppv)
++{
++ if (pSFParent == NULL)
++ return E_FAIL;
++
++ return pSFParent->QueryInterface(riid, ppv);
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::Item(int iItemIndex, LPITEMIDLIST *ppidl)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::ItemCount(UINT uFlags, int *pcItems)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::Items(UINT uFlags, REFIID riid, void **ppv)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::GetSelectionMarkedItem(int *piItem)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::GetFocusedItem(int *piItem)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::GetItemPosition(LPCITEMIDLIST pidl, POINT *ppt)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::GetSpacing(POINT *ppt)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::GetDefaultSpacing(POINT *ppt)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::GetAutoArrange()
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::SelectItem(int iItem, DWORD dwFlags)
++{
++ return E_NOTIMPL;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::SelectAndPositionItems(UINT cidl, LPCITEMIDLIST *apidl, POINT *apt, DWORD dwFlags)
++{
++ return E_NOTIMPL;
++}
++
++/**********************************************************
++ * ISVOleCmdTarget_QueryStatus (IOleCommandTarget)
++ */
++HRESULT WINAPI CDefView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText)
++{
++ FIXME("(%p)->(%p(%s) 0x%08x %p %p\n",
++ this, pguidCmdGroup, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
++
++ if (!prgCmds)
++ return E_POINTER;
++
++ for (UINT i=0; i < cCmds; i++)
++ {
++ FIXME("\tprgCmds[%d].cmdID = %d\n", i, prgCmds[i].cmdID);
++ prgCmds[i].cmdf = 0;
++ }
++
++ return OLECMDERR_E_UNKNOWNGROUP;
++}
++
++/**********************************************************
++ * ISVOleCmdTarget_Exec (IOleCommandTarget)
++ *
++ * nCmdID is the OLECMDID_* enumeration
++ */
++HRESULT WINAPI CDefView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
++{
++ FIXME("(%p)->(\n\tTarget GUID:%s Command:0x%08x Opt:0x%08x %p %p)\n",
++ this, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt, pvaIn, pvaOut);
++
++ if (IsEqualIID(*pguidCmdGroup, CGID_Explorer) &&
++ (nCmdID == 0x29) &&
++ (nCmdexecopt == 4) && pvaOut)
++ return S_OK;
++
++ if (IsEqualIID(*pguidCmdGroup, CGID_ShellDocView) &&
++ (nCmdID == 9) &&
++ (nCmdexecopt == 0))
++ return 1;
++
++ return OLECMDERR_E_UNKNOWNGROUP;
++}
++
++/**********************************************************
++ * ISVDropTarget implementation
++ */
++
++/******************************************************************************
++ * drag_notify_subitem [Internal]
++ *
++ * Figure out the shellfolder object, which is currently under the mouse cursor
++ * and notify it via the IDropTarget interface.
++ */
++
++#define SCROLLAREAWIDTH 20
++
++HRESULT CDefView::drag_notify_subitem(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
++{
++ LVHITTESTINFO htinfo;
++ LVITEMW lvItem;
++ LONG lResult;
++ HRESULT hr;
++ RECT clientRect;
++
++ /* Map from global to client coordinates and query the index of the listview-item, which is
++ * currently under the mouse cursor. */
++ htinfo.pt.x = pt.x;
++ htinfo.pt.y = pt.y;
++ htinfo.flags = LVHT_ONITEM;
++ ::ScreenToClient(hWndList, &htinfo.pt);
++ lResult = SendMessageW(hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo);
++
++ /* Send WM_*SCROLL messages every 250 ms during drag-scrolling */
++ ::GetClientRect(hWndList, &clientRect);
++ if (htinfo.pt.x == ptLastMousePos.x && htinfo.pt.y == ptLastMousePos.y &&
++ (htinfo.pt.x < SCROLLAREAWIDTH || htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH ||
++ htinfo.pt.y < SCROLLAREAWIDTH || htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH ))
++ {
++ cScrollDelay = (cScrollDelay + 1) % 5; /* DragOver is called every 50 ms */
++ if (cScrollDelay == 0)
++ {
++ /* Mouse did hover another 250 ms over the scroll-area */
++ if (htinfo.pt.x < SCROLLAREAWIDTH)
++ SendMessageW(hWndList, WM_HSCROLL, SB_LINEUP, 0);
++
++ if (htinfo.pt.x > clientRect.right - SCROLLAREAWIDTH)
++ SendMessageW(hWndList, WM_HSCROLL, SB_LINEDOWN, 0);
++
++ if (htinfo.pt.y < SCROLLAREAWIDTH)
++ SendMessageW(hWndList, WM_VSCROLL, SB_LINEUP, 0);
++
++ if (htinfo.pt.y > clientRect.bottom - SCROLLAREAWIDTH)
++ SendMessageW(hWndList, WM_VSCROLL, SB_LINEDOWN, 0);
++ }
++ }
++ else
++ {
++ cScrollDelay = 0; /* Reset, if the cursor is not over the listview's scroll-area */
++ }
++
++ ptLastMousePos = htinfo.pt;
++
++ /* If we are still over the previous sub-item, notify it via DragOver and return. */
++ if (pCurDropTarget && lResult == iDragOverItem)
++ return pCurDropTarget->DragOver(grfKeyState, pt, pdwEffect);
++
++ /* We've left the previous sub-item, notify it via DragLeave and Release it. */
++ if (pCurDropTarget)
++ {
++ pCurDropTarget->DragLeave();
++ pCurDropTarget.Release();
++ }
++
++ iDragOverItem = lResult;
++ if (lResult == -1)
++ {
++ /* We are not above one of the listview's subitems. Bind to the parent folder's
++ * DropTarget interface. */
++ hr = pSFParent->QueryInterface(IID_IDropTarget,
++ (LPVOID*)&pCurDropTarget);
++ }
++ else
++ {
++ /* Query the relative PIDL of the shellfolder object represented by the currently
++ * dragged over listview-item ... */
++ lvItem.mask = LVIF_PARAM;
++ lvItem.iItem = lResult;
++ lvItem.iSubItem = 0;
++ SendMessageW(hWndList, LVM_GETITEMW, 0, (LPARAM) &lvItem);
++
++ /* ... and bind pCurDropTarget to the IDropTarget interface of an UIObject of this object */
++ hr = pSFParent->GetUIObjectOf(hWndList, 1,
++ (LPCITEMIDLIST*)&lvItem.lParam, IID_IDropTarget, NULL, (LPVOID*)&pCurDropTarget);
++ }
++
++ /* If anything failed, pCurDropTarget should be NULL now, which ought to be a save state. */
++ if (FAILED(hr))
++ return hr;
++
++ /* Notify the item just entered via DragEnter. */
++ return pCurDropTarget->DragEnter(pCurDataObject, grfKeyState, pt, pdwEffect);
++}
++
++HRESULT WINAPI CDefView::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
++{
++ /* Get a hold on the data object for later calls to DragEnter on the sub-folders */
++ pCurDataObject = pDataObject;
++ pDataObject->AddRef();
++
++ return drag_notify_subitem(grfKeyState, pt, pdwEffect);
++}
++
++HRESULT WINAPI CDefView::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
++{
++ return drag_notify_subitem(grfKeyState, pt, pdwEffect);
++}
++
++HRESULT WINAPI CDefView::DragLeave()
++{
++ if (pCurDropTarget)
++ {
++ pCurDropTarget->DragLeave();
++ pCurDropTarget.Release();
++ }
++
++ if (pCurDataObject != NULL)
++ {
++ pCurDataObject.Release();
++ }
++
++ iDragOverItem = 0;
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDefView::Drop(IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
++{
++ if (pCurDropTarget)
++ {
++ pCurDropTarget->Drop(pDataObject, grfKeyState, pt, pdwEffect);
++ pCurDropTarget.Release();
++ }
++
++ pCurDataObject.Release();
++ iDragOverItem = 0;
++
++ return S_OK;
++}
++
++/**********************************************************
++ * ISVDropSource implementation
++ */
++
++HRESULT WINAPI CDefView::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
++{
++ TRACE("(%p)\n",this);
++
++ if (fEscapePressed)
++ return DRAGDROP_S_CANCEL;
++ else if (!(grfKeyState & MK_LBUTTON) && !(grfKeyState & MK_RBUTTON))
++ return DRAGDROP_S_DROP;
++ else
++ return NOERROR;
++}
++
++HRESULT WINAPI CDefView::GiveFeedback(DWORD dwEffect)
++{
++ TRACE("(%p)\n",this);
++
++ return DRAGDROP_S_USEDEFAULTCURSORS;
++}
++
++/**********************************************************
++ * ISVViewObject implementation
++ */
++
++HRESULT WINAPI CDefView::Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds, BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue), ULONG_PTR dwContinue)
++{
++ FIXME("Stub: this=%p\n",this);
++
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDefView::GetColorSet(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDevice, LOGPALETTE **ppColorSet)
++{
++ FIXME("Stub: this=%p\n",this);
++
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDefView::Freeze(DWORD dwDrawAspect, LONG lindex, void *pvAspect, DWORD *pdwFreeze)
++{
++ FIXME("Stub: this=%p\n",this);
++
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDefView::Unfreeze(DWORD dwFreeze)
++{
++ FIXME("Stub: this=%p\n",this);
++
++ return E_NOTIMPL;
++}
++
++HRESULT WINAPI CDefView::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink *pAdvSink)
++{
++ FIXME("partial stub: %p %08x %08x %p\n", this, aspects, advf, pAdvSink);
++
++ /* FIXME: we set the AdviseSink, but never use it to send any advice */
++ pAdvSink = pAdvSink;
++ dwAspects = aspects;
++ dwAdvf = advf;
++
++ return S_OK;
++}
++
++HRESULT WINAPI CDefView::GetAdvise(DWORD *pAspects, DWORD *pAdvf, IAdviseSink **ppAdvSink)
++{
++ TRACE("this=%p pAspects=%p pAdvf=%p ppAdvSink=%p\n", this, pAspects, pAdvf, ppAdvSink);
++
++ if (ppAdvSink)
++ {
++ *ppAdvSink = pAdvSink;
++ pAdvSink.p->AddRef();
++ }
++
++ if (pAspects)
++ *pAspects = dwAspects;
++
++ if (pAdvf)
++ *pAdvf = dwAdvf;
++
++ return S_OK;
++}
++
++HRESULT STDMETHODCALLTYPE CDefView::QueryService(REFGUID guidService, REFIID riid, void **ppvObject)
++{
++ if (IsEqualIID(guidService, SID_IShellBrowser))
++ return pShellBrowser->QueryInterface(riid, ppvObject);
++ return E_NOINTERFACE;
++}
++
++/**********************************************************
++ * IShellView_Constructor
++ */
++HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView)
++{
++ CComObject<CDefView> *theView;
++ CComPtr<IShellView> result;
++ HRESULT hResult;
++
++ if (newView == NULL)
++ return E_POINTER;
++
++ *newView = NULL;
++ ATLTRY (theView = new CComObject<CDefView>);
++
++ if (theView == NULL)
++ return E_OUTOFMEMORY;
++
++ hResult = theView->QueryInterface (IID_IShellView, (void **)&result);
++ if (FAILED (hResult))
++ {
++ delete theView;
++ return hResult;
++ }
++
++ hResult = theView->Initialize (pFolder);
++ if (FAILED (hResult))
++ return hResult;
++ *newView = result.Detach ();
++
++ return S_OK;
++}
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
--- /dev/null
- void WINAPI IUnknown_Set(IUnknown **ppunk, IUnknown *punk);
- void WINAPI IUnknown_AtomicRelease(IUnknown **punk);
- HRESULT WINAPI IUnknown_GetWindow(IUnknown *punk, HWND *phwnd);
+/*
+ * SHLWAPI.DLL functions
+ *
+ * Copyright (C) 2000 Juergen Schmied
+ *
+ * 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
+ */
+
+#ifndef __WINE_SHLWAPI_H
+#define __WINE_SHLWAPI_H
+
+/* FIXME: #include <specstrings.h> */
+#include <objbase.h>
+#include <shtypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* defined(__cplusplus) */
+
+#include <pshpack8.h>
+
+#ifndef NO_SHLWAPI_REG
+
+/* Registry functions */
+
+DWORD WINAPI SHDeleteEmptyKeyA(HKEY,LPCSTR);
+DWORD WINAPI SHDeleteEmptyKeyW(HKEY,LPCWSTR);
+#define SHDeleteEmptyKey WINELIB_NAME_AW(SHDeleteEmptyKey)
+
+DWORD WINAPI SHDeleteKeyA(HKEY,LPCSTR);
+DWORD WINAPI SHDeleteKeyW(HKEY,LPCWSTR);
+#define SHDeleteKey WINELIB_NAME_AW(SHDeleteKey)
+
+DWORD WINAPI SHDeleteValueA(HKEY,LPCSTR,LPCSTR);
+DWORD WINAPI SHDeleteValueW(HKEY,LPCWSTR,LPCWSTR);
+#define SHDeleteValue WINELIB_NAME_AW(SHDeleteValue)
+
+DWORD WINAPI SHGetValueA(HKEY,LPCSTR,LPCSTR,LPDWORD,LPVOID,LPDWORD);
+DWORD WINAPI SHGetValueW(HKEY,LPCWSTR,LPCWSTR,LPDWORD,LPVOID,LPDWORD);
+#define SHGetValue WINELIB_NAME_AW(SHGetValue)
+
+DWORD WINAPI SHSetValueA(HKEY,LPCSTR,LPCSTR,DWORD,LPCVOID,DWORD);
+DWORD WINAPI SHSetValueW(HKEY,LPCWSTR,LPCWSTR,DWORD,LPCVOID,DWORD);
+#define SHSetValue WINELIB_NAME_AW(SHSetValue)
+
+DWORD WINAPI SHQueryValueExA(HKEY,LPCSTR,LPDWORD,LPDWORD,LPVOID,LPDWORD);
+DWORD WINAPI SHQueryValueExW(HKEY,LPCWSTR,LPDWORD,LPDWORD,LPVOID,LPDWORD);
+#define SHQueryValueEx WINELIB_NAME_AW(SHQueryValueEx)
+
+LONG WINAPI SHEnumKeyExA(HKEY,DWORD,LPSTR,LPDWORD);
+LONG WINAPI SHEnumKeyExW(HKEY,DWORD,LPWSTR,LPDWORD);
+#define SHEnumKeyEx WINELIB_NAME_AW(SHEnumKeyEx)
+
+LONG WINAPI SHEnumValueA(HKEY,DWORD,LPSTR,LPDWORD,LPDWORD,LPVOID,LPDWORD);
+LONG WINAPI SHEnumValueW(HKEY,DWORD,LPWSTR,LPDWORD,LPDWORD,LPVOID,LPDWORD);
+#define SHEnumValue WINELIB_NAME_AW(SHEnumValue)
+
+LONG WINAPI SHQueryInfoKeyA(HKEY,LPDWORD,LPDWORD,LPDWORD,LPDWORD);
+LONG WINAPI SHQueryInfoKeyW(HKEY,LPDWORD,LPDWORD,LPDWORD,LPDWORD);
+#define SHQueryInfoKey WINELIB_NAME_AW(SHQueryInfoKey)
+
+DWORD WINAPI SHRegGetPathA(HKEY,LPCSTR,LPCSTR,LPSTR,DWORD);
+DWORD WINAPI SHRegGetPathW(HKEY,LPCWSTR,LPCWSTR,LPWSTR,DWORD);
+#define SHRegGetPath WINELIB_NAME_AW(SHRegGetPath)
+
+DWORD WINAPI SHRegSetPathA(HKEY,LPCSTR,LPCSTR,LPCSTR,DWORD);
+DWORD WINAPI SHRegSetPathW(HKEY,LPCWSTR,LPCWSTR,LPCWSTR,DWORD);
+#define SHRegSetPath WINELIB_NAME_AW(SHRegSetPath)
+
+DWORD WINAPI SHCopyKeyA(HKEY,LPCSTR,HKEY,DWORD);
+DWORD WINAPI SHCopyKeyW(HKEY,LPCWSTR,HKEY,DWORD);
+#define SHCopyKey WINELIB_NAME_AW(SHCopyKey)
+
+HKEY WINAPI SHRegDuplicateHKey(HKEY);
+
+/* SHRegGetValue flags */
+typedef INT SRRF;
+
+#define SRRF_RT_REG_NONE 0x1
+#define SRRF_RT_REG_SZ 0x2
+#define SRRF_RT_REG_EXPAND_SZ 0x4
+#define SRRF_RT_REG_BINARY 0x8
+#define SRRF_RT_REG_DWORD 0x10
+#define SRRF_RT_REG_MULTI_SZ 0x20
+#define SRRF_RT_REG_QWORD 0x40
+
+#define SRRF_RT_DWORD (SRRF_RT_REG_BINARY|SRRF_RT_REG_DWORD)
+#define SRRF_RT_QWORD (SRRF_RT_REG_BINARY|SRRF_RT_REG_QWORD)
+#define SRRF_RT_ANY 0xffff
+
+#define SRRF_RM_ANY 0
+#define SRRF_RM_NORMAL 0x10000
+#define SRRF_RM_SAFE 0x20000
+#define SRRF_RM_SAFENETWORK 0x40000
+
+#define SRRF_NOEXPAND 0x10000000
+#define SRRF_ZEROONFAILURE 0x20000000
+#define SRRF_NOVIRT 0x40000000
+
+LSTATUS WINAPI SHRegGetValueA(HKEY,LPCSTR,LPCSTR,SRRF,LPDWORD,LPVOID,LPDWORD);
+LSTATUS WINAPI SHRegGetValueW(HKEY,LPCWSTR,LPCWSTR,SRRF,LPDWORD,LPVOID,LPDWORD);
+#define SHRegGetValue WINELIB_NAME_AW(SHRegGetValue)
+
+/* Undocumented registry functions */
+
+DWORD WINAPI SHDeleteOrphanKeyA(HKEY,LPCSTR);
+DWORD WINAPI SHDeleteOrphanKeyW(HKEY,LPCWSTR);
+#define SHDeleteOrphanKey WINELIB_NAME_AW(SHDeleteOrphanKey)
+
+
+/* User registry functions */
+
+typedef enum
+{
+ SHREGDEL_DEFAULT = 0,
+ SHREGDEL_HKCU = 0x1,
+ SHREGDEL_HKLM = 0x10,
+ SHREGDEL_BOTH = SHREGDEL_HKLM | SHREGDEL_HKCU
+} SHREGDEL_FLAGS;
+
+typedef enum
+{
+ SHREGENUM_DEFAULT = 0,
+ SHREGENUM_HKCU = 0x1,
+ SHREGENUM_HKLM = 0x10,
+ SHREGENUM_BOTH = SHREGENUM_HKLM | SHREGENUM_HKCU
+} SHREGENUM_FLAGS;
+
+#define SHREGSET_HKCU 0x1 /* Apply to HKCU if empty */
+#define SHREGSET_FORCE_HKCU 0x2 /* Always apply to HKCU */
+#define SHREGSET_HKLM 0x4 /* Apply to HKLM if empty */
+#define SHREGSET_FORCE_HKLM 0x8 /* Always apply to HKLM */
+#define SHREGSET_DEFAULT (SHREGSET_FORCE_HKCU | SHREGSET_HKLM)
+
+typedef HANDLE HUSKEY;
+typedef HUSKEY *PHUSKEY;
+
+LONG WINAPI SHRegCreateUSKeyA(LPCSTR,REGSAM,HUSKEY,PHUSKEY,DWORD);
+LONG WINAPI SHRegCreateUSKeyW(LPCWSTR,REGSAM,HUSKEY,PHUSKEY,DWORD);
+#define SHRegCreateUSKey WINELIB_NAME_AW(SHRegCreateUSKey)
+
+LONG WINAPI SHRegOpenUSKeyA(LPCSTR,REGSAM,HUSKEY,PHUSKEY,BOOL);
+LONG WINAPI SHRegOpenUSKeyW(LPCWSTR,REGSAM,HUSKEY,PHUSKEY,BOOL);
+#define SHRegOpenUSKey WINELIB_NAME_AW(SHRegOpenUSKey)
+
+LONG WINAPI SHRegQueryUSValueA(HUSKEY,LPCSTR,LPDWORD,LPVOID,LPDWORD,
+ BOOL,LPVOID,DWORD);
+LONG WINAPI SHRegQueryUSValueW(HUSKEY,LPCWSTR,LPDWORD,LPVOID,LPDWORD,
+ BOOL,LPVOID,DWORD);
+#define SHRegQueryUSValue WINELIB_NAME_AW(SHRegQueryUSValue)
+
+LONG WINAPI SHRegWriteUSValueA(HUSKEY,LPCSTR,DWORD,LPVOID,DWORD,DWORD);
+LONG WINAPI SHRegWriteUSValueW(HUSKEY,LPCWSTR,DWORD,LPVOID,DWORD,DWORD);
+#define SHRegWriteUSValue WINELIB_NAME_AW(SHRegWriteUSValue)
+
+LONG WINAPI SHRegDeleteUSValueA(HUSKEY,LPCSTR,SHREGDEL_FLAGS);
+LONG WINAPI SHRegDeleteUSValueW(HUSKEY,LPCWSTR,SHREGDEL_FLAGS);
+#define SHRegDeleteUSValue WINELIB_NAME_AW(SHRegDeleteUSValue)
+
+LONG WINAPI SHRegDeleteEmptyUSKeyA(HUSKEY,LPCSTR,SHREGDEL_FLAGS);
+LONG WINAPI SHRegDeleteEmptyUSKeyW(HUSKEY,LPCWSTR,SHREGDEL_FLAGS);
+#define SHRegDeleteEmptyUSKey WINELIB_NAME_AW(SHRegDeleteEmptyUSKey)
+
+LONG WINAPI SHRegEnumUSKeyA(HUSKEY,DWORD,LPSTR,LPDWORD,SHREGENUM_FLAGS);
+LONG WINAPI SHRegEnumUSKeyW(HUSKEY,DWORD,LPWSTR,LPDWORD,SHREGENUM_FLAGS);
+#define SHRegEnumUSKey WINELIB_NAME_AW(SHRegEnumUSKey)
+
+LONG WINAPI SHRegEnumUSValueA(HUSKEY,DWORD,LPSTR,LPDWORD,LPDWORD,
+ LPVOID,LPDWORD,SHREGENUM_FLAGS);
+LONG WINAPI SHRegEnumUSValueW(HUSKEY,DWORD,LPWSTR,LPDWORD,LPDWORD,
+ LPVOID,LPDWORD,SHREGENUM_FLAGS);
+#define SHRegEnumUSValue WINELIB_NAME_AW(SHRegEnumUSValue)
+
+LONG WINAPI SHRegQueryInfoUSKeyA(HUSKEY,LPDWORD,LPDWORD,LPDWORD,
+ LPDWORD,SHREGENUM_FLAGS);
+LONG WINAPI SHRegQueryInfoUSKeyW(HUSKEY,LPDWORD,LPDWORD,LPDWORD,
+ LPDWORD,SHREGENUM_FLAGS);
+#define SHRegQueryInfoUSKey WINELIB_NAME_AW(SHRegQueryInfoUSKey)
+
+LONG WINAPI SHRegCloseUSKey(HUSKEY);
+
+LONG WINAPI SHRegGetUSValueA(LPCSTR,LPCSTR,LPDWORD,LPVOID,LPDWORD,
+ BOOL,LPVOID,DWORD);
+LONG WINAPI SHRegGetUSValueW(LPCWSTR,LPCWSTR,LPDWORD,LPVOID,LPDWORD,
+ BOOL,LPVOID,DWORD);
+#define SHRegGetUSValue WINELIB_NAME_AW(SHRegGetUSValue)
+
+LONG WINAPI SHRegSetUSValueA(LPCSTR,LPCSTR,DWORD,LPVOID,DWORD,DWORD);
+LONG WINAPI SHRegSetUSValueW(LPCWSTR,LPCWSTR,DWORD,LPVOID,DWORD,DWORD);
+#define SHRegSetUSValue WINELIB_NAME_AW(SHRegSetUSValue)
+
+BOOL WINAPI SHRegGetBoolUSValueA(LPCSTR,LPCSTR,BOOL,BOOL);
+BOOL WINAPI SHRegGetBoolUSValueW(LPCWSTR,LPCWSTR,BOOL,BOOL);
+#define SHRegGetBoolUSValue WINELIB_NAME_AW(SHRegGetBoolUSValue)
+
+int WINAPI SHRegGetIntW(HKEY,LPCWSTR,int);
+
+/* IQueryAssociation and helpers */
+enum
+{
+ ASSOCF_INIT_NOREMAPCLSID = 0x001, /* Don't map clsid->progid */
+ ASSOCF_INIT_BYEXENAME = 0x002, /* .exe name given */
+ ASSOCF_OPEN_BYEXENAME = 0x002, /* Synonym */
+ ASSOCF_INIT_DEFAULTTOSTAR = 0x004, /* Use * as base */
+ ASSOCF_INIT_DEFAULTTOFOLDER = 0x008, /* Use folder as base */
+ ASSOCF_NOUSERSETTINGS = 0x010, /* No HKCU reads */
+ ASSOCF_NOTRUNCATE = 0x020, /* Don't truncate return */
+ ASSOCF_VERIFY = 0x040, /* Verify data */
+ ASSOCF_REMAPRUNDLL = 0x080, /* Get rundll args */
+ ASSOCF_NOFIXUPS = 0x100, /* Don't fixup errors */
+ ASSOCF_IGNOREBASECLASS = 0x200, /* Don't read baseclass */
+ ASSOCF_INIT_IGNOREUNKNOWN = 0x400, /* Fail for unknown progid */
+};
+
+typedef DWORD ASSOCF;
+
+typedef enum
+{
+ ASSOCSTR_COMMAND = 1, /* Verb command */
+ ASSOCSTR_EXECUTABLE, /* .exe from command string */
+ ASSOCSTR_FRIENDLYDOCNAME, /* Friendly doc type name */
+ ASSOCSTR_FRIENDLYAPPNAME, /* Friendly .exe name */
+ ASSOCSTR_NOOPEN, /* noopen value */
+ ASSOCSTR_SHELLNEWVALUE, /* Use shellnew key */
+ ASSOCSTR_DDECOMMAND, /* DDE command template */
+ ASSOCSTR_DDEIFEXEC, /* DDE command for process create */
+ ASSOCSTR_DDEAPPLICATION, /* DDE app name */
+ ASSOCSTR_DDETOPIC, /* DDE topic */
+ ASSOCSTR_INFOTIP, /* Infotip */
+ ASSOCSTR_QUICKTIP, /* Quick infotip */
+ ASSOCSTR_TILEINFO, /* Properties for tileview */
+ ASSOCSTR_CONTENTTYPE, /* Mimetype */
+ ASSOCSTR_DEFAULTICON, /* Icon */
+ ASSOCSTR_SHELLEXTENSION, /* GUID for shell extension handler */
+ ASSOCSTR_MAX
+} ASSOCSTR;
+
+typedef enum
+{
+ ASSOCKEY_SHELLEXECCLASS = 1, /* Key for ShellExec */
+ ASSOCKEY_APP, /* Application */
+ ASSOCKEY_CLASS, /* Progid or class */
+ ASSOCKEY_BASECLASS, /* Base class */
+ ASSOCKEY_MAX
+} ASSOCKEY;
+
+typedef enum
+{
+ ASSOCDATA_MSIDESCRIPTOR = 1, /* Component descriptor */
+ ASSOCDATA_NOACTIVATEHANDLER, /* Don't activate */
+ ASSOCDATA_QUERYCLASSSTORE, /* Look in Class Store */
+ ASSOCDATA_HASPERUSERASSOC, /* Use user association */
+ ASSOCDATA_EDITFLAGS, /* Edit flags */
+ ASSOCDATA_VALUE, /* pszExtra is value */
+ ASSOCDATA_MAX
+} ASSOCDATA;
+
+typedef enum
+{
+ ASSOCENUM_NONE
+} ASSOCENUM;
+
+typedef struct IQueryAssociations *LPQUERYASSOCIATIONS;
+
+#define INTERFACE IQueryAssociations
+DECLARE_INTERFACE_(IQueryAssociations,IUnknown)
+{
+ /*** IUnknown methods ***/
+ STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
+ STDMETHOD_(ULONG,AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG,Release)(THIS) PURE;
+ /*** IQueryAssociations methods ***/
+ STDMETHOD(Init)(THIS_ ASSOCF flags, LPCWSTR pszAssoc, HKEY hkProgid, HWND hwnd) PURE;
+ STDMETHOD(GetString)(THIS_ ASSOCF flags, ASSOCSTR str, LPCWSTR pszExtra, LPWSTR pszOut, DWORD * pcchOut) PURE;
+ STDMETHOD(GetKey)(THIS_ ASSOCF flags, ASSOCKEY key, LPCWSTR pszExtra, HKEY * phkeyOut) PURE;
+ STDMETHOD(GetData)(THIS_ ASSOCF flags, ASSOCDATA data, LPCWSTR pszExtra, LPVOID pvOut, DWORD * pcbOut) PURE;
+ STDMETHOD(GetEnum)(THIS_ ASSOCF flags, ASSOCENUM assocenum, LPCWSTR pszExtra, REFIID riid, LPVOID * ppvOut) PURE;
+};
+#undef INTERFACE
+
+#if !defined(__cplusplus) || defined(CINTERFACE)
+#define IQueryAssociations_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
+#define IQueryAssociations_AddRef(p) (p)->lpVtbl->AddRef(p)
+#define IQueryAssociations_Release(p) (p)->lpVtbl->Release(p)
+#define IQueryAssociations_Init(p,a,b,c,d) (p)->lpVtbl->Init(p,a,b,c,d)
+#define IQueryAssociations_GetString(p,a,b,c,d,e) (p)->lpVtbl->GetString(p,a,b,c,d,e)
+#define IQueryAssociations_GetKey(p,a,b,c,d) (p)->lpVtbl->GetKey(p,a,b,c,d)
+#define IQueryAssociations_GetData(p,a,b,c,d,e) (p)->lpVtbl->GetData(p,a,b,c,d,e)
+#define IQueryAssociations_GetEnum(p,a,b,c,d,e) (p)->lpVtbl->GetEnum(p,a,b,c,d,e)
+#endif
+
+HRESULT WINAPI AssocCreate(CLSID,REFIID,LPVOID*);
+
+HRESULT WINAPI AssocQueryStringA(ASSOCF,ASSOCSTR,LPCSTR,LPCSTR,LPSTR,LPDWORD);
+HRESULT WINAPI AssocQueryStringW(ASSOCF,ASSOCSTR,LPCWSTR,LPCWSTR,LPWSTR,LPDWORD);
+#define AssocQueryString WINELIB_NAME_AW(AssocQueryString)
+
+HRESULT WINAPI AssocQueryStringByKeyA(ASSOCF,ASSOCSTR,HKEY,LPCSTR,LPSTR,LPDWORD);
+HRESULT WINAPI AssocQueryStringByKeyW(ASSOCF,ASSOCSTR,HKEY,LPCWSTR,LPWSTR,LPDWORD);
+#define AssocQueryStringByKey WINELIB_NAME_AW(AssocQueryStringByKey)
+
+HRESULT WINAPI AssocQueryKeyA(ASSOCF,ASSOCKEY,LPCSTR,LPCSTR,PHKEY);
+HRESULT WINAPI AssocQueryKeyW(ASSOCF,ASSOCKEY,LPCWSTR,LPCWSTR,PHKEY);
+#define AssocQueryKey WINELIB_NAME_AW(AssocQueryKey)
+
+BOOL WINAPI AssocIsDangerous(LPCWSTR);
+
+#endif /* NO_SHLWAPI_REG */
+
- HRESULT WINAPI IUnknown_GetSite(IUnknown *punk, REFIID riid, void **ppv);
+HRESULT WINAPI IUnknown_SetSite(IUnknown *punk, IUnknown *punkSite);
- LPWSTR WINAPI StrStrNW(LPCWSTR,LPCWSTR,UINT);
- LPWSTR WINAPI StrStrNIW(LPCWSTR,LPCWSTR,UINT);
-
+HRESULT WINAPI IUnknown_QueryService(IUnknown *punk, REFGUID guidService, REFIID riid, void **ppvOut);
+
+/* Path functions */
+#ifndef NO_SHLWAPI_PATH
+
+/* GetPathCharType return flags */
+#define GCT_INVALID 0x0
+#define GCT_LFNCHAR 0x1
+#define GCT_SHORTCHAR 0x2
+#define GCT_WILD 0x4
+#define GCT_SEPARATOR 0x8
+
+LPSTR WINAPI PathAddBackslashA(LPSTR);
+LPWSTR WINAPI PathAddBackslashW(LPWSTR);
+#define PathAddBackslash WINELIB_NAME_AW(PathAddBackslash)
+
+BOOL WINAPI PathAddExtensionA(LPSTR,LPCSTR);
+BOOL WINAPI PathAddExtensionW(LPWSTR,LPCWSTR);
+#define PathAddExtension WINELIB_NAME_AW(PathAddExtension)
+
+BOOL WINAPI PathAppendA(LPSTR,LPCSTR);
+BOOL WINAPI PathAppendW(LPWSTR,LPCWSTR);
+#define PathAppend WINELIB_NAME_AW(PathAppend)
+
+LPSTR WINAPI PathBuildRootA(LPSTR,int);
+LPWSTR WINAPI PathBuildRootW(LPWSTR,int);
+#define PathBuildRoot WINELIB_NAME_AW(PathBuiltRoot)
+
+BOOL WINAPI PathCanonicalizeA(LPSTR,LPCSTR);
+BOOL WINAPI PathCanonicalizeW(LPWSTR,LPCWSTR);
+#define PathCanonicalize WINELIB_NAME_AW(PathCanonicalize)
+
+LPSTR WINAPI PathCombineA(LPSTR,LPCSTR,LPCSTR);
+LPWSTR WINAPI PathCombineW(LPWSTR,LPCWSTR,LPCWSTR);
+#define PathCombine WINELIB_NAME_AW(PathCombine)
+
+BOOL WINAPI PathCompactPathA(HDC,LPSTR,UINT);
+BOOL WINAPI PathCompactPathW(HDC,LPWSTR,UINT);
+#define PathCompactPath WINELIB_NAME_AW(PathCompactPath)
+
+BOOL WINAPI PathCompactPathExA(LPSTR,LPCSTR,UINT,DWORD);
+BOOL WINAPI PathCompactPathExW(LPWSTR,LPCWSTR,UINT,DWORD);
+#define PathCompactPathEx WINELIB_NAME_AW(PathCompactPathEx)
+
+int WINAPI PathCommonPrefixA(LPCSTR,LPCSTR,LPSTR);
+int WINAPI PathCommonPrefixW(LPCWSTR,LPCWSTR,LPWSTR);
+#define PathCommonPrefix WINELIB_NAME_AW(PathCommonPrefix)
+
+HRESULT WINAPI PathCreateFromUrlA(LPCSTR pszUrl, LPSTR pszPath, LPDWORD pcchPath, DWORD dwReserved);
+HRESULT WINAPI PathCreateFromUrlW(LPCWSTR pszUrl, LPWSTR pszPath, LPDWORD pcchPath, DWORD dwReserved);
+#define PathCreateFromUrl WINELIB_NAME_AW(PathCreateFromUrl)
+
+BOOL WINAPI PathFileExistsA(LPCSTR);
+BOOL WINAPI PathFileExistsW(LPCWSTR);
+#define PathFileExists WINELIB_NAME_AW(PathFileExists)
+
+BOOL WINAPI PathFileExistsAndAttributesA(LPCSTR lpszPath, DWORD *dwAttr);
+BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr);
+#define PathFileExistsAndAttributes WINELIB_NAME_AW(PathFileExistsAndAttributes)
+
+LPSTR WINAPI PathFindExtensionA(LPCSTR);
+LPWSTR WINAPI PathFindExtensionW(LPCWSTR);
+#define PathFindExtension WINELIB_NAME_AW(PathFindExtension)
+
+LPSTR WINAPI PathFindFileNameA(LPCSTR);
+LPWSTR WINAPI PathFindFileNameW(LPCWSTR);
+#define PathFindFileName WINELIB_NAME_AW(PathFindFileName)
+
+LPSTR WINAPI PathFindNextComponentA(LPCSTR);
+LPWSTR WINAPI PathFindNextComponentW(LPCWSTR);
+#define PathFindNextComponent WINELIB_NAME_AW(PathFindNextComponent)
+
+BOOL WINAPI PathFindOnPathA(LPSTR,LPCSTR*);
+BOOL WINAPI PathFindOnPathW(LPWSTR,LPCWSTR*);
+#define PathFindOnPath WINELIB_NAME_AW(PathFindOnPath)
+
+LPSTR WINAPI PathGetArgsA(LPCSTR);
+LPWSTR WINAPI PathGetArgsW(LPCWSTR);
+#define PathGetArgs WINELIB_NAME_AW(PathGetArgs)
+
+UINT WINAPI PathGetCharTypeA(UCHAR);
+UINT WINAPI PathGetCharTypeW(WCHAR);
+#define PathGetCharType WINELIB_NAME_AW(PathGetCharType)
+
+int WINAPI PathGetDriveNumberA(LPCSTR);
+int WINAPI PathGetDriveNumberW(LPCWSTR);
+#define PathGetDriveNumber WINELIB_NAME_AW(PathGetDriveNumber)
+
+BOOL WINAPI PathIsDirectoryA(LPCSTR);
+BOOL WINAPI PathIsDirectoryW(LPCWSTR);
+#define PathIsDirectory WINELIB_NAME_AW(PathIsDirectory)
+
+BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR);
+BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR);
+#define PathIsDirectoryEmpty WINELIB_NAME_AW(PathIsDirectoryEmpty)
+
+BOOL WINAPI PathIsFileSpecA(LPCSTR);
+BOOL WINAPI PathIsFileSpecW(LPCWSTR);
+#define PathIsFileSpec WINELIB_NAME_AW(PathIsFileSpec);
+
+BOOL WINAPI PathIsPrefixA(LPCSTR,LPCSTR);
+BOOL WINAPI PathIsPrefixW(LPCWSTR,LPCWSTR);
+#define PathIsPrefix WINELIB_NAME_AW(PathIsPrefix)
+
+BOOL WINAPI PathIsRelativeA(LPCSTR);
+BOOL WINAPI PathIsRelativeW(LPCWSTR);
+#define PathIsRelative WINELIB_NAME_AW(PathIsRelative)
+
+BOOL WINAPI PathIsRootA(LPCSTR);
+BOOL WINAPI PathIsRootW(LPCWSTR);
+#define PathIsRoot WINELIB_NAME_AW(PathIsRoot)
+
+BOOL WINAPI PathIsSameRootA(LPCSTR,LPCSTR);
+BOOL WINAPI PathIsSameRootW(LPCWSTR,LPCWSTR);
+#define PathIsSameRoot WINELIB_NAME_AW(PathIsSameRoot)
+
+BOOL WINAPI PathIsUNCA(LPCSTR);
+BOOL WINAPI PathIsUNCW(LPCWSTR);
+#define PathIsUNC WINELIB_NAME_AW(PathIsUNC)
+
+BOOL WINAPI PathIsUNCServerA(LPCSTR);
+BOOL WINAPI PathIsUNCServerW(LPCWSTR);
+#define PathIsUNCServer WINELIB_NAME_AW(PathIsUNCServer)
+
+BOOL WINAPI PathIsUNCServerShareA(LPCSTR);
+BOOL WINAPI PathIsUNCServerShareW(LPCWSTR);
+#define PathIsUNCServerShare WINELIB_NAME_AW(PathIsUNCServerShare)
+
+BOOL WINAPI PathIsContentTypeA(LPCSTR,LPCSTR);
+BOOL WINAPI PathIsContentTypeW(LPCWSTR,LPCWSTR);
+#define PathIsContentType WINELIB_NAME_AW(PathIsContentType)
+
+BOOL WINAPI PathIsURLA(LPCSTR);
+BOOL WINAPI PathIsURLW(LPCWSTR);
+#define PathIsURL WINELIB_NAME_AW(PathIsURL)
+
+BOOL WINAPI PathMakePrettyA(LPSTR);
+BOOL WINAPI PathMakePrettyW(LPWSTR);
+#define PathMakePretty WINELIB_NAME_AW(PathMakePretty)
+
+BOOL WINAPI PathMatchSpecA(LPCSTR,LPCSTR);
+BOOL WINAPI PathMatchSpecW(LPCWSTR,LPCWSTR);
+#define PathMatchSpec WINELIB_NAME_AW(PathMatchSpec)
+
+int WINAPI PathParseIconLocationA(LPSTR);
+int WINAPI PathParseIconLocationW(LPWSTR);
+#define PathParseIconLocation WINELIB_NAME_AW(PathParseIconLocation)
+
+VOID WINAPI PathQuoteSpacesA(LPSTR);
+VOID WINAPI PathQuoteSpacesW(LPWSTR);
+#define PathQuoteSpaces WINELIB_NAME_AW(PathQuoteSpaces)
+
+BOOL WINAPI PathRelativePathToA(LPSTR,LPCSTR,DWORD,LPCSTR,DWORD);
+BOOL WINAPI PathRelativePathToW(LPWSTR,LPCWSTR,DWORD,LPCWSTR,DWORD);
+#define PathRelativePathTo WINELIB_NAME_AW(PathRelativePathTo)
+
+VOID WINAPI PathRemoveArgsA(LPSTR);
+VOID WINAPI PathRemoveArgsW(LPWSTR);
+#define PathRemoveArgs WINELIB_NAME_AW(PathRemoveArgs)
+
+LPSTR WINAPI PathRemoveBackslashA(LPSTR);
+LPWSTR WINAPI PathRemoveBackslashW(LPWSTR);
+#define PathRemoveBackslash WINELIB_NAME_AW(PathRemoveBackslash)
+
+VOID WINAPI PathRemoveBlanksA(LPSTR);
+VOID WINAPI PathRemoveBlanksW(LPWSTR);
+#define PathRemoveBlanks WINELIB_NAME_AW(PathRemoveBlanks)
+
+VOID WINAPI PathRemoveExtensionA(LPSTR);
+VOID WINAPI PathRemoveExtensionW(LPWSTR);
+#define PathRemoveExtension WINELIB_NAME_AW(PathRemoveExtension)
+
+BOOL WINAPI PathRemoveFileSpecA(LPSTR);
+BOOL WINAPI PathRemoveFileSpecW(LPWSTR);
+#define PathRemoveFileSpec WINELIB_NAME_AW(PathRemoveFileSpec)
+
+BOOL WINAPI PathRenameExtensionA(LPSTR,LPCSTR);
+BOOL WINAPI PathRenameExtensionW(LPWSTR,LPCWSTR);
+#define PathRenameExtension WINELIB_NAME_AW(PathRenameExtension)
+
+BOOL WINAPI PathSearchAndQualifyA(LPCSTR,LPSTR,UINT);
+BOOL WINAPI PathSearchAndQualifyW(LPCWSTR,LPWSTR,UINT);
+#define PathSearchAndQualify WINELIB_NAME_AW(PathSearchAndQualify)
+
+VOID WINAPI PathSetDlgItemPathA(HWND,int,LPCSTR);
+VOID WINAPI PathSetDlgItemPathW(HWND,int,LPCWSTR);
+#define PathSetDlgItemPath WINELIB_NAME_AW(PathSetDlgItemPath)
+
+LPSTR WINAPI PathSkipRootA(LPCSTR);
+LPWSTR WINAPI PathSkipRootW(LPCWSTR);
+#define PathSkipRoot WINELIB_NAME_AW(PathSkipRoot)
+
+VOID WINAPI PathStripPathA(LPSTR);
+VOID WINAPI PathStripPathW(LPWSTR);
+#define PathStripPath WINELIB_NAME_AW(PathStripPath)
+
+BOOL WINAPI PathStripToRootA(LPSTR);
+BOOL WINAPI PathStripToRootW(LPWSTR);
+#define PathStripToRoot WINELIB_NAME_AW(PathStripToRoot)
+
+VOID WINAPI PathUnquoteSpacesA(LPSTR);
+VOID WINAPI PathUnquoteSpacesW(LPWSTR);
+#define PathUnquoteSpaces WINELIB_NAME_AW(PathUnquoteSpaces)
+
+BOOL WINAPI PathMakeSystemFolderA(LPCSTR);
+BOOL WINAPI PathMakeSystemFolderW(LPCWSTR);
+#define PathMakeSystemFolder WINELIB_NAME_AW(PathMakeSystemFolder)
+
+BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR);
+BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR);
+#define PathUnmakeSystemFolder WINELIB_NAME_AW(PathUnmakeSystemFolder)
+
+BOOL WINAPI PathIsSystemFolderA(LPCSTR,DWORD);
+BOOL WINAPI PathIsSystemFolderW(LPCWSTR,DWORD);
+#define PathIsSystemFolder WINELIB_NAME_AW(PathIsSystemFolder)
+
+BOOL WINAPI PathIsNetworkPathA(LPCSTR);
+BOOL WINAPI PathIsNetworkPathW(LPCWSTR);
+#define PathIsNetworkPath WINELIB_NAME_AW(PathIsNetworkPath)
+
+BOOL WINAPI PathIsLFNFileSpecA(LPCSTR);
+BOOL WINAPI PathIsLFNFileSpecW(LPCWSTR);
+#define PathIsLFNFileSpec WINELIB_NAME_AW(PathIsLFNFileSpec)
+
+LPCSTR WINAPI PathFindSuffixArrayA(LPCSTR,LPCSTR *,int);
+LPCWSTR WINAPI PathFindSuffixArrayW(LPCWSTR,LPCWSTR *,int);
+#define PathFindSuffixArray WINELIB_NAME_AW(PathFindSuffixArray)
+
+VOID WINAPI PathUndecorateA(LPSTR);
+VOID WINAPI PathUndecorateW(LPWSTR);
+#define PathUndecorate WINELIB_NAME_AW(PathUndecorate)
+
+BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR,LPSTR,UINT);
+BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR,LPWSTR,UINT);
+#define PathUnExpandEnvStrings WINELIB_NAME_AW(PathUnExpandEnvStrings)
+
+/* Url functions */
+typedef enum {
+ URL_SCHEME_INVALID = -1,
+ URL_SCHEME_UNKNOWN = 0,
+ URL_SCHEME_FTP,
+ URL_SCHEME_HTTP,
+ URL_SCHEME_GOPHER,
+ URL_SCHEME_MAILTO,
+ URL_SCHEME_NEWS,
+ URL_SCHEME_NNTP,
+ URL_SCHEME_TELNET,
+ URL_SCHEME_WAIS,
+ URL_SCHEME_FILE,
+ URL_SCHEME_MK,
+ URL_SCHEME_HTTPS,
+ URL_SCHEME_SHELL,
+ URL_SCHEME_SNEWS,
+ URL_SCHEME_LOCAL,
+ URL_SCHEME_JAVASCRIPT,
+ URL_SCHEME_VBSCRIPT,
+ URL_SCHEME_ABOUT,
+ URL_SCHEME_RES,
+ URL_SCHEME_MSSHELLROOTED,
+ URL_SCHEME_MSSHELLIDLIST,
+ URL_SCHEME_MSHELP,
+ URL_SCHEME_MSSHELLDEVICE,
+ URL_SCHEME_WILDCARD,
+ URL_SCHEME_SEARCH_MS,
+ URL_SCHEME_SEARCH,
+ URL_SCHEME_KNOWNFOLDER,
+ URL_SCHEME_MAXVALUE
+} URL_SCHEME;
+
+/* These are used by UrlGetPart routine */
+typedef enum {
+ URL_PART_NONE = 0,
+ URL_PART_SCHEME = 1,
+ URL_PART_HOSTNAME,
+ URL_PART_USERNAME,
+ URL_PART_PASSWORD,
+ URL_PART_PORT,
+ URL_PART_QUERY
+} URL_PART;
+
+#define URL_PARTFLAG_KEEPSCHEME 0x00000001
+
+/* These are used by the UrlIs... routines */
+typedef enum {
+ URLIS_URL,
+ URLIS_OPAQUE,
+ URLIS_NOHISTORY,
+ URLIS_FILEURL,
+ URLIS_APPLIABLE,
+ URLIS_DIRECTORY,
+ URLIS_HASQUERY
+} URLIS;
+
+/* This is used by the UrlApplyScheme... routines */
+#define URL_APPLY_FORCEAPPLY 0x00000008
+#define URL_APPLY_GUESSFILE 0x00000004
+#define URL_APPLY_GUESSSCHEME 0x00000002
+#define URL_APPLY_DEFAULT 0x00000001
+
+/* The following are used by UrlEscape..., UrlUnEscape...,
+ * UrlCanonicalize..., and UrlCombine... routines
+ */
+#define URL_WININET_COMPATIBILITY 0x80000000
+#define URL_PLUGGABLE_PROTOCOL 0x40000000
+#define URL_ESCAPE_UNSAFE 0x20000000
+#define URL_UNESCAPE 0x10000000
+
+#define URL_DONT_SIMPLIFY 0x08000000
+#define URL_NO_META URL_DONT_SIMPLIFY
+#define URL_ESCAPE_SPACES_ONLY 0x04000000
+#define URL_DONT_ESCAPE_EXTRA_INFO 0x02000000
+#define URL_DONT_UNESCAPE_EXTRA_INFO URL_DONT_ESCAPE_EXTRA_INFO
+#define URL_BROWSER_MODE URL_DONT_ESCAPE_EXTRA_INFO
+
+#define URL_INTERNAL_PATH 0x00800000 /* Will escape #'s in paths */
+#define URL_UNESCAPE_HIGH_ANSI_ONLY 0x00400000
+#define URL_CONVERT_IF_DOSPATH 0x00200000
+#define URL_UNESCAPE_INPLACE 0x00100000
+
+#define URL_FILE_USE_PATHURL 0x00010000
+
+#define URL_ESCAPE_SEGMENT_ONLY 0x00002000
+#define URL_ESCAPE_PERCENT 0x00001000
+
+HRESULT WINAPI UrlApplySchemeA(LPCSTR,LPSTR,LPDWORD,DWORD);
+HRESULT WINAPI UrlApplySchemeW(LPCWSTR,LPWSTR,LPDWORD,DWORD);
+#define UrlApplyScheme WINELIB_NAME_AW(UrlApplyScheme)
+
+HRESULT WINAPI UrlCanonicalizeA(LPCSTR,LPSTR,LPDWORD,DWORD);
+HRESULT WINAPI UrlCanonicalizeW(LPCWSTR,LPWSTR,LPDWORD,DWORD);
+#define UrlCanonicalize WINELIB_NAME_AW(UrlCanonicalize)
+
+HRESULT WINAPI UrlCombineA(LPCSTR,LPCSTR,LPSTR,LPDWORD,DWORD);
+HRESULT WINAPI UrlCombineW(LPCWSTR,LPCWSTR,LPWSTR,LPDWORD,DWORD);
+#define UrlCombine WINELIB_NAME_AW(UrlCombine)
+
+INT WINAPI UrlCompareA(LPCSTR,LPCSTR,BOOL);
+INT WINAPI UrlCompareW(LPCWSTR,LPCWSTR,BOOL);
+#define UrlCompare WINELIB_NAME_AW(UrlCompare)
+
+HRESULT WINAPI UrlEscapeA(LPCSTR,LPSTR,LPDWORD,DWORD);
+HRESULT WINAPI UrlEscapeW(LPCWSTR,LPWSTR,LPDWORD,DWORD);
+#define UrlEscape WINELIB_NAME_AW(UrlEscape)
+
+#define UrlEscapeSpacesA(x,y,z) UrlCanonicalizeA(x, y, z, \
+ URL_DONT_ESCAPE_EXTRA_INFO|URL_ESCAPE_SPACES_ONLY)
+#define UrlEscapeSpacesW(x,y,z) UrlCanonicalizeW(x, y, z, \
+ URL_DONT_ESCAPE_EXTRA_INFO|URL_ESCAPE_SPACES_ONLY)
+#define UrlEscapeSpaces WINELIB_NAME_AW(UrlEscapeSpaces)
+
+LPCSTR WINAPI UrlGetLocationA(LPCSTR);
+LPCWSTR WINAPI UrlGetLocationW(LPCWSTR);
+#define UrlGetLocation WINELIB_NAME_AW(UrlGetLocation)
+
+HRESULT WINAPI UrlGetPartA(LPCSTR,LPSTR,LPDWORD,DWORD,DWORD);
+HRESULT WINAPI UrlGetPartW(LPCWSTR,LPWSTR,LPDWORD,DWORD,DWORD);
+#define UrlGetPart WINELIB_NAME_AW(UrlGetPart)
+
+HRESULT WINAPI HashData(const unsigned char *,DWORD,unsigned char *lpDest,DWORD);
+
+HRESULT WINAPI UrlHashA(LPCSTR,unsigned char *,DWORD);
+HRESULT WINAPI UrlHashW(LPCWSTR,unsigned char *,DWORD);
+#define UrlHash WINELIB_NAME_AW(UrlHash)
+
+BOOL WINAPI UrlIsA(LPCSTR,URLIS);
+BOOL WINAPI UrlIsW(LPCWSTR,URLIS);
+#define UrlIs WINELIB_NAME_AW(UrlIs)
+
+BOOL WINAPI UrlIsNoHistoryA(LPCSTR);
+BOOL WINAPI UrlIsNoHistoryW(LPCWSTR);
+#define UrlIsNoHistory WINELIB_NAME_AW(UrlIsNoHistory)
+
+BOOL WINAPI UrlIsOpaqueA(LPCSTR);
+BOOL WINAPI UrlIsOpaqueW(LPCWSTR);
+#define UrlIsOpaque WINELIB_NAME_AW(UrlIsOpaque)
+
+#define UrlIsFileUrlA(x) UrlIsA(x, URLIS_FILEURL)
+#define UrlIsFileUrlW(y) UrlIsW(x, URLIS_FILEURL)
+#define UrlIsFileUrl WINELIB_NAME_AW(UrlIsFileUrl)
+
+HRESULT WINAPI UrlUnescapeA(LPSTR,LPSTR,LPDWORD,DWORD);
+HRESULT WINAPI UrlUnescapeW(LPWSTR,LPWSTR,LPDWORD,DWORD);
+#define UrlUnescape WINELIB_NAME_AW(UrlUnescape)
+
+#define UrlUnescapeInPlaceA(x,y) UrlUnescapeA(x, NULL, NULL, \
+ y | URL_UNESCAPE_INPLACE)
+#define UrlUnescapeInPlaceW(x,y) UrlUnescapeW(x, NULL, NULL, \
+ y | URL_UNESCAPE_INPLACE)
+#define UrlUnescapeInPlace WINELIB_NAME_AW(UrlUnescapeInPlace)
+
+HRESULT WINAPI UrlCreateFromPathA(LPCSTR,LPSTR,LPDWORD,DWORD);
+HRESULT WINAPI UrlCreateFromPathW(LPCWSTR,LPWSTR,LPDWORD,DWORD);
+#define UrlCreateFromPath WINELIB_NAME_AW(UrlCreateFromPath)
+
+typedef struct tagPARSEDURLA {
+ DWORD cbSize;
+ LPCSTR pszProtocol;
+ UINT cchProtocol;
+ LPCSTR pszSuffix;
+ UINT cchSuffix;
+ UINT nScheme;
+} PARSEDURLA, *PPARSEDURLA;
+
+typedef struct tagPARSEDURLW {
+ DWORD cbSize;
+ LPCWSTR pszProtocol;
+ UINT cchProtocol;
+ LPCWSTR pszSuffix;
+ UINT cchSuffix;
+ UINT nScheme;
+} PARSEDURLW, *PPARSEDURLW;
+
+HRESULT WINAPI ParseURLA(LPCSTR pszUrl, PARSEDURLA *ppu);
+HRESULT WINAPI ParseURLW(LPCWSTR pszUrl, PARSEDURLW *ppu);
+#define ParseURL WINELIB_NAME_AW(ParseUrl)
+
+#endif /* NO_SHLWAPI_PATH */
+
+
+/* String functions */
+#ifndef NO_SHLWAPI_STRFCNS
+
+/* StrToIntEx flags */
+#define STIF_DEFAULT 0x0L
+#define STIF_SUPPORT_HEX 0x1L
+
+BOOL WINAPI ChrCmpIA (WORD,WORD);
+BOOL WINAPI ChrCmpIW (WCHAR,WCHAR);
+#define ChrCmpI WINELIB_NAME_AW(ChrCmpI)
+
+INT WINAPI StrCSpnA(LPCSTR,LPCSTR);
+INT WINAPI StrCSpnW(LPCWSTR,LPCWSTR);
+#define StrCSpn WINELIB_NAME_AW(StrCSpn)
+
+INT WINAPI StrCSpnIA(LPCSTR,LPCSTR);
+INT WINAPI StrCSpnIW(LPCWSTR,LPCWSTR);
+#define StrCSpnI WINELIB_NAME_AW(StrCSpnI)
+
+#define StrCatA lstrcatA
+LPWSTR WINAPI StrCatW(LPWSTR,LPCWSTR);
+#define StrCat WINELIB_NAME_AW(StrCat)
+
+LPSTR WINAPI StrCatBuffA(LPSTR,LPCSTR,INT);
+LPWSTR WINAPI StrCatBuffW(LPWSTR,LPCWSTR,INT);
+#define StrCatBuff WINELIB_NAME_AW(StrCatBuff)
+
+DWORD WINAPI StrCatChainW(LPWSTR,DWORD,DWORD,LPCWSTR);
+
+LPSTR WINAPI StrChrA(LPCSTR,WORD);
+LPWSTR WINAPI StrChrW(LPCWSTR,WCHAR);
+#define StrChr WINELIB_NAME_AW(StrChr)
+
+LPSTR WINAPI StrChrIA(LPCSTR,WORD);
+LPWSTR WINAPI StrChrIW(LPCWSTR,WCHAR);
+#define StrChrI WINELIB_NAME_AW(StrChrI)
+
+#define StrCmpA lstrcmpA
+int WINAPI StrCmpW(LPCWSTR,LPCWSTR);
+#define StrCmp WINELIB_NAME_AW(StrCmp)
+
+#define StrCmpIA lstrcmpiA
+int WINAPI StrCmpIW(LPCWSTR,LPCWSTR);
+#define StrCmpI WINELIB_NAME_AW(StrCmpI)
+
+#define StrCpyA lstrcpyA
+LPWSTR WINAPI StrCpyW(LPWSTR,LPCWSTR);
+#define StrCpy WINELIB_NAME_AW(StrCpy)
+
+#define StrCpyNA lstrcpynA
+LPWSTR WINAPI StrCpyNW(LPWSTR,LPCWSTR,int);
+#define StrCpyN WINELIB_NAME_AW(StrCpyN)
+#define StrNCpy WINELIB_NAME_AW(StrCpyN)
+
+INT WINAPI StrCmpLogicalW(LPCWSTR,LPCWSTR);
+
+INT WINAPI StrCmpNA(LPCSTR,LPCSTR,INT);
+INT WINAPI StrCmpNW(LPCWSTR,LPCWSTR,INT);
+#define StrCmpN WINELIB_NAME_AW(StrCmpN)
+#define StrNCmp WINELIB_NAME_AW(StrCmpN)
+
+INT WINAPI StrCmpNIA(LPCSTR,LPCSTR,INT);
+INT WINAPI StrCmpNIW(LPCWSTR,LPCWSTR,INT);
+#define StrCmpNI WINELIB_NAME_AW(StrCmpNI)
+#define StrNCmpI WINELIB_NAME_AW(StrCmpNI)
+
+LPSTR WINAPI StrDupA(LPCSTR);
+LPWSTR WINAPI StrDupW(LPCWSTR);
+#define StrDup WINELIB_NAME_AW(StrDup)
+
+HRESULT WINAPI SHStrDupA(LPCSTR,WCHAR**);
+HRESULT WINAPI SHStrDupW(LPCWSTR,WCHAR**);
+#define SHStrDup WINELIB_NAME_AW(SHStrDup)
+
+LPSTR WINAPI StrFormatByteSizeA (DWORD,LPSTR,UINT);
+
+/* A/W Pairing is broken for this function */
+LPSTR WINAPI StrFormatByteSize64A (LONGLONG,LPSTR,UINT);
+LPWSTR WINAPI StrFormatByteSizeW (LONGLONG,LPWSTR,UINT);
+#ifndef WINE_NO_UNICODE_MACROS
+#ifdef UNICODE
+#define StrFormatByteSize StrFormatByteSizeW
+#else
+#define StrFormatByteSize StrFormatByteSize64A
+#endif
+#endif
+
+LPSTR WINAPI StrFormatKBSizeA(LONGLONG,LPSTR,UINT);
+LPWSTR WINAPI StrFormatKBSizeW(LONGLONG,LPWSTR,UINT);
+#define StrFormatKBSize WINELIB_NAME_AW(StrFormatKBSize)
+
+int WINAPI StrFromTimeIntervalA(LPSTR,UINT,DWORD,int);
+int WINAPI StrFromTimeIntervalW(LPWSTR,UINT,DWORD,int);
+#define StrFromTimeInterval WINELIB_NAME_AW(StrFromTimeInterval)
+
+BOOL WINAPI StrIsIntlEqualA(BOOL,LPCSTR,LPCSTR,int);
+BOOL WINAPI StrIsIntlEqualW(BOOL,LPCWSTR,LPCWSTR,int);
+#define StrIsIntlEqual WINELIB_NAME_AW(StrIsIntlEqual)
+
+#define StrIntlEqNA(a,b,c) StrIsIntlEqualA(TRUE,a,b,c)
+#define StrIntlEqNW(a,b,c) StrIsIntlEqualW(TRUE,a,b,c)
+
+#define StrIntlEqNIA(a,b,c) StrIsIntlEqualA(FALSE,a,b,c)
+#define StrIntlEqNIW(a,b,c) StrIsIntlEqualW(FALSE,a,b,c)
+
+LPSTR WINAPI StrNCatA(LPSTR,LPCSTR,int);
+LPWSTR WINAPI StrNCatW(LPWSTR,LPCWSTR,int);
+#define StrNCat WINELIB_NAME_AW(StrNCat)
+#define StrCatN WINELIB_NAME_AW(StrNCat)
+
+LPSTR WINAPI StrPBrkA(LPCSTR,LPCSTR);
+LPWSTR WINAPI StrPBrkW(LPCWSTR,LPCWSTR);
+#define StrPBrk WINELIB_NAME_AW(StrPBrk)
+
+LPSTR WINAPI StrRChrA(LPCSTR,LPCSTR,WORD);
+LPWSTR WINAPI StrRChrW(LPCWSTR,LPCWSTR,WORD);
+#define StrRChr WINELIB_NAME_AW(StrRChr)
+
+LPSTR WINAPI StrRChrIA(LPCSTR,LPCSTR,WORD);
+LPWSTR WINAPI StrRChrIW(LPCWSTR,LPCWSTR,WORD);
+#define StrRChrI WINELIB_NAME_AW(StrRChrI)
+
+LPSTR WINAPI StrRStrIA(LPCSTR,LPCSTR,LPCSTR);
+LPWSTR WINAPI StrRStrIW(LPCWSTR,LPCWSTR,LPCWSTR);
+#define StrRStrI WINELIB_NAME_AW(StrRStrI)
+
+int WINAPI StrSpnA(LPCSTR,LPCSTR);
+int WINAPI StrSpnW(LPCWSTR,LPCWSTR);
+#define StrSpn WINELIB_NAME_AW(StrSpn)
+
+LPSTR WINAPI StrStrA(LPCSTR,LPCSTR);
+LPWSTR WINAPI StrStrW(LPCWSTR,LPCWSTR);
+#define StrStr WINELIB_NAME_AW(StrStr)
+
+LPSTR WINAPI StrStrIA(LPCSTR,LPCSTR);
+LPWSTR WINAPI StrStrIW(LPCWSTR,LPCWSTR);
+#define StrStrI WINELIB_NAME_AW(StrStrI)
+
- HRESULT WINAPI SHCreateThreadRef(LONG*, IUnknown**);
+int WINAPI StrToIntA(LPCSTR);
+int WINAPI StrToIntW(LPCWSTR);
+#define StrToInt WINELIB_NAME_AW(StrToInt)
+#define StrToLong WINELIB_NAME_AW(StrToInt)
+
+BOOL WINAPI StrToIntExA(LPCSTR,DWORD,int*);
+BOOL WINAPI StrToIntExW(LPCWSTR,DWORD,int*);
+#define StrToIntEx WINELIB_NAME_AW(StrToIntEx)
+
+BOOL WINAPI StrToInt64ExA(LPCSTR,DWORD,LONGLONG*);
+BOOL WINAPI StrToInt64ExW(LPCWSTR,DWORD,LONGLONG*);
+#define StrToIntEx64 WINELIB_NAME_AW(StrToIntEx64)
+
+BOOL WINAPI StrTrimA(LPSTR,LPCSTR);
+BOOL WINAPI StrTrimW(LPWSTR,LPCWSTR);
+#define StrTrim WINELIB_NAME_AW(StrTrim)
+
+INT WINAPI wvnsprintfA(LPSTR,INT,LPCSTR,__ms_va_list);
+INT WINAPI wvnsprintfW(LPWSTR,INT,LPCWSTR,__ms_va_list);
+#define wvnsprintf WINELIB_NAME_AW(wvnsprintf)
+
+INT WINAPIV wnsprintfA(LPSTR,INT,LPCSTR, ...);
+INT WINAPIV wnsprintfW(LPWSTR,INT,LPCWSTR, ...);
+#define wnsprintf WINELIB_NAME_AW(wnsprintf)
+
+HRESULT WINAPI SHLoadIndirectString(LPCWSTR,LPWSTR,UINT,PVOID*);
+
+BOOL WINAPI IntlStrEqWorkerA(BOOL,LPCSTR,LPCSTR,int);
+BOOL WINAPI IntlStrEqWorkerW(BOOL,LPCWSTR,LPCWSTR,int);
+#define IntlStrEqWorker WINELIB_NAME_AW(IntlStrEqWorker)
+
+#define IntlStrEqNA(s1,s2,n) IntlStrEqWorkerA(TRUE,s1,s2,n)
+#define IntlStrEqNW(s1,s2,n) IntlStrEqWorkerW(TRUE,s1,s2,n)
+#define IntlStrEqN WINELIB_NAME_AW(IntlStrEqN)
+
+#define IntlStrEqNIA(s1,s2,n) IntlStrEqWorkerA(FALSE,s1,s2,n)
+#define IntlStrEqNIW(s1,s2,n) IntlStrEqWorkerW(FALSE,s1,s2,n)
+#define IntlStrEqNI WINELIB_NAME_AW(IntlStrEqNI)
+
+HRESULT WINAPI StrRetToStrA(STRRET*,LPCITEMIDLIST,LPSTR*);
+HRESULT WINAPI StrRetToStrW(STRRET*,LPCITEMIDLIST,LPWSTR*);
+#define StrRetToStr WINELIB_NAME_AW(StrRetToStr)
+
+HRESULT WINAPI StrRetToBufA(STRRET*,LPCITEMIDLIST,LPSTR,UINT);
+HRESULT WINAPI StrRetToBufW(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
+#define StrRetToBuf WINELIB_NAME_AW(StrRetToBuf)
+
+HRESULT WINAPI StrRetToBSTR(STRRET*,LPCITEMIDLIST,BSTR*);
+
+#endif /* NO_SHLWAPI_STRFCNS */
+
+
+/* GDI functions */
+#ifndef NO_SHLWAPI_GDI
+
+HPALETTE WINAPI SHCreateShellPalette(HDC);
+
+COLORREF WINAPI ColorHLSToRGB(WORD,WORD,WORD);
+
+COLORREF WINAPI ColorAdjustLuma(COLORREF,int,BOOL);
+
+VOID WINAPI ColorRGBToHLS(COLORREF,LPWORD,LPWORD,LPWORD);
+
+#endif /* NO_SHLWAPI_GDI */
+
+
+/* Stream functions */
+#ifndef NO_SHLWAPI_STREAM
+
+struct IStream * WINAPI SHOpenRegStreamA(HKEY,LPCSTR,LPCSTR,DWORD);
+struct IStream * WINAPI SHOpenRegStreamW(HKEY,LPCWSTR,LPCWSTR,DWORD);
+#define SHOpenRegStream WINELIB_NAME_AW(SHOpenRegStream2) /* Uses version 2 */
+
+struct IStream * WINAPI SHOpenRegStream2A(HKEY,LPCSTR,LPCSTR,DWORD);
+struct IStream * WINAPI SHOpenRegStream2W(HKEY,LPCWSTR,LPCWSTR,DWORD);
+#define SHOpenRegStream2 WINELIB_NAME_AW(SHOpenRegStream2)
+
+HRESULT WINAPI SHCreateStreamOnFileA(LPCSTR,DWORD,struct IStream**);
+HRESULT WINAPI SHCreateStreamOnFileW(LPCWSTR,DWORD,struct IStream**);
+#define SHCreateStreamOnFile WINELIB_NAME_AW(SHCreateStreamOnFile)
+
+HRESULT WINAPI SHCreateStreamOnFileEx(LPCWSTR,DWORD,DWORD,BOOL,struct IStream*,struct IStream**);
+
+HRESULT WINAPI SHCreateStreamWrapper(LPBYTE,DWORD,DWORD,struct IStream**);
+
+#endif /* NO_SHLWAPI_STREAM */
+
+/* SHAutoComplete flags */
+#define SHACF_DEFAULT 0x00000000
+#define SHACF_FILESYSTEM 0x00000001
+#define SHACF_URLHISTORY 0x00000002
+#define SHACF_URLMRU 0x00000004
+#define SHACF_URLALL (SHACF_URLHISTORY|SHACF_URLMRU)
+#define SHACF_USETAB 0x00000008
+#define SHACF_FILESYS_ONLY 0x00000010
+#define SHACF_FILESYS_DIRS 0x00000020
+#define SHACF_AUTOSUGGEST_FORCE_ON 0x10000000
+#define SHACF_AUTOSUGGEST_FORCE_OFF 0x20000000
+#define SHACF_AUTOAPPEND_FORCE_ON 0x40000000
+#define SHACF_AUTOAPPEND_FORCE_OFF 0x80000000
+
+HRESULT WINAPI SHAutoComplete(HWND,DWORD);
+
+/* Threads */
+HRESULT WINAPI SHGetThreadRef(IUnknown**);
+HRESULT WINAPI SHSetThreadRef(IUnknown*);
+HRESULT WINAPI SHReleaseThreadRef(void);
+
+/* SHCreateThread flags */
+#define CTF_INSIST 0x01 /* Always call */
+#define CTF_THREAD_REF 0x02 /* Hold thread ref */
+#define CTF_PROCESS_REF 0x04 /* Hold process ref */
+#define CTF_COINIT 0x08 /* Startup COM first */
+#define CTF_FREELIBANDEXIT 0x10 /* Hold DLL ref */
+#define CTF_REF_COUNTED 0x20 /* Thread is ref counted */
+#define CTF_WAIT_ALLOWCOM 0x40 /* Allow marshalling */
+
+BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE,void*,DWORD,LPTHREAD_START_ROUTINE);
+
+BOOL WINAPI SHSkipJunction(struct IBindCtx*,const CLSID*);
+
+/* Version Information */
+
+typedef struct _DllVersionInfo {
+ DWORD cbSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformID;
+} DLLVERSIONINFO;
+
+#define DLLVER_PLATFORM_WINDOWS 0x01 /* Win9x */
+#define DLLVER_PLATFORM_NT 0x02 /* WinNT */
+
+typedef HRESULT (CALLBACK *DLLGETVERSIONPROC)(DLLVERSIONINFO *);
+
+#ifdef __WINESRC__
+/* shouldn't be here, but is nice for type checking */
+HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *) DECLSPEC_HIDDEN;
+#endif
+
+typedef struct _DLLVERSIONINFO2 {
+ DLLVERSIONINFO info1;
+ DWORD dwFlags; /* Reserved */
+ ULONGLONG DECLSPEC_ALIGN(8) ullVersion; /* 16 bits each for Major, Minor, Build, QFE */
+} DLLVERSIONINFO2;
+
+#define DLLVER_MAJOR_MASK 0xFFFF000000000000
+#define DLLVER_MINOR_MASK 0x0000FFFF00000000
+#define DLLVER_BUILD_MASK 0x00000000FFFF0000
+#define DLLVER_QFE_MASK 0x000000000000FFFF
+
+#define MAKEDLLVERULL(mjr, mnr, bld, qfe) (((ULONGLONG)(mjr)<< 48)| \
+ ((ULONGLONG)(mnr)<< 32) | ((ULONGLONG)(bld)<< 16) | (ULONGLONG)(qfe))
+
+HRESULT WINAPI DllInstall(BOOL,LPCWSTR) DECLSPEC_HIDDEN;
+
+
++#if (_WIN32_IE >= 0x0600)
++#define SHGVSPB_PERUSER 0x00000001
++#define SHGVSPB_ALLUSERS 0x00000002
++#define SHGVSPB_PERFOLDER 0x00000004
++#define SHGVSPB_ALLFOLDERS 0x00000008
++#define SHGVSPB_INHERIT 0x00000010
++#define SHGVSPB_ROAM 0x00000020
++#define SHGVSPB_NOAUTODEFAULTS 0x80000000
++
++#define SHGVSPB_FOLDER (SHGVSPB_PERUSER | SHGVSPB_PERFOLDER)
++#define SHGVSPB_FOLDERNODEFAULTS (SHGVSPB_PERUSER | SHGVSPB_PERFOLDER | SHGVSPB_NOAUTODEFAULTS)
++#define SHGVSPB_USERDEFAULTS (SHGVSPB_PERUSER | SHGVSPB_ALLFOLDERS)
++#define SHGVSPB_GLOBALDEAFAULTS (SHGVSPB_ALLUSERS | SHGVSPB_ALLFOLDERS)
++
++HRESULT WINAPI SHGetViewStatePropertyBag(LPCITEMIDLIST pidl, LPWSTR bag_name, DWORD flags, REFIID riid, void **ppv);
++#endif /* (_WIN32_IE >= 0x0600) */
++
++
+/* IsOS definitions */
+
+#define OS_WIN32SORGREATER 0x00
+#define OS_NT 0x01
+#define OS_WIN95ORGREATER 0x02
+#define OS_NT4ORGREATER 0x03
+#define OS_WIN2000ORGREATER_ALT 0x04
+#define OS_WIN98ORGREATER 0x05
+#define OS_WIN98_GOLD 0x06
+#define OS_WIN2000ORGREATER 0x07
+#define OS_WIN2000PRO 0x08
+#define OS_WIN2000SERVER 0x09
+#define OS_WIN2000ADVSERVER 0x0A
+#define OS_WIN2000DATACENTER 0x0B
+#define OS_WIN2000TERMINAL 0x0C
+#define OS_EMBEDDED 0x0D
+#define OS_TERMINALCLIENT 0x0E
+#define OS_TERMINALREMOTEADMIN 0x0F
+#define OS_WIN95_GOLD 0x10
+#define OS_MEORGREATER 0x11
+#define OS_XPORGREATER 0x12
+#define OS_HOME 0x13
+#define OS_PROFESSIONAL 0x14
+#define OS_DATACENTER 0x15
+#define OS_ADVSERVER 0x16
+#define OS_SERVER 0x17
+#define OS_TERMINALSERVER 0x18
+#define OS_PERSONALTERMINALSERVER 0x19
+#define OS_FASTUSERSWITCHING 0x1A
+#define OS_WELCOMELOGONUI 0x1B
+#define OS_DOMAINMEMBER 0x1C
+#define OS_ANYSERVER 0x1D
+#define OS_WOW6432 0x1E
+#define OS_WEBSERVER 0x1F
+#define OS_SMALLBUSINESSSERVER 0x20
+#define OS_TABLETPC 0x21
+#define OS_SERVERADMINUI 0x22
+#define OS_MEDIACENTER 0x23
+#define OS_APPLIANCE 0x24
+
+BOOL WINAPI IsOS(DWORD);
+
+/* SHSetTimerQueueTimer definitions */
+#define TPS_EXECUTEIO 0x00000001
+#define TPS_LONGEXECTIME 0x00000008
+
+/* SHFormatDateTimeA/SHFormatDateTimeW flags */
+#define FDTF_SHORTTIME 0x00000001
+#define FDTF_SHORTDATE 0x00000002
+#define FDTF_DEFAULT (FDTF_SHORTDATE | FDTF_SHORTTIME)
+#define FDTF_LONGDATE 0x00000004
+#define FDTF_LONGTIME 0x00000008
+#define FDTF_RELATIVE 0x00000010
+#define FDTF_LTRDATE 0x00000100
+#define FDTF_RTLDATE 0x00000200
+#define FDTF_NOAUTOREADINGORDER 0x00000400
+
+
+typedef struct
+{
+ const IID *piid;
+ int dwOffset;
+} QITAB, *LPQITAB;
+
+HRESULT WINAPI QISearch(void* base, const QITAB *pqit, REFIID riid, void **ppv);
+
++HANDLE WINAPI SHAllocShared(LPVOID pv, ULONG cb, DWORD pid);
++BOOL WINAPI SHFreeShared(HANDLE hMem, DWORD pid);
++LPVOID WINAPI SHLockShared(HANDLE hMem, DWORD pid);
++BOOL WINAPI SHUnlockShared(LPVOID pv);
++
+#include <poppack.h>
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* defined(__cplusplus) */
+
+#endif /* __WINE_SHLWAPI_H */
--- /dev/null
+/*
+ * ReactOS shlwapi
+ *
+ * Copyright 2009 Andrew Hill <ash77 at domain reactos.org>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __SHLWAPI_UNDOC_H
+#define __SHLWAPI_UNDOC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* defined(__cplusplus) */
+
+struct IEThreadParamBlock
+{
+ long offset0;
+ long offset4;
+ long offset8;
+ IUnknown *offsetC;
+ long offset10;
+ IUnknown *offset14;
+ LPITEMIDLIST directoryPIDL;
+ char filler1[84]; // unknown contents
+ IUnknown *offset70;
+ long filler2; // unknown contents
+ IUnknown *offset78;
+ LPITEMIDLIST offset7C;
+ LPITEMIDLIST offset80;
+ char filler3[116]; // unknown contents
+ IUnknown *offsetF8; // instance explorer
+ long filler4; // unknown contents
+};
+
++BOOL WINAPI SHAboutInfoA(LPSTR lpszDest, DWORD dwDestLen);
++BOOL WINAPI SHAboutInfoW(LPWSTR lpszDest, DWORD dwDestLen);
++HRESULT WINAPI IUnknown_QueryStatus(IUnknown *lpUnknown, REFGUID pguidCmdGroup, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT* pCmdText);
++HRESULT WINAPI IUnknown_Exec(IUnknown* lpUnknown, REFGUID pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn, VARIANT* pvaOut);
++LONG WINAPI SHSetWindowBits(HWND hwnd, INT offset, UINT wMask, UINT wFlags);
++HWND WINAPI SHSetParentHwnd(HWND hWnd, HWND hWndParent);
++HRESULT WINAPI ConnectToConnectionPoint(IUnknown *lpUnkSink, REFIID riid, BOOL bAdviseOnly, IUnknown *lpUnknown, LPDWORD lpCookie, IConnectionPoint **lppCP);
++DWORD WINAPI IUnknown_AtomicRelease(IUnknown **lpUnknown);
++BOOL WINAPI SHIsSameObject(IUnknown *lpInt1, IUnknown *lpInt2);
++HRESULT WINAPI IUnknown_GetWindow(IUnknown *lpUnknown, HWND *lphWnd);
++HRESULT WINAPI IUnknown_SetOwner(IUnknown *pUnk, ULONG arg);
++HRESULT WINAPI IUnknown_SetSite(IUnknown *obj, IUnknown *site);
++HRESULT WINAPI IUnknown_GetClassID(IUnknown *lpUnknown, CLSID *lpClassId);
++HRESULT WINAPI IUnknown_QueryService(IUnknown* lpUnknown, REFGUID sid, REFIID riid, LPVOID *lppOut);
++HRESULT WINAPI IUnknown_UIActivateIO(IUnknown *unknown, BOOL activate, LPMSG msg);
++BOOL WINAPI SHLoadMenuPopup(HINSTANCE hInst, LPCWSTR szName);
++void WINAPI SHPropagateMessage(HWND hWnd, UINT uiMsgId, WPARAM wParam, LPARAM lParam, BOOL bSend);
++DWORD WINAPI SHRemoveAllSubMenus(HMENU hMenu);
++UINT WINAPI SHEnableMenuItem(HMENU hMenu, UINT wItemID, BOOL bEnable);
++DWORD WINAPI SHCheckMenuItem(HMENU hMenu, UINT uID, BOOL bCheck);
++DWORD WINAPI SHRegisterClassA(WNDCLASSA *wndclass);
++BOOL WINAPI SHSimulateDrop(IDropTarget *pDrop, IDataObject *pDataObj, DWORD grfKeyState, PPOINTL lpPt, DWORD* pdwEffect);
++HRESULT WINAPI IUnknown_TranslateAcceleratorOCS(IUnknown *lpUnknown, LPMSG lpMsg, DWORD dwModifiers);
++HRESULT WINAPI IUnknown_OnFocusOCS(IUnknown *lpUnknown, BOOL fGotFocus);
++HRESULT WINAPI IUnknown_HandleIRestrict(LPUNKNOWN lpUnknown, PVOID lpArg1, PVOID lpArg2, PVOID lpArg3, PVOID lpArg4);
++HMENU WINAPI SHGetMenuFromID(HMENU hMenu, UINT uID);
++DWORD WINAPI SHGetCurColorRes(void);
++DWORD WINAPI SHWaitForSendMessageThread(HANDLE hand, DWORD dwTimeout);
++HRESULT WINAPI SHIsExpandableFolder(LPSHELLFOLDER lpFolder, LPCITEMIDLIST pidl);
++DWORD WINAPI SHFillRectClr(HDC hDC, LPCRECT pRect, COLORREF cRef);
++int WINAPI SHSearchMapInt(const int *lpKeys, const int *lpValues, int iLen, int iKey);
++VOID WINAPI IUnknown_Set(IUnknown **lppDest, IUnknown *lpUnknown);
++HRESULT WINAPI MayQSForward(IUnknown* lpUnknown, PVOID lpReserved, REFGUID riidCmdGrp, ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT *pCmdText);
++HRESULT WINAPI MayExecForward(IUnknown* lpUnknown, INT iUnk, REFGUID pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut);
++HRESULT WINAPI IsQSForward(REFGUID pguidCmdGroup,ULONG cCmds, OLECMD *prgCmds);
++BOOL WINAPI SHIsChildOrSelf(HWND hParent, HWND hChild);
++
+void WINAPI InitOCHostClass(long param8);
+long WINAPI SHOpenFolderWindow(IEThreadParamBlock *param8);
+void WINAPI SHCreateSavedWindows(void);
+long WINAPI SHCreateFromDesktop(long param8);
+long WINAPI SHExplorerParseCmdLine(LPCTSTR commandLine);
+void WINAPI UEMRegisterNotify(long param8, long paramC);
+HRESULT WINAPI SHCreateBandForPidl(LPCITEMIDLIST param8, IUnknown *paramC, BOOL param10);
+HRESULT WINAPI SHPidlFromDataObject(IDataObject *param8, long *paramC, long param10, FILEDESCRIPTORW *param14);
+long WINAPI IDataObject_GetDeskBandState(long param8);
+IEThreadParamBlock *WINAPI SHCreateIETHREADPARAM(long param8, long paramC, IUnknown *param10, IUnknown *param14);
+IEThreadParamBlock *WINAPI SHCloneIETHREADPARAM(IEThreadParamBlock *param);
+long WINAPI SHParseIECommandLine(long param8, long paramC);
+void WINAPI SHDestroyIETHREADPARAM(IEThreadParamBlock *param);
+HRESULT WINAPI SHOnCWMCommandLine(long param8);
+LPITEMIDLIST WINAPI Channel_GetFolderPidl(void);
+IUnknown *WINAPI ChannelBand_Create(LPITEMIDLIST pidl);
+HRESULT WINAPI Channels_SetBandInfoSFB(IUnknown *param8);
+HRESULT WINAPI IUnknown_SetBandInfoSFB(IUnknown *param8, long paramC);
+HRESULT WINAPI Channel_QuickLaunch(void);
+HRESULT WINAPI SHGetNavigateTarget(long param8, long paramC, long param10, long param14);
+HRESULT WINAPI GetInfoTip(IUnknown *param8, long paramC, LPTSTR *param10, long cchMax);
+HRESULT WINAPI SHEnumClassesOfCategories(long param8, long paramC, long param10, long param14, long param18);
+HRESULT WINAPI SHWriteClassesOfCategories(long param8, long paramC, long param10, long param14, long param18, long param1C, long param20);
+BOOL WINAPI SHIsExplorerBrowser();
+HRESULT WINAPI SHOpenNewFrame(LPITEMIDLIST pidl, IUnknown *paramC, long param10, long param14);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* defined(__cplusplus) */
+
+#endif /* __SHLWAPI_UNDOC_H */
--- /dev/null
+
+#ifndef _INC_COMMCTRL_WINE
+#define _INC_COMMCTRL_WINE
+
+#define DPA_GetPtr DPA_GetPtr_wine_hack
+#define FlatSB_SetScrollProp FlatSB_SetScrollProp_wine_hack
+
+#if (_WIN32_IE < 0x501)
+#undef _WIN32_IE
+#define _WIN32_IE 0x0501
+#endif
+
+#include <psdk/commctrl.h>
+
++#ifdef __cplusplus
++extern "C" {
++#endif
++
+#undef DPA_GetPtr
+LPVOID WINAPI DPA_GetPtr(HDPA, INT);
+
+#undef FlatSB_SetScrollProp
+BOOL WINAPI FlatSB_SetScrollProp(HWND, UINT, INT, BOOL);
+
+#define DRAGLISTMSGSTRINGA "commctrl_DragListMsg"
+#if defined(__GNUC__)
+# define DRAGLISTMSGSTRINGW (const WCHAR []){ 'c','o','m','m','c','t','r','l', \
+ '_','D','r','a','g','L','i','s','t','M','s','g',0 }
+#elif defined(_MSC_VER)
+# define DRAGLISTMSGSTRINGW L"commctrl_DragListMsg"
+#else
+static const WCHAR DRAGLISTMSGSTRINGW[] = { 'c','o','m','m','c','t','r','l',
+ '_','D','r','a','g','L','i','s','t','M','s','g',0 };
+#endif
+
+#define ListView_InsertItemA(hwnd,pitem) \
+ (INT)SNDMSGA((hwnd),LVM_INSERTITEMA,0,(LPARAM)(const LVITEMA *)(pitem))
+#define ListView_InsertItemW(hwnd,pitem) \
+ (INT)SNDMSGW((hwnd),LVM_INSERTITEMW,0,(LPARAM)(const LVITEMW *)(pitem))
+
+#ifdef __cplusplus
+#define SNDMSGA ::SendMessageA
+#define SNDMSGW ::SendMessageW
+#else
+#define SNDMSGA SendMessageA
+#define SNDMSGW SendMessageW
+#endif
+
+#define FLATSB_CLASSA "flatsb_class32"
+#if defined(__GNUC__)
+# define FLATSB_CLASSW (const WCHAR []){ 'f','l','a','t','s','b','_', \
+ 'c','l','a','s','s','3','2',0 }
+#elif defined(_MSC_VER)
+# define FLATSB_CLASSW L"flatsb_class32"
+#else
+static const WCHAR FLATSB_CLASSW[] = { 'f','l','a','t','s','b','_',
+ 'c','l','a','s','s','3','2',0 };
+#endif
+
+typedef TBSAVEPARAMSW *LPTBSAVEPARAMSW;
+
+typedef LVFINDINFOA *LPLVFINDINFOA;
+typedef LVFINDINFOW *LPLVFINDINFOW;
+
+#define SB_SETBORDERS (WM_USER+5)
+#define TBSTYLE_EX_UNDOC1 0x00000004 /* similar to TBSTYLE_WRAPABLE */
+
+/* these are undocumented and the names are guesses */
+typedef struct
+{
+ NMHDR hdr;
+ HWND hwndDialog;
+} NMTBINITCUSTOMIZE;
+
+typedef struct
+{
+ NMHDR hdr;
+ INT idNew;
+ INT iDirection; /* left is -1, right is 1 */
+ DWORD dwReason; /* HICF_* */
+} NMTBWRAPHOTITEM;
+
+#define LPNMLVDISPINFO WINELIB_NAME_AW(LPNMLVDISPINFO)
+
+/* undocumented messages in Toolbar */
+#define TB_UNKWN45D (WM_USER+93)
+#define TB_UNKWN464 (WM_USER+100)
+
++#ifdef __cplusplus
++}
++#endif
++
+#endif /* _INC_COMMCTRL_WINE */