diff --git a/reactos/dll/win32/shell32/CMakeLists.txt b/reactos/dll/win32/shell32/CMakeLists.txt index bf68b6baf74..c915f757a4c 100644 --- a/reactos/dll/win32/shell32/CMakeLists.txt +++ b/reactos/dll/win32/shell32/CMakeLists.txt @@ -1,3 +1,4 @@ +set_cpp() remove_definitions(-D_WIN32_WINNT=0x502) add_definitions(-D_WIN32_WINNT=0x600) @@ -10,71 +11,78 @@ add_definitions( 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 - 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 + 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) -target_link_libraries(shell32 wine uuid recyclebin) + +set_module_type(shell32 win32dll UNICODE) + +target_link_libraries(shell32 + atlnew + wine + uuid + recyclebin) + add_delay_importlibs(shell32 ole32 version) add_importlibs(shell32 @@ -92,5 +100,6 @@ add_importlibs(shell32 ntdll) add_pch(shell32 precomp.h) + add_cd_file(TARGET shell32 DESTINATION reactos/system32 FOR all) add_importlib_target(shell32.spec) diff --git a/reactos/dll/win32/shell32/GlueCode.cpp b/reactos/dll/win32/shell32/GlueCode.cpp new file mode 100644 index 00000000000..055ca4775af --- /dev/null +++ b/reactos/dll/win32/shell32/GlueCode.cpp @@ -0,0 +1,336 @@ + +LONG WINAPI RegCopyTreeX(HKEY, LPCWSTR, HKEY) +{ + DebugBreak(); + return 0; +} + +static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars) +{ + HGLOBAL hMemory; + HRSRC hResource; + WCHAR *pString; + int idxString; + + /* Negative values have to be inverted. */ + if (HIWORD(resId) == 0xffff) + resId = (UINT)(-((INT)resId)); + + /* Load the resource into memory and get a pointer to it. */ + hResource = FindResourceW(hModule, MAKEINTRESOURCEW(LOWORD(resId >> 4) + 1), (LPWSTR)RT_STRING); + if (!hResource) return 0; + hMemory = LoadResource(hModule, hResource); + if (!hMemory) return 0; + pString = (WCHAR *)LockResource(hMemory); + + /* Strings are length-prefixed. Lowest nibble of resId is an index. */ + idxString = resId & 0xf; + while (idxString--) pString += *pString + 1; + + /* If no buffer is given, return length of the string. */ + if (!pwszBuffer) return *pString; + + /* Else copy over the string, respecting the buffer size. */ + cMaxChars = (*pString < cMaxChars) ? *pString : (cMaxChars - 1); + if (cMaxChars >= 0) + { + memcpy(pwszBuffer, pString+1, cMaxChars * sizeof(WCHAR)); + pwszBuffer[cMaxChars] = L'\0'; + } + + return cMaxChars; +} + +LONG WINAPI +RegLoadMUIStringWX(IN HKEY hKey, + IN LPCWSTR pszValue OPTIONAL, + OUT LPWSTR pszOutBuf, + IN DWORD cbOutBuf, + OUT LPDWORD pcbData OPTIONAL, + IN DWORD Flags, + IN LPCWSTR pszDirectory OPTIONAL) +{ + DWORD dwValueType, cbData; + LPWSTR pwszTempBuffer = NULL, pwszExpandedBuffer = NULL; + LONG result; + + /* Parameter sanity checks. */ + if (!hKey || !pszOutBuf) + return ERROR_INVALID_PARAMETER; + + if (pszDirectory && *pszDirectory) + { + return ERROR_INVALID_PARAMETER; + } + + /* Check for value existence and correctness of it's type, allocate a buffer and load it. */ + result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, NULL, &cbData); + if (result != ERROR_SUCCESS) goto cleanup; + if (!(dwValueType == REG_SZ || dwValueType == REG_EXPAND_SZ) || !cbData) + { + result = ERROR_FILE_NOT_FOUND; + goto cleanup; + } + pwszTempBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cbData); + if (!pwszTempBuffer) + { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + result = RegQueryValueExW(hKey, pszValue, NULL, &dwValueType, (LPBYTE)pwszTempBuffer, &cbData); + if (result != ERROR_SUCCESS) goto cleanup; + + /* Expand environment variables, if appropriate, or copy the original string over. */ + if (dwValueType == REG_EXPAND_SZ) + { + cbData = ExpandEnvironmentStringsW(pwszTempBuffer, NULL, 0) * sizeof(WCHAR); + if (!cbData) goto cleanup; + pwszExpandedBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cbData); + if (!pwszExpandedBuffer) + { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + ExpandEnvironmentStringsW(pwszTempBuffer, pwszExpandedBuffer, cbData); + } + else + { + pwszExpandedBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cbData); + memcpy(pwszExpandedBuffer, pwszTempBuffer, cbData); + } + + /* If the value references a resource based string, parse the value and load the string. + * Else just copy over the original value. */ + result = ERROR_SUCCESS; + if (*pwszExpandedBuffer != L'@') /* '@' is the prefix for resource based string entries. */ + { + lstrcpynW(pszOutBuf, pwszExpandedBuffer, cbOutBuf / sizeof(WCHAR)); + } + else + { + WCHAR *pComma = wcsrchr(pwszExpandedBuffer, L','); + UINT uiStringId; + HMODULE hModule; + + /* Format of the expanded value is 'path_to_dll,-resId' */ + if (!pComma || pComma[1] != L'-') + { + result = ERROR_BADKEY; + goto cleanup; + } + + uiStringId = _wtoi(pComma+2); + *pComma = L'\0'; + + hModule = LoadLibraryExW(pwszExpandedBuffer + 1, NULL, LOAD_LIBRARY_AS_DATAFILE); + if (!hModule || !load_string(hModule, uiStringId, pszOutBuf, cbOutBuf / sizeof(WCHAR))) + result = ERROR_BADKEY; + FreeLibrary(hModule); + } + +cleanup: + HeapFree(GetProcessHeap(), 0, pwszTempBuffer); + HeapFree(GetProcessHeap(), 0, pwszExpandedBuffer); + return result; +} + +#if 0 +VOID WINAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString); +#else +typedef VOID (WINAPI *PRtlFreeUnicodeString)(PUNICODE_STRING UnicodeString); +static VOID WINAPI +RtlFreeUnicodeStringx(PUNICODE_STRING UnicodeString) +{ + static PRtlFreeUnicodeString Func = NULL; + + if (Func == NULL) + { + HMODULE hShlwapi; + hShlwapi = LoadLibrary(TEXT("ntdll.DLL")); + if (hShlwapi != NULL) + { + Func = (PRtlFreeUnicodeString)GetProcAddress(hShlwapi, "RtlFreeUnicodeString"); + } + } + + if (Func != NULL) + { + Func(UnicodeString); + return; + } + + MessageBox(NULL, TEXT("RtlFreeUnicodeString not available"), NULL, 0); +} +#endif + +LONG WINAPI +RegLoadMUIStringAX(IN HKEY hKey, + IN LPCSTR pszValue OPTIONAL, + OUT LPSTR pszOutBuf, + IN DWORD cbOutBuf, + OUT LPDWORD pcbData OPTIONAL, + IN DWORD Flags, + IN LPCSTR pszDirectory OPTIONAL) +{ + UNICODE_STRING valueW, baseDirW; + WCHAR *pwszBuffer; + DWORD cbData = cbOutBuf * sizeof(WCHAR); + LONG result; + + valueW.Buffer = baseDirW.Buffer = pwszBuffer = NULL; + if (!RtlCreateUnicodeStringFromAsciiz(&valueW, pszValue) || + !RtlCreateUnicodeStringFromAsciiz(&baseDirW, pszDirectory) || + !(pwszBuffer = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, cbData))) + { + result = ERROR_NOT_ENOUGH_MEMORY; + goto cleanup; + } + + result = RegLoadMUIStringWX(hKey, valueW.Buffer, pwszBuffer, cbData, NULL, Flags, + baseDirW.Buffer); + + if (result == ERROR_SUCCESS) + { + cbData = WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszOutBuf, cbOutBuf, NULL, NULL); + if (pcbData) + *pcbData = cbData; + } + +cleanup: + HeapFree(GetProcessHeap(), 0, pwszBuffer); + RtlFreeUnicodeStringx(&baseDirW); + RtlFreeUnicodeStringx(&valueW); + + return result; +} + +static VOID +RegpApplyRestrictions(DWORD dwFlags, + DWORD dwType, + DWORD cbData, + PLONG ret) +{ + /* Check if the type is restricted by the passed flags */ + if (*ret == ERROR_SUCCESS || *ret == ERROR_MORE_DATA) + { + DWORD dwMask = 0; + + switch (dwType) + { + case REG_NONE: dwMask = RRF_RT_REG_NONE; break; + case REG_SZ: dwMask = RRF_RT_REG_SZ; break; + case REG_EXPAND_SZ: dwMask = RRF_RT_REG_EXPAND_SZ; break; + case REG_MULTI_SZ: dwMask = RRF_RT_REG_MULTI_SZ; break; + case REG_BINARY: dwMask = RRF_RT_REG_BINARY; break; + case REG_DWORD: dwMask = RRF_RT_REG_DWORD; break; + case REG_QWORD: dwMask = RRF_RT_REG_QWORD; break; + } + + if (dwFlags & dwMask) + { + /* Type is not restricted, check for size mismatch */ + if (dwType == REG_BINARY) + { + DWORD cbExpect = 0; + + if ((dwFlags & RRF_RT_DWORD) == RRF_RT_DWORD) + cbExpect = 4; + else if ((dwFlags & RRF_RT_QWORD) == RRF_RT_QWORD) + cbExpect = 8; + + if (cbExpect && cbData != cbExpect) + *ret = ERROR_DATATYPE_MISMATCH; + } + } + else *ret = ERROR_UNSUPPORTED_TYPE; + } +} + +LONG WINAPI RegGetValueX(HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData) +{ + DWORD dwType, cbData = pcbData ? *pcbData : 0; + PVOID pvBuf = NULL; + LONG ret; + + if (pvData && !pcbData) + return ERROR_INVALID_PARAMETER; + if ((dwFlags & RRF_RT_REG_EXPAND_SZ) && !(dwFlags & RRF_NOEXPAND) && + ((dwFlags & RRF_RT_ANY) != RRF_RT_ANY)) + return ERROR_INVALID_PARAMETER; + + if (pszSubKey && pszSubKey[0]) + { + ret = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_QUERY_VALUE, &hKey); + if (ret != ERROR_SUCCESS) return ret; + } + + ret = RegQueryValueExW(hKey, pszValue, NULL, &dwType, (LPBYTE)pvData, &cbData); + + /* If we are going to expand we need to read in the whole the value even + * if the passed buffer was too small as the expanded string might be + * smaller than the unexpanded one and could fit into cbData bytes. */ + if ((ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA) && + dwType == REG_EXPAND_SZ && !(dwFlags & RRF_NOEXPAND)) + { + do + { + HeapFree(GetProcessHeap(), 0, pvBuf); + + pvBuf = HeapAlloc(GetProcessHeap(), 0, cbData); + if (!pvBuf) + { + ret = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + if (ret == ERROR_MORE_DATA || !pvData) + ret = RegQueryValueExW(hKey, pszValue, NULL, + &dwType, (LPBYTE)pvBuf, &cbData); + else + { + /* Even if cbData was large enough we have to copy the + * string since ExpandEnvironmentStrings can't handle + * overlapping buffers. */ + CopyMemory(pvBuf, pvData, cbData); + } + + /* Both the type or the value itself could have been modified in + * between so we have to keep retrying until the buffer is large + * enough or we no longer have to expand the value. */ + } + while (dwType == REG_EXPAND_SZ && ret == ERROR_MORE_DATA); + + if (ret == ERROR_SUCCESS) + { + /* Recheck dwType in case it changed since the first call */ + if (dwType == REG_EXPAND_SZ) + { + cbData = ExpandEnvironmentStringsW((LPCWSTR)pvBuf, (LPWSTR)pvData, + pcbData ? *pcbData : 0) * sizeof(WCHAR); + dwType = REG_SZ; + if (pvData && pcbData && cbData > *pcbData) + ret = ERROR_MORE_DATA; + } + else if (pvData) + CopyMemory(pvData, pvBuf, *pcbData); + } + + HeapFree(GetProcessHeap(), 0, pvBuf); + } + + if (pszSubKey && pszSubKey[0]) + RegCloseKey(hKey); + + RegpApplyRestrictions(dwFlags, dwType, cbData, &ret); + + if (pvData && ret != ERROR_SUCCESS && (dwFlags & RRF_ZEROONFAILURE)) + ZeroMemory(pvData, *pcbData); + + if (pdwType) + *pdwType = dwType; + + if (pcbData) + *pcbData = cbData; + + return ret; +} diff --git a/reactos/dll/win32/shell32/GlueCode.h b/reactos/dll/win32/shell32/GlueCode.h new file mode 100644 index 00000000000..4803de2cd08 --- /dev/null +++ b/reactos/dll/win32/shell32/GlueCode.h @@ -0,0 +1,11 @@ + +#ifndef _GLUE_CODE_H_ +#define _GLUE_CODE_H_ + +LONG WINAPI RegCopyTreeX(HKEY, LPCWSTR, HKEY); +LONG WINAPI RegGetValueX(HKEY hKey, LPCWSTR pszSubKey, LPCWSTR pszValue, DWORD dwFlags, LPDWORD pdwType, PVOID pvData, LPDWORD pcbData); +LONG WINAPI RegLoadMUIStringWX(IN HKEY hKey, IN LPCWSTR pszValue OPTIONAL, OUT LPWSTR pszOutBuf, IN DWORD cbOutBuf, OUT LPDWORD pcbData OPTIONAL, IN DWORD Flags, IN LPCWSTR pszDirectory OPTIONAL); +LONG WINAPI RegLoadMUIStringAX(IN HKEY hKey, IN LPCSTR pszValue OPTIONAL, OUT LPSTR pszOutBuf, IN DWORD cbOutBuf, OUT LPDWORD pcbData OPTIONAL, IN DWORD Flags, IN LPCSTR pszDirectory OPTIONAL); + +#endif + diff --git a/reactos/dll/win32/shell32/authors.cpp b/reactos/dll/win32/shell32/authors.cpp new file mode 100644 index 00000000000..36243b617b7 --- /dev/null +++ b/reactos/dll/win32/shell32/authors.cpp @@ -0,0 +1,2 @@ + +const char * const SHELL_Authors[] = { "Copyright 1993-2011 WINE team", "Copyright 1998-2011 ReactOS Team", 0 }; diff --git a/reactos/dll/win32/shell32/autocomplete.cpp b/reactos/dll/win32/shell32/autocomplete.cpp new file mode 100644 index 00000000000..103f0a68cd3 --- /dev/null +++ b/reactos/dll/win32/shell32/autocomplete.cpp @@ -0,0 +1,515 @@ +/* + * AutoComplete interfaces implementation. + * + * Copyright 2004 Maxime Bellengé + * 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 + */ + +/* + Implemented: + - ACO_AUTOAPPEND style + - ACO_AUTOSUGGEST style + - ACO_UPDOWNKEYDROPSLIST style + + - Handle pwzsRegKeyPath and pwszQuickComplete in Init + + TODO: + - implement ACO_SEARCH style + - implement ACO_FILTERPREFIXES style + - implement ACO_USETAB style + - implement ACO_RTLREADING style + + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/************************************************************************** + * IAutoComplete_Constructor + */ +CAutoComplete::CAutoComplete() +{ + enabled = TRUE; + options = ACO_AUTOAPPEND; + wpOrigEditProc = NULL; + hwndListBox = NULL; + txtbackup = NULL; + quickComplete = NULL; + hwndEdit = NULL; + wpOrigLBoxProc = NULL; +} + +/************************************************************************** + * IAutoComplete_Destructor + */ +CAutoComplete::~CAutoComplete() +{ + TRACE(" destroying IAutoComplete(%p)\n", this); + HeapFree(GetProcessHeap(), 0, quickComplete); + HeapFree(GetProcessHeap(), 0, txtbackup); + if (hwndListBox) + DestroyWindow(hwndListBox); +} + +/****************************************************************************** + * IAutoComplete_fnEnable + */ +HRESULT WINAPI CAutoComplete::Enable(BOOL fEnable) +{ + HRESULT hr = S_OK; + + TRACE("(%p)->(%s)\n", this, (fEnable) ? "true" : "false"); + + enabled = fEnable; + + return hr; +} + +/****************************************************************************** + * IAutoComplete_fnInit + */ +HRESULT WINAPI CAutoComplete::Init(HWND hwndEdit, IUnknown *punkACL, LPCOLESTR pwzsRegKeyPath, LPCOLESTR pwszQuickComplete) +{ + static const WCHAR lbName[] = {'L','i','s','t','B','o','x',0}; + + TRACE("(%p)->(0x%08lx, %p, %s, %s)\n", + this, hwndEdit, punkACL, debugstr_w(pwzsRegKeyPath), debugstr_w(pwszQuickComplete)); + + if (options & ACO_AUTOSUGGEST) + TRACE(" ACO_AUTOSUGGEST\n"); + if (options & ACO_AUTOAPPEND) + TRACE(" ACO_AUTOAPPEND\n"); + if (options & ACO_SEARCH) + FIXME(" ACO_SEARCH not supported\n"); + if (options & ACO_FILTERPREFIXES) + FIXME(" ACO_FILTERPREFIXES not supported\n"); + if (options & ACO_USETAB) + FIXME(" ACO_USETAB not supported\n"); + if (options & ACO_UPDOWNKEYDROPSLIST) + TRACE(" ACO_UPDOWNKEYDROPSLIST\n"); + if (options & ACO_RTLREADING) + FIXME(" ACO_RTLREADING not supported\n"); + + hwndEdit = hwndEdit; + + if (!SUCCEEDED (punkACL->QueryInterface(IID_IEnumString, (LPVOID *)&enumstr))) + { + TRACE("No IEnumString interface\n"); + return E_NOINTERFACE; + } + + wpOrigEditProc = (WNDPROC)SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, (LONG_PTR) ACEditSubclassProc); + SetWindowLongPtrW(hwndEdit, GWLP_USERDATA, (LONG_PTR)this); + + if (options & ACO_AUTOSUGGEST) + { + HWND hwndParent; + + hwndParent = GetParent(hwndEdit); + + /* FIXME : The listbox should be resizable with the mouse. WS_THICKFRAME looks ugly */ + hwndListBox = CreateWindowExW(0, lbName, NULL, + WS_BORDER | WS_CHILD | WS_VSCROLL | LBS_HASSTRINGS | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + hwndParent, NULL, + (HINSTANCE)GetWindowLongPtrW(hwndParent, GWLP_HINSTANCE), NULL); + + if (hwndListBox) + { + wpOrigLBoxProc = (WNDPROC)SetWindowLongPtrW(hwndListBox, GWLP_WNDPROC, (LONG_PTR)ACLBoxSubclassProc); + SetWindowLongPtrW(hwndListBox, GWLP_USERDATA, (LONG_PTR)this); + } + } + + if (pwzsRegKeyPath) + { + WCHAR *key; + WCHAR result[MAX_PATH]; + WCHAR *value; + HKEY hKey = 0; + LONG res; + LONG len; + + /* pwszRegKeyPath contains the key as well as the value, so we split */ + key = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pwzsRegKeyPath) + 1) * sizeof(WCHAR)); + + if (key) + { + wcscpy(key, pwzsRegKeyPath); + value = const_cast(strrchrW(key, '\\')); + + if (value) + { + *value = 0; + value++; + /* Now value contains the value and buffer the key */ + res = RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_READ, &hKey); + + if (res != ERROR_SUCCESS) + { + /* if the key is not found, MSDN states we must seek in HKEY_LOCAL_MACHINE */ + res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey); + } + + if (res == ERROR_SUCCESS) + { + res = RegQueryValueW(hKey, value, result, &len); + if (res == ERROR_SUCCESS) + { + quickComplete = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); + wcscpy(quickComplete, result); + } + RegCloseKey(hKey); + } + } + + HeapFree(GetProcessHeap(), 0, key); + } + else + { + TRACE("HeapAlloc Failed when trying to alloca %d bytes\n", (wcslen(pwzsRegKeyPath) + 1) * sizeof(WCHAR)); + return S_FALSE; + } + } + + if ((pwszQuickComplete) && (!quickComplete)) + { + quickComplete = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pwszQuickComplete) + 1) * sizeof(WCHAR)); + + if (quickComplete) + { + wcscpy(quickComplete, pwszQuickComplete); + } + else + { + TRACE("HeapAlloc Failed when trying to alloca %d bytes\n", (wcslen(pwszQuickComplete) + 1) * sizeof(WCHAR)); + return S_FALSE; + } + } + + return S_OK; +} + +/************************************************************************** + * IAutoComplete_fnGetOptions + */ +HRESULT WINAPI CAutoComplete::GetOptions(DWORD *pdwFlag) +{ + HRESULT hr = S_OK; + + TRACE("(%p) -> (%p)\n", this, pdwFlag); + + *pdwFlag = options; + + return hr; +} + +/************************************************************************** + * IAutoComplete_fnSetOptions + */ +HRESULT WINAPI CAutoComplete::SetOptions(DWORD dwFlag) +{ + HRESULT hr = S_OK; + + TRACE("(%p) -> (0x%x)\n", this, dwFlag); + + options = (AUTOCOMPLETEOPTIONS)dwFlag; + + return hr; +} + +/* + Window procedure for autocompletion + */ +LRESULT APIENTRY CAutoComplete::ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + CAutoComplete *pThis = (CAutoComplete *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); + LPOLESTR strs; + HRESULT hr; + WCHAR hwndText[255]; + WCHAR *hwndQCText; + RECT r; + BOOL control, filled, displayall = FALSE; + int cpt, height, sel; + + if (!pThis->enabled) + { + return CallWindowProcW(pThis->wpOrigEditProc, hwnd, uMsg, wParam, lParam); + } + + switch (uMsg) + { + case CB_SHOWDROPDOWN: + { + ShowWindow(pThis->hwndListBox, SW_HIDE); + }; break; + + case WM_KILLFOCUS: + { + if ((pThis->options & ACO_AUTOSUGGEST) && ((HWND)wParam != pThis->hwndListBox)) + { + ShowWindow(pThis->hwndListBox, SW_HIDE); + } + return CallWindowProcW(pThis->wpOrigEditProc, hwnd, uMsg, wParam, lParam); + }; break; + + case WM_KEYUP: + { + GetWindowTextW(hwnd, (LPWSTR)hwndText, 255); + + switch(wParam) + { + case VK_RETURN: + { + /* If quickComplete is set and control is pressed, replace the string */ + control = GetKeyState(VK_CONTROL) & 0x8000; + if (control && pThis->quickComplete) + { + hwndQCText = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + (wcslen(pThis->quickComplete)+wcslen(hwndText))*sizeof(WCHAR)); + sel = swprintf(hwndQCText, pThis->quickComplete, hwndText); + SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)hwndQCText); + SendMessageW(hwnd, EM_SETSEL, 0, sel); + HeapFree(GetProcessHeap(), 0, hwndQCText); + } + + ShowWindow(pThis->hwndListBox, SW_HIDE); + return 0; + }; break; + + case VK_LEFT: + case VK_RIGHT: + { + return 0; + }; break; + + case VK_UP: + case VK_DOWN: + { + /* Two cases here : + - if the listbox is not visible, displays it + with all the entries if the style ACO_UPDOWNKEYDROPSLIST + is present but does not select anything. + - if the listbox is visible, change the selection + */ + if ( (pThis->options & (ACO_AUTOSUGGEST | ACO_UPDOWNKEYDROPSLIST)) + && (!IsWindowVisible(pThis->hwndListBox) && (! *hwndText)) ) + { + /* We must display all the entries */ + displayall = TRUE; + } + else + { + if (IsWindowVisible(pThis->hwndListBox)) + { + int count; + + count = SendMessageW(pThis->hwndListBox, LB_GETCOUNT, 0, 0); + /* Change the selection */ + sel = SendMessageW(pThis->hwndListBox, LB_GETCURSEL, 0, 0); + if (wParam == VK_UP) + sel = ((sel-1)<0)?count-1:sel-1; + else + sel = ((sel+1)>= count)?-1:sel+1; + + SendMessageW(pThis->hwndListBox, LB_SETCURSEL, sel, 0); + + if (sel != -1) + { + WCHAR *msg; + int len; + + len = SendMessageW(pThis->hwndListBox, LB_GETTEXTLEN, sel, (LPARAM)NULL); + msg = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len + 1) * sizeof(WCHAR)); + + if (msg) + { + SendMessageW(pThis->hwndListBox, LB_GETTEXT, sel, (LPARAM)msg); + SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)msg); + SendMessageW(hwnd, EM_SETSEL, wcslen(msg), wcslen(msg)); + + HeapFree(GetProcessHeap(), 0, msg); + } + else + { + TRACE("HeapAlloc failed to allocate %d bytes\n", (len + 1) * sizeof(WCHAR)); + } + } + else + { + SendMessageW(hwnd, WM_SETTEXT, 0, (LPARAM)pThis->txtbackup); + SendMessageW(hwnd, EM_SETSEL, wcslen(pThis->txtbackup), wcslen(pThis->txtbackup)); + } + } + return 0; + } + }; break; + + case VK_BACK: + case VK_DELETE: + { + if ((! *hwndText) && (pThis->options & ACO_AUTOSUGGEST)) + { + ShowWindow(pThis->hwndListBox, SW_HIDE); + return CallWindowProcW(pThis->wpOrigEditProc, hwnd, uMsg, wParam, lParam); + } + + if (pThis->options & ACO_AUTOAPPEND) + { + DWORD b; + SendMessageW(hwnd, EM_GETSEL, (WPARAM)&b, (LPARAM)NULL); + if (b>1) + { + hwndText[b-1] = '\0'; + } + else + { + hwndText[0] = '\0'; + SetWindowTextW(hwnd, hwndText); + } + } + }; break; + + default: + ; + } + + SendMessageW(pThis->hwndListBox, LB_RESETCONTENT, 0, 0); + + HeapFree(GetProcessHeap(), 0, pThis->txtbackup); + + pThis->txtbackup = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(hwndText)+1)*sizeof(WCHAR)); + + if (pThis->txtbackup) + { + wcscpy(pThis->txtbackup, hwndText); + } + else + { + TRACE("HeapAlloc failed to allocate %d bytes\n", (wcslen(hwndText)+1)*sizeof(WCHAR)); + } + + /* Returns if there is no text to search and we doesn't want to display all the entries */ + if ((!displayall) && (! *hwndText) ) + break; + + pThis->enumstr->Reset(); + filled = FALSE; + + for(cpt = 0;;) + { + hr = pThis->enumstr->Next(1, &strs, NULL); + if (hr != S_OK) + break; + + if ((LPWSTR)strstrW(strs, hwndText) == strs) + { + + if (pThis->options & ACO_AUTOAPPEND) + { + SetWindowTextW(hwnd, strs); + SendMessageW(hwnd, EM_SETSEL, wcslen(hwndText), wcslen(strs)); + break; + } + + if (pThis->options & ACO_AUTOSUGGEST) + { + SendMessageW(pThis->hwndListBox, LB_ADDSTRING, 0, (LPARAM)strs); + filled = TRUE; + cpt++; + } + } + } + + if (pThis->options & ACO_AUTOSUGGEST) + { + if (filled) + { + height = SendMessageW(pThis->hwndListBox, LB_GETITEMHEIGHT, 0, 0); + SendMessageW(pThis->hwndListBox, LB_CARETOFF, 0, 0); + GetWindowRect(hwnd, &r); + SetParent(pThis->hwndListBox, HWND_DESKTOP); + /* It seems that Windows XP displays 7 lines at most + and otherwise displays a vertical scroll bar */ + SetWindowPos(pThis->hwndListBox, HWND_TOP, + r.left, r.bottom + 1, r.right - r.left, min(height * 7, height * (cpt + 1)), + SWP_SHOWWINDOW ); + } + else + { + ShowWindow(pThis->hwndListBox, SW_HIDE); + } + } + + }; break; + + default: + { + return CallWindowProcW(pThis->wpOrigEditProc, hwnd, uMsg, wParam, lParam); + } + + } + + return 0; +} + +LRESULT APIENTRY CAutoComplete::ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + CAutoComplete *pThis = (CAutoComplete *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); + WCHAR *msg; + int sel, len; + + switch (uMsg) + { + case WM_MOUSEMOVE: + { + sel = SendMessageW(hwnd, LB_ITEMFROMPOINT, 0, lParam); + SendMessageW(hwnd, LB_SETCURSEL, (WPARAM)sel, (LPARAM)0); + }; break; + + case WM_LBUTTONDOWN: + { + sel = SendMessageW(hwnd, LB_GETCURSEL, 0, 0); + + if (sel < 0) + break; + + len = SendMessageW(pThis->hwndListBox, LB_GETTEXTLEN, sel, 0); + msg = (WCHAR *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len + 1) * sizeof(WCHAR)); + + if (msg) + { + SendMessageW(hwnd, LB_GETTEXT, sel, (LPARAM)msg); + SendMessageW(pThis->hwndEdit, WM_SETTEXT, 0, (LPARAM)msg); + SendMessageW(pThis->hwndEdit, EM_SETSEL, 0, wcslen(msg)); + ShowWindow(hwnd, SW_HIDE); + + HeapFree(GetProcessHeap(), 0, msg); + } + else + { + TRACE("HeapAlloc failed to allocate %d bytes\n", (len + 1) * sizeof(WCHAR)); + } + + }; break; + + default: + return CallWindowProcW(pThis->wpOrigLBoxProc, hwnd, uMsg, wParam, lParam); + } + return 0; +} diff --git a/reactos/dll/win32/shell32/autocomplete.h b/reactos/dll/win32/shell32/autocomplete.h new file mode 100644 index 00000000000..d50fe4c1e62 --- /dev/null +++ b/reactos/dll/win32/shell32/autocomplete.h @@ -0,0 +1,65 @@ +/* + * AutoComplete interfaces implementation. + * + * Copyright 2004 Maxime Bellengé + * 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 + */ + +#ifndef _AUTOCOMPLETE_H_ +#define _AUTOCOMPLETE_H_ + +class CAutoComplete : + public CComCoClass, + public CComObjectRootEx, + public IAutoComplete2 +{ +private: + BOOL enabled; + HWND hwndEdit; + HWND hwndListBox; + WNDPROC wpOrigEditProc; + WNDPROC wpOrigLBoxProc; + WCHAR *txtbackup; + WCHAR *quickComplete; + CComPtr enumstr; + AUTOCOMPLETEOPTIONS options; +public: + + CAutoComplete(); + ~CAutoComplete(); + + static LRESULT APIENTRY ACEditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + static LRESULT APIENTRY ACLBoxSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + + // IAutoComplete2 + virtual HRESULT WINAPI Enable(BOOL fEnable); + virtual HRESULT WINAPI Init(HWND hwndEdit, IUnknown *punkACL, LPCOLESTR pwzsRegKeyPath, LPCOLESTR pwszQuickComplete); + virtual HRESULT WINAPI GetOptions(DWORD *pdwFlag); + virtual HRESULT WINAPI SetOptions(DWORD dwFlag); + +DECLARE_REGISTRY_RESOURCEID(IDR_AUTOCOMPLETE) +DECLARE_NOT_AGGREGATABLE(CAutoComplete) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CAutoComplete) + COM_INTERFACE_ENTRY_IID(IID_IAutoComplete, IAutoComplete) + COM_INTERFACE_ENTRY_IID(IID_IAutoComplete2, IAutoComplete2) +END_COM_MAP() +}; + +#endif // _AUTOCOMPLETE_H_ diff --git a/reactos/dll/win32/shell32/basebar.cpp b/reactos/dll/win32/shell32/basebar.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/basebar.h b/reactos/dll/win32/shell32/basebar.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/brsfolder.cpp b/reactos/dll/win32/shell32/brsfolder.cpp new file mode 100644 index 00000000000..2d66bddaaf5 --- /dev/null +++ b/reactos/dll/win32/shell32/brsfolder.cpp @@ -0,0 +1,816 @@ +/* + * Copyright 1999 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 + * + * FIXME: + * - many memory leaks + * - many flags unimplemented + * - implement new dialog style "make new folder" button + * - implement editbox + * - implement new dialog style resizing + */ + +#include + + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +typedef struct tagbrowse_info +{ + HWND hWnd; + HWND hwndTreeView; + LPBROWSEINFOW lpBrowseInfo; + LPITEMIDLIST pidlRet; +} browse_info; + +typedef struct tagTV_ITEMDATA +{ + LPSHELLFOLDER lpsfParent; /* IShellFolder of the parent */ + LPITEMIDLIST lpi; /* PIDL relative to parent */ + LPITEMIDLIST lpifq; /* Fully qualified PIDL */ + IEnumIDList* pEnumIL; /* Children iterator */ +} TV_ITEMDATA, *LPTV_ITEMDATA; + +#define SUPPORTEDFLAGS (BIF_STATUSTEXT | \ + BIF_BROWSEFORCOMPUTER | \ + BIF_RETURNFSANCESTORS | \ + BIF_RETURNONLYFSDIRS | \ + BIF_NONEWFOLDERBUTTON | \ + BIF_NEWDIALOGSTYLE | \ + BIF_BROWSEINCLUDEFILES) + +static void FillTreeView(browse_info*, LPSHELLFOLDER, + LPITEMIDLIST, HTREEITEM, IEnumIDList*); +static HTREEITEM InsertTreeViewItem( browse_info*, IShellFolder *, + LPCITEMIDLIST, LPCITEMIDLIST, IEnumIDList*, HTREEITEM); + +static const WCHAR szBrowseFolderInfo[] = { + '_','_','W','I','N','E','_', + 'B','R','S','F','O','L','D','E','R','D','L','G','_', + 'I','N','F','O',0 +}; + +static DWORD __inline BrowseFlagsToSHCONTF(UINT ulFlags) +{ + return SHCONTF_FOLDERS | (ulFlags & BIF_BROWSEINCLUDEFILES ? SHCONTF_NONFOLDERS : 0); +} + +static void browsefolder_callback( LPBROWSEINFOW lpBrowseInfo, HWND hWnd, + UINT msg, LPARAM param ) +{ + if (!lpBrowseInfo->lpfn) + return; + lpBrowseInfo->lpfn( hWnd, msg, param, lpBrowseInfo->lParam ); +} + +/****************************************************************************** + * InitializeTreeView [Internal] + * + * Called from WM_INITDIALOG handler. + * + * PARAMS + * hwndParent [I] The BrowseForFolder dialog + * root [I] ITEMIDLIST of the root shell folder + */ +static void InitializeTreeView( browse_info *info ) +{ + LPITEMIDLIST pidlParent, pidlChild; + HIMAGELIST hImageList; + HRESULT hr; + IShellFolder *lpsfParent, *lpsfRoot; + IEnumIDList * pEnumChildren = NULL; + HTREEITEM item; + DWORD flags; + LPCITEMIDLIST root = info->lpBrowseInfo->pidlRoot; + + TRACE("%p\n", info ); + + Shell_GetImageLists(NULL, &hImageList); + + if (hImageList) + SendMessageW( info->hwndTreeView, TVM_SETIMAGELIST, 0, (LPARAM)hImageList ); + + /* We want to call InsertTreeViewItem down the code, in order to insert + * the root item of the treeview. Due to InsertTreeViewItem's signature, + * we need the following to do this: + * + * + An ITEMIDLIST corresponding to _the parent_ of root. + * + An ITEMIDLIST, which is a relative path from root's parent to root + * (containing a single SHITEMID). + * + An IShellFolder interface pointer of root's parent folder. + * + * If root is 'Desktop', then root's parent is also 'Desktop'. + */ + + pidlParent = ILClone(root); + ILRemoveLastID(pidlParent); + pidlChild = ILClone(ILFindLastID(root)); + + if (_ILIsDesktop(pidlParent)) { + hr = SHGetDesktopFolder(&lpsfParent); + } else { + IShellFolder *lpsfDesktop; + hr = SHGetDesktopFolder(&lpsfDesktop); + if (!SUCCEEDED(hr)) { + WARN("SHGetDesktopFolder failed! hr = %08x\n", hr); + return; + } + hr = lpsfDesktop->BindToObject(pidlParent, 0, IID_IShellFolder, (LPVOID *)&lpsfParent); + lpsfDesktop->Release(); + } + + if (!SUCCEEDED(hr)) { + WARN("Could not bind to parent shell folder! hr = %08x\n", hr); + return; + } + + if (pidlChild && pidlChild->mkid.cb) { + hr = lpsfParent->BindToObject(pidlChild, 0, IID_IShellFolder, (LPVOID *)&lpsfRoot); + } else { + lpsfRoot = lpsfParent; + hr = lpsfParent->AddRef(); + } + + if (!SUCCEEDED(hr)) { + WARN("Could not bind to root shell folder! hr = %08x\n", hr); + lpsfParent->Release(); + return; + } + + flags = BrowseFlagsToSHCONTF( info->lpBrowseInfo->ulFlags ); + hr = lpsfRoot->EnumObjects(info->hWnd, flags, &pEnumChildren ); + if (!SUCCEEDED(hr)) { + WARN("Could not get child iterator! hr = %08x\n", hr); + lpsfParent->Release(); + lpsfRoot->Release(); + return; + } + + SendMessageW( info->hwndTreeView, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT ); + item = InsertTreeViewItem( info, lpsfParent, pidlChild, + pidlParent, pEnumChildren, TVI_ROOT ); + SendMessageW( info->hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)item ); + + lpsfRoot->Release(); + lpsfParent->Release(); +} + +static int GetIcon(LPCITEMIDLIST lpi, UINT uFlags) +{ + SHFILEINFOW sfi; + SHGetFileInfoW((LPCWSTR)lpi, 0 ,&sfi, sizeof(SHFILEINFOW), uFlags); + return sfi.iIcon; +} + +static void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTVITEMW lpTV_ITEM) +{ + LPITEMIDLIST pidlDesktop = NULL; + DWORD flags; + + TRACE("%p %p\n",lpifq, lpTV_ITEM); + + if (!lpifq) + { + pidlDesktop = _ILCreateDesktop(); + lpifq = pidlDesktop; + } + + flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON; + lpTV_ITEM->iImage = GetIcon( lpifq, flags ); + + flags = SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON; + lpTV_ITEM->iSelectedImage = GetIcon( lpifq, flags ); + + if (pidlDesktop) + ILFree( pidlDesktop ); +} + +/****************************************************************************** + * GetName [Internal] + * + * Query a shell folder for the display name of one of it's children + * + * PARAMS + * lpsf [I] IShellFolder interface of the folder to be queried. + * lpi [I] ITEMIDLIST of the child, relative to parent + * dwFlags [I] as in IShellFolder::GetDisplayNameOf + * lpFriendlyName [O] The desired display name in unicode + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +static BOOL GetName(LPSHELLFOLDER lpsf, LPCITEMIDLIST lpi, DWORD dwFlags, LPWSTR lpFriendlyName) +{ + BOOL bSuccess=TRUE; + STRRET str; + + TRACE("%p %p %x %p\n", lpsf, lpi, dwFlags, lpFriendlyName); + if (SUCCEEDED(lpsf->GetDisplayNameOf(lpi, dwFlags, &str))) + bSuccess = StrRetToStrNW(lpFriendlyName, MAX_PATH, &str, lpi); + else + bSuccess = FALSE; + + TRACE("-- %s\n", debugstr_w(lpFriendlyName)); + return bSuccess; +} + +/****************************************************************************** + * InsertTreeViewItem [Internal] + * + * PARAMS + * info [I] data for the dialog + * lpsf [I] IShellFolder interface of the item's parent shell folder + * pidl [I] ITEMIDLIST of the child to insert, relative to parent + * pidlParent [I] ITEMIDLIST of the parent shell folder + * pEnumIL [I] Iterator for the children of the item to be inserted + * hParent [I] The treeview-item that represents the parent shell folder + * + * RETURNS + * Success: Handle to the created and inserted treeview-item + * Failure: NULL + */ +static HTREEITEM InsertTreeViewItem( browse_info *info, IShellFolder * lpsf, + LPCITEMIDLIST pidl, LPCITEMIDLIST pidlParent, IEnumIDList* pEnumIL, + HTREEITEM hParent) +{ + TVITEMW tvi; + TVINSERTSTRUCTW tvins; + WCHAR szBuff[MAX_PATH]; + LPTV_ITEMDATA lptvid=0; + + tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM; + + tvi.cChildren= pEnumIL ? 1 : 0; + tvi.mask |= TVIF_CHILDREN; + + lptvid = (TV_ITEMDATA *)SHAlloc( sizeof(TV_ITEMDATA) ); + if (!lptvid) + return NULL; + + if (!GetName(lpsf, pidl, SHGDN_NORMAL, szBuff)) + return NULL; + + tvi.pszText = szBuff; + tvi.cchTextMax = MAX_PATH; + tvi.lParam = (LPARAM)lptvid; + + lpsf->AddRef(); + lptvid->lpsfParent = lpsf; + lptvid->lpi = ILClone(pidl); + lptvid->lpifq = pidlParent ? ILCombine(pidlParent, pidl) : ILClone(pidl); + lptvid->pEnumIL = pEnumIL; + GetNormalAndSelectedIcons(lptvid->lpifq, &tvi); + + tvins.item = tvi; + tvins.hInsertAfter = NULL; + tvins.hParent = hParent; + + return (HTREEITEM)SendMessageW(info->hwndTreeView, TVM_INSERTITEM, 0, (LPARAM)&tvins ); +} + +/****************************************************************************** + * FillTreeView [Internal] + * + * For each child (given by lpe) of the parent shell folder, which is given by + * lpsf and whose PIDL is pidl, insert a treeview-item right under hParent + * + * PARAMS + * info [I] data for the dialog + * lpsf [I] IShellFolder interface of the parent shell folder + * pidl [I] ITEMIDLIST of the parent shell folder + * hParent [I] The treeview item that represents the parent shell folder + * lpe [I] An iterator for the children of the parent shell folder + */ +static void FillTreeView( browse_info *info, IShellFolder * lpsf, + LPITEMIDLIST pidl, HTREEITEM hParent, IEnumIDList* lpe) +{ + HTREEITEM hPrev = 0; + LPITEMIDLIST pidlTemp = 0; + ULONG ulFetched; + HRESULT hr; + HWND hwnd = GetParent( info->hwndTreeView ); + + TRACE("%p %p %p %p\n",lpsf, pidl, hParent, lpe); + + /* No IEnumIDList -> No children */ + if (!lpe) return; + + SetCapture( hwnd ); + SetCursor( LoadCursorA( 0, (LPSTR)IDC_WAIT ) ); + + while (NOERROR == lpe->Next(1,&pidlTemp,&ulFetched)) + { + ULONG ulAttrs = SFGAO_HASSUBFOLDER | SFGAO_FOLDER; + IEnumIDList* pEnumIL = NULL; + IShellFolder* pSFChild = NULL; + lpsf->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlTemp, &ulAttrs); + if (ulAttrs & SFGAO_FOLDER) + { + hr = lpsf->BindToObject(pidlTemp, NULL, IID_IShellFolder, (LPVOID *)&pSFChild); + if (SUCCEEDED(hr)) + { + DWORD flags = BrowseFlagsToSHCONTF(info->lpBrowseInfo->ulFlags); + hr = pSFChild->EnumObjects(hwnd, flags, &pEnumIL); + if (hr == S_OK) + { + if ((pEnumIL->Skip(1) != S_OK) || + FAILED(pEnumIL->Reset())) + { + pEnumIL->Release(); + pEnumIL = NULL; + } + } + pSFChild->Release(); + } + } + + if (!(hPrev = InsertTreeViewItem(info, lpsf, pidlTemp, pidl, pEnumIL, hParent))) + goto done; + SHFree(pidlTemp); /* Finally, free the pidl that the shell gave us... */ + pidlTemp=NULL; + } + +done: + ReleaseCapture(); + SetCursor(LoadCursorW(0, (LPWSTR)IDC_ARROW)); + SHFree(pidlTemp); +} + +static BOOL __inline PIDLIsType(LPCITEMIDLIST pidl, PIDLTYPE type) +{ + LPPIDLDATA data = _ILGetDataPointer(pidl); + if (!data) + return FALSE; + return (data->type == type); +} + +static void BrsFolder_CheckValidSelection( browse_info *info, LPTV_ITEMDATA lptvid ) +{ + LPBROWSEINFOW lpBrowseInfo = info->lpBrowseInfo; + LPCITEMIDLIST pidl = lptvid->lpi; + BOOL bEnabled = TRUE; + DWORD dwAttributes; + HRESULT r; + + if ((lpBrowseInfo->ulFlags & BIF_BROWSEFORCOMPUTER) && + !PIDLIsType(pidl, PT_COMP)) + bEnabled = FALSE; + if (lpBrowseInfo->ulFlags & BIF_RETURNFSANCESTORS) + { + dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM; + r = lptvid->lpsfParent->GetAttributesOf(1, + (LPCITEMIDLIST*)&lptvid->lpi, &dwAttributes); + if (FAILED(r) || !(dwAttributes & (SFGAO_FILESYSANCESTOR|SFGAO_FILESYSTEM))) + bEnabled = FALSE; + } + if (lpBrowseInfo->ulFlags & BIF_RETURNONLYFSDIRS) + { + dwAttributes = SFGAO_FOLDER | SFGAO_FILESYSTEM; + r = lptvid->lpsfParent->GetAttributesOf(1, + (LPCITEMIDLIST*)&lptvid->lpi, &dwAttributes); + if (FAILED(r) || + ((dwAttributes & (SFGAO_FOLDER|SFGAO_FILESYSTEM)) != (SFGAO_FOLDER|SFGAO_FILESYSTEM))) + { + bEnabled = FALSE; + } + } + SendMessageW(info->hWnd, BFFM_ENABLEOK, 0, (LPARAM)bEnabled); +} + +static LRESULT BrsFolder_Treeview_Delete( browse_info *info, NMTREEVIEWW *pnmtv ) +{ + LPTV_ITEMDATA lptvid = (LPTV_ITEMDATA)pnmtv->itemOld.lParam; + + TRACE("TVN_DELETEITEMA/W %p\n", lptvid); + + lptvid->lpsfParent->Release(); + if (lptvid->pEnumIL) + lptvid->pEnumIL->Release(); + SHFree(lptvid->lpi); + SHFree(lptvid->lpifq); + SHFree(lptvid); + return 0; +} + +static LRESULT BrsFolder_Treeview_Expand( browse_info *info, NMTREEVIEWW *pnmtv ) +{ + IShellFolder *lpsf2 = NULL; + LPTV_ITEMDATA lptvid = (LPTV_ITEMDATA) pnmtv->itemNew.lParam; + HRESULT r; + + TRACE("TVN_ITEMEXPANDINGA/W\n"); + + if ((pnmtv->itemNew.state & TVIS_EXPANDEDONCE)) + return 0; + + if (lptvid->lpi && lptvid->lpi->mkid.cb) { + r = lptvid->lpsfParent->BindToObject(lptvid->lpi, 0, + IID_IShellFolder, (LPVOID *)&lpsf2 ); + } else { + lpsf2 = lptvid->lpsfParent; + r = lpsf2->AddRef(); + } + + if (SUCCEEDED(r)) + FillTreeView( info, lpsf2, lptvid->lpifq, pnmtv->itemNew.hItem, lptvid->pEnumIL); + + /* My Computer is already sorted and trying to do a simple text + * sort will only mess things up */ + if (!_ILIsMyComputer(lptvid->lpi)) + SendMessageW( info->hwndTreeView, TVM_SORTCHILDREN, + FALSE, (LPARAM)pnmtv->itemNew.hItem ); + + return 0; +} + +static HRESULT BrsFolder_Treeview_Changed( browse_info *info, NMTREEVIEWW *pnmtv ) +{ + LPTV_ITEMDATA lptvid = (LPTV_ITEMDATA) pnmtv->itemNew.lParam; + + lptvid = (LPTV_ITEMDATA) pnmtv->itemNew.lParam; + info->pidlRet = lptvid->lpifq; + browsefolder_callback( info->lpBrowseInfo, info->hWnd, BFFM_SELCHANGED, + (LPARAM)info->pidlRet ); + BrsFolder_CheckValidSelection( info, lptvid ); + return 0; +} + +static LRESULT BrsFolder_OnNotify( browse_info *info, UINT CtlID, LPNMHDR lpnmh ) +{ + NMTREEVIEWW *pnmtv = (NMTREEVIEWW *)lpnmh; + + TRACE("%p %x %p msg=%x\n", info, CtlID, lpnmh, pnmtv->hdr.code); + + if (pnmtv->hdr.idFrom != IDD_TREEVIEW) + return 0; + + switch (pnmtv->hdr.code) + { + case TVN_DELETEITEMA: + case TVN_DELETEITEMW: + return BrsFolder_Treeview_Delete( info, pnmtv ); + + case TVN_ITEMEXPANDINGA: + case TVN_ITEMEXPANDINGW: + return BrsFolder_Treeview_Expand( info, pnmtv ); + + case TVN_SELCHANGEDA: + case TVN_SELCHANGEDW: + return BrsFolder_Treeview_Changed( info, pnmtv ); + + default: + WARN("unhandled (%d)\n", pnmtv->hdr.code); + break; + } + + return 0; +} + + +static BOOL BrsFolder_OnCreate( HWND hWnd, browse_info *info ) +{ + LPBROWSEINFOW lpBrowseInfo = info->lpBrowseInfo; + + info->hWnd = hWnd; + SetPropW( hWnd, szBrowseFolderInfo, info ); + + if (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE) + FIXME("flags BIF_NEWDIALOGSTYLE partially implemented\n"); + if (lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS) + FIXME("flags %x not implemented\n", lpBrowseInfo->ulFlags & ~SUPPORTEDFLAGS); + + if (lpBrowseInfo->lpszTitle) + SetWindowTextW( GetDlgItem(hWnd, IDD_TITLE), lpBrowseInfo->lpszTitle ); + else + ShowWindow( GetDlgItem(hWnd, IDD_TITLE), SW_HIDE ); + + if (!(lpBrowseInfo->ulFlags & BIF_STATUSTEXT) + || (lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE)) + ShowWindow( GetDlgItem(hWnd, IDD_STATUS), SW_HIDE ); + + /* Hide "Make New Folder" Button? */ + if ((lpBrowseInfo->ulFlags & BIF_NONEWFOLDERBUTTON) + || !(lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE)) + ShowWindow( GetDlgItem(hWnd, IDD_MAKENEWFOLDER), SW_HIDE ); + + /* Hide the editbox? */ + if (!(lpBrowseInfo->ulFlags & BIF_EDITBOX)) + { + ShowWindow( GetDlgItem(hWnd, IDD_FOLDER), SW_HIDE ); + ShowWindow( GetDlgItem(hWnd, IDD_FOLDERTEXT), SW_HIDE ); + } + + info->hwndTreeView = GetDlgItem( hWnd, IDD_TREEVIEW ); + if (info->hwndTreeView) + { + InitializeTreeView( info ); + + /* Resize the treeview if there's not editbox */ + if ((lpBrowseInfo->ulFlags & BIF_NEWDIALOGSTYLE) + && !(lpBrowseInfo->ulFlags & BIF_EDITBOX)) + { + RECT rc; + GetClientRect(info->hwndTreeView, &rc); + SetWindowPos(info->hwndTreeView, HWND_TOP, 0, 0, + rc.right, rc.bottom + 40, SWP_NOMOVE); + } + } + else + ERR("treeview control missing!\n"); + + browsefolder_callback( info->lpBrowseInfo, hWnd, BFFM_INITIALIZED, 0 ); + + return TRUE; +} + +static BOOL BrsFolder_OnCommand( browse_info *info, UINT id ) +{ + LPBROWSEINFOW lpBrowseInfo = info->lpBrowseInfo; + + switch (id) + { + case IDOK: + /* The original pidl is owned by the treeview and will be free'd. */ + info->pidlRet = ILClone(info->pidlRet); + if (info->pidlRet == NULL) /* A null pidl would mean a cancel */ + info->pidlRet = _ILCreateDesktop(); + pdump( info->pidlRet ); + if (lpBrowseInfo->pszDisplayName) + SHGetPathFromIDListW( info->pidlRet, lpBrowseInfo->pszDisplayName ); + EndDialog( info->hWnd, 1 ); + return TRUE; + + case IDCANCEL: + EndDialog( info->hWnd, 0 ); + return TRUE; + + case IDD_MAKENEWFOLDER: + FIXME("make new folder not implemented\n"); + return TRUE; + } + return FALSE; +} + +static BOOL BrsFolder_OnSetExpanded(browse_info *info, LPVOID selection, + BOOL is_str, HTREEITEM *pItem) +{ + LPITEMIDLIST pidlSelection = (LPITEMIDLIST)selection; + LPCITEMIDLIST pidlCurrent, pidlRoot; + TVITEMEXW item; + BOOL bResult = FALSE; + + /* If 'selection' is a string, convert to a Shell ID List. */ + if (is_str) { + IShellFolder *psfDesktop; + HRESULT hr; + + hr = SHGetDesktopFolder(&psfDesktop); + if (FAILED(hr)) + goto done; + + hr = psfDesktop->ParseDisplayName(NULL, NULL, + (LPOLESTR)selection, NULL, &pidlSelection, NULL); + psfDesktop->Release(); + if (FAILED(hr)) + goto done; + } + + /* Move pidlCurrent behind the SHITEMIDs in pidlSelection, which are the root of + * the sub-tree currently displayed. */ + pidlRoot = info->lpBrowseInfo->pidlRoot; + pidlCurrent = pidlSelection; + while (!_ILIsEmpty(pidlRoot) && _ILIsEqualSimple(pidlRoot, pidlCurrent)) { + pidlRoot = ILGetNext(pidlRoot); + pidlCurrent = ILGetNext(pidlCurrent); + } + + /* The given ID List is not part of the SHBrowseForFolder's current sub-tree. */ + if (!_ILIsEmpty(pidlRoot)) + goto done; + + /* Initialize item to point to the first child of the root folder. */ + memset(&item, 0, sizeof(item)); + item.mask = TVIF_PARAM; + item.hItem = TreeView_GetRoot(info->hwndTreeView); + if (item.hItem) + item.hItem = TreeView_GetChild(info->hwndTreeView, item.hItem); + + /* Walk the tree along the nodes corresponding to the remaining ITEMIDLIST */ + while (item.hItem && !_ILIsEmpty(pidlCurrent)) { + LPTV_ITEMDATA pItemData; + + SendMessageW(info->hwndTreeView, TVM_GETITEMW, 0, (LPARAM)&item); + pItemData = (LPTV_ITEMDATA)item.lParam; + + if (_ILIsEqualSimple(pItemData->lpi, pidlCurrent)) { + pidlCurrent = ILGetNext(pidlCurrent); + if (!_ILIsEmpty(pidlCurrent)) { + /* Only expand current node and move on to it's first child, + * if we didn't already reach the last SHITEMID */ + SendMessageW(info->hwndTreeView, TVM_EXPAND, TVE_EXPAND, (LPARAM)item.hItem); + item.hItem = TreeView_GetChild(info->hwndTreeView, item.hItem); + } + } else { + item.hItem = TreeView_GetNextSibling(info->hwndTreeView, item.hItem); + } + } + + if (_ILIsEmpty(pidlCurrent) && item.hItem) + bResult = TRUE; + +done: + if (pidlSelection && pidlSelection != (LPITEMIDLIST)selection) + ILFree(pidlSelection); + + if (pItem) + *pItem = item.hItem; + + return bResult; +} + +static BOOL BrsFolder_OnSetSelectionW(browse_info *info, LPVOID selection, BOOL is_str) { + HTREEITEM hItem; + BOOL bResult; + + bResult = BrsFolder_OnSetExpanded(info, selection, is_str, &hItem); + if (bResult) + SendMessageW(info->hwndTreeView, TVM_SELECTITEM, TVGN_CARET, (LPARAM)hItem ); + return bResult; +} + +static BOOL BrsFolder_OnSetSelectionA(browse_info *info, LPVOID selection, BOOL is_str) { + LPWSTR selectionW = NULL; + BOOL result = FALSE; + int length; + + if (!is_str) + return BrsFolder_OnSetSelectionW(info, selection, is_str); + + if ((length = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)selection, -1, NULL, 0)) && + (selectionW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, length * sizeof(WCHAR))) && + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)selection, -1, selectionW, length)) + { + result = BrsFolder_OnSetSelectionW(info, selectionW, is_str); + } + + HeapFree(GetProcessHeap(), 0, selectionW); + return result; +} + +/************************************************************************* + * BrsFolderDlgProc32 (not an exported API function) + */ +static INT_PTR CALLBACK BrsFolderDlgProc( HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam ) +{ + browse_info *info; + + TRACE("hwnd=%p msg=%04x 0x%08lx 0x%08lx\n", hWnd, msg, wParam, lParam ); + + if (msg == WM_INITDIALOG) + return BrsFolder_OnCreate( hWnd, (browse_info*) lParam ); + + info = (browse_info*) GetPropW( hWnd, szBrowseFolderInfo ); + + switch (msg) + { + case WM_NOTIFY: + return BrsFolder_OnNotify( info, (UINT)wParam, (LPNMHDR)lParam); + + case WM_COMMAND: + return BrsFolder_OnCommand( info, wParam ); + + case BFFM_SETSTATUSTEXTA: + TRACE("Set status %s\n", debugstr_a((LPSTR)lParam)); + SetWindowTextA(GetDlgItem(hWnd, IDD_STATUS), (LPSTR)lParam); + break; + + case BFFM_SETSTATUSTEXTW: + TRACE("Set status %s\n", debugstr_w((LPWSTR)lParam)); + SetWindowTextW(GetDlgItem(hWnd, IDD_STATUS), (LPWSTR)lParam); + break; + + case BFFM_ENABLEOK: + TRACE("Enable %ld\n", lParam); + EnableWindow(GetDlgItem(hWnd, 1), (lParam)?TRUE:FALSE); + break; + + case BFFM_SETOKTEXT: /* unicode only */ + TRACE("Set OK text %s\n", debugstr_w((LPWSTR)wParam)); + SetWindowTextW(GetDlgItem(hWnd, 1), (LPWSTR)wParam); + break; + + case BFFM_SETSELECTIONA: + return BrsFolder_OnSetSelectionA(info, (LPVOID)lParam, (BOOL)wParam); + + case BFFM_SETSELECTIONW: + return BrsFolder_OnSetSelectionW(info, (LPVOID)lParam, (BOOL)wParam); + + case BFFM_SETEXPANDED: /* unicode only */ + return BrsFolder_OnSetExpanded(info, (LPVOID)lParam, (BOOL)wParam, NULL); + } + return FALSE; +} + +static const WCHAR swBrowseTemplateName[] = { + 'S','H','B','R','S','F','O','R','F','O','L','D','E','R','_','M','S','G','B','O','X',0}; +static const WCHAR swNewBrowseTemplateName[] = { + 'S','H','N','E','W','B','R','S','F','O','R','F','O','L','D','E','R','_','M','S','G','B','O','X',0}; + +/************************************************************************* + * SHBrowseForFolderA [SHELL32.@] + * SHBrowseForFolder [SHELL32.@] + */ +LPITEMIDLIST WINAPI SHBrowseForFolderA (LPBROWSEINFOA lpbi) +{ + BROWSEINFOW bi; + LPITEMIDLIST lpid; + INT len; + LPWSTR title; + + TRACE("%p\n", lpbi); + + bi.hwndOwner = lpbi->hwndOwner; + bi.pidlRoot = lpbi->pidlRoot; + if (lpbi->pszDisplayName) + { + bi.pszDisplayName = (WCHAR *)HeapAlloc( GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, lpbi->pszDisplayName, -1, bi.pszDisplayName, MAX_PATH ); + } + else + bi.pszDisplayName = NULL; + + if (lpbi->lpszTitle) + { + len = MultiByteToWideChar( CP_ACP, 0, lpbi->lpszTitle, -1, NULL, 0 ); + title = (WCHAR *)HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, lpbi->lpszTitle, -1, title, len ); + } + else + title = NULL; + + bi.lpszTitle = title; + bi.ulFlags = lpbi->ulFlags; + bi.lpfn = lpbi->lpfn; + bi.lParam = lpbi->lParam; + bi.iImage = lpbi->iImage; + lpid = SHBrowseForFolderW( &bi ); + if (bi.pszDisplayName) + { + WideCharToMultiByte( CP_ACP, 0, bi.pszDisplayName, -1, + lpbi->pszDisplayName, MAX_PATH, 0, NULL); + HeapFree( GetProcessHeap(), 0, bi.pszDisplayName ); + } + HeapFree(GetProcessHeap(), 0, title); + lpbi->iImage = bi.iImage; + return lpid; +} + + +/************************************************************************* + * SHBrowseForFolderW [SHELL32.@] + * + * NOTES + * crashes when passed a null pointer + */ +LPITEMIDLIST WINAPI SHBrowseForFolderW (LPBROWSEINFOW lpbi) +{ + browse_info info; + DWORD r; + HRESULT hr; + const WCHAR * templateName; + + info.hWnd = 0; + info.pidlRet = NULL; + info.lpBrowseInfo = lpbi; + info.hwndTreeView = NULL; + + hr = OleInitialize(NULL); + + if (lpbi->ulFlags & BIF_NEWDIALOGSTYLE) + templateName = swNewBrowseTemplateName; + else + templateName = swBrowseTemplateName; + r = DialogBoxParamW( shell32_hInstance, templateName, lpbi->hwndOwner, + BrsFolderDlgProc, (LPARAM)&info ); + if (SUCCEEDED(hr)) + OleUninitialize(); + if (!r) + return NULL; + + return info.pidlRet; +} diff --git a/reactos/dll/win32/shell32/changenotify.cpp b/reactos/dll/win32/shell32/changenotify.cpp new file mode 100644 index 00000000000..c9c85967b7b --- /dev/null +++ b/reactos/dll/win32/shell32/changenotify.cpp @@ -0,0 +1,476 @@ +/* + * shell change notification + * + * Copyright 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 + */ + +#include + + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +namespace +{ + extern CRITICAL_SECTION SHELL32_ChangenotifyCS; + CRITICAL_SECTION_DEBUG critsect_debug = + { + 0, 0, &SHELL32_ChangenotifyCS, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_ChangenotifyCS") } + }; + CRITICAL_SECTION SHELL32_ChangenotifyCS = { &critsect_debug, -1, 0, 0, 0, 0 }; +} + +typedef SHChangeNotifyEntry *LPNOTIFYREGISTER; + +/* internal list of notification clients (internal) */ +typedef struct _NOTIFICATIONLIST +{ + struct _NOTIFICATIONLIST *next; + struct _NOTIFICATIONLIST *prev; + HWND hwnd; /* window to notify */ + DWORD uMsg; /* message to send */ + LPNOTIFYREGISTER apidl; /* array of entries to watch*/ + UINT cidl; /* number of pidls in array */ + LONG wEventMask; /* subscribed events */ + LONG wSignalledEvent; /* event that occurred */ + DWORD dwFlags; /* client flags */ + LPCITEMIDLIST pidlSignaled; /*pidl of the path that caused the signal*/ + +} NOTIFICATIONLIST, *LPNOTIFICATIONLIST; + +static NOTIFICATIONLIST *head, *tail; + +#define SHCNE_NOITEMEVENTS ( \ + SHCNE_ASSOCCHANGED ) + +#define SHCNE_ONEITEMEVENTS ( \ + SHCNE_ATTRIBUTES | SHCNE_CREATE | SHCNE_DELETE | SHCNE_DRIVEADD | \ + SHCNE_DRIVEADDGUI | SHCNE_DRIVEREMOVED | SHCNE_FREESPACE | \ + SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED | SHCNE_MKDIR | \ + SHCNE_NETSHARE | SHCNE_NETUNSHARE | SHCNE_RMDIR | \ + SHCNE_SERVERDISCONNECT | SHCNE_UPDATEDIR | SHCNE_UPDATEIMAGE ) + +#define SHCNE_TWOITEMEVENTS ( \ + SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM ) + +/* for dumping events */ +static const char * DumpEvent( LONG event ) +{ + if( event == SHCNE_ALLEVENTS ) + return "SHCNE_ALLEVENTS"; +#define DUMPEV(x) ,( event & SHCNE_##x )? #x " " : "" + return wine_dbg_sprintf( "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s" + DUMPEV(RENAMEITEM) + DUMPEV(CREATE) + DUMPEV(DELETE) + DUMPEV(MKDIR) + DUMPEV(RMDIR) + DUMPEV(MEDIAINSERTED) + DUMPEV(MEDIAREMOVED) + DUMPEV(DRIVEREMOVED) + DUMPEV(DRIVEADD) + DUMPEV(NETSHARE) + DUMPEV(NETUNSHARE) + DUMPEV(ATTRIBUTES) + DUMPEV(UPDATEDIR) + DUMPEV(UPDATEITEM) + DUMPEV(SERVERDISCONNECT) + DUMPEV(UPDATEIMAGE) + DUMPEV(DRIVEADDGUI) + DUMPEV(RENAMEFOLDER) + DUMPEV(FREESPACE) + DUMPEV(EXTENDED_EVENT) + DUMPEV(ASSOCCHANGED) + DUMPEV(INTERRUPT) + ); +#undef DUMPEV +} + +static const char * NodeName(const NOTIFICATIONLIST *item) +{ + const char *str; + WCHAR path[MAX_PATH]; + + if(SHGetPathFromIDListW(item->apidl[0].pidl, path )) + str = wine_dbg_sprintf("%s", debugstr_w(path)); + else + str = wine_dbg_sprintf("" ); + return str; +} + +static void AddNode(LPNOTIFICATIONLIST item) +{ + TRACE("item %p\n", item ); + + /* link items */ + item->prev = tail; + item->next = NULL; + if( tail ) + tail->next = item; + else + head = item; + tail = item; +} + +static LPNOTIFICATIONLIST FindNode( HANDLE hitem ) +{ + LPNOTIFICATIONLIST ptr; + for( ptr = head; ptr; ptr = ptr->next ) + if( ptr == (LPNOTIFICATIONLIST) hitem ) + return ptr; + return NULL; +} + +static void DeleteNode(LPNOTIFICATIONLIST item) +{ + UINT i; + + TRACE("item=%p prev=%p next=%p\n", item, item->prev, item->next); + + /* remove item from list */ + if( item->prev ) + item->prev->next = item->next; + else + head = item->next; + if( item->next ) + item->next->prev = item->prev; + else + tail = item->prev; + + /* free the item */ + for (i=0; icidl; i++) + SHFree((LPITEMIDLIST)item->apidl[i].pidl); + SHFree(item->apidl); + SHFree(item); +} + +void InitChangeNotifications(void) +{ +} + +void FreeChangeNotifications(void) +{ + TRACE("\n"); + + EnterCriticalSection(&SHELL32_ChangenotifyCS); + + while( head ) + DeleteNode( head ); + + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + + // DeleteCriticalSection(&SHELL32_ChangenotifyCS); // static +} + +/************************************************************************* + * SHChangeNotifyRegister [SHELL32.2] + * + */ +ULONG WINAPI +SHChangeNotifyRegister( + HWND hwnd, + int fSources, + LONG wEventMask, + UINT uMsg, + int cItems, + SHChangeNotifyEntry *lpItems) +{ + LPNOTIFICATIONLIST item; + int i; + + item = (NOTIFICATIONLIST *)SHAlloc(sizeof(NOTIFICATIONLIST)); + + TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p) item=%p\n", + hwnd, fSources, wEventMask, uMsg, cItems, lpItems, item); + + item->next = NULL; + item->prev = NULL; + item->cidl = cItems; + item->apidl = (SHChangeNotifyEntry *)SHAlloc(sizeof(SHChangeNotifyEntry) * cItems); + for(i=0;iapidl[i].pidl = ILClone(lpItems[i].pidl); + item->apidl[i].fRecursive = lpItems[i].fRecursive; + } + item->hwnd = hwnd; + item->uMsg = uMsg; + item->wEventMask = wEventMask; + item->wSignalledEvent = 0; + item->dwFlags = fSources; + + TRACE("new node: %s\n", NodeName( item )); + + EnterCriticalSection(&SHELL32_ChangenotifyCS); + + AddNode(item); + + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + + return (ULONG)item; +} + +/************************************************************************* + * SHChangeNotifyDeregister [SHELL32.4] + */ +BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify) +{ + LPNOTIFICATIONLIST node; + + TRACE("(0x%08x)\n", hNotify); + + EnterCriticalSection(&SHELL32_ChangenotifyCS); + + node = FindNode((HANDLE)hNotify); + if( node ) + DeleteNode(node); + + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + + return node?TRUE:FALSE; +} + +/************************************************************************* + * SHChangeNotifyUpdateEntryList [SHELL32.5] + */ +EXTERN_C BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2, + DWORD unknown3, DWORD unknown4) +{ + FIXME("(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", + unknown1, unknown2, unknown3, unknown4); + + return -1; +} + +static BOOL should_notify( LPCITEMIDLIST changed, LPCITEMIDLIST watched, BOOL sub ) +{ + TRACE("%p %p %d\n", changed, watched, sub ); + if ( !watched ) + return FALSE; + if (ILIsEqual( watched, changed ) ) + return TRUE; + if( sub && ILIsParent( watched, changed, TRUE ) ) + return TRUE; + return FALSE; +} + +/************************************************************************* + * SHChangeNotify [SHELL32.@] + */ +void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2) +{ + LPCITEMIDLIST Pidls[2]; + LPNOTIFICATIONLIST ptr; + UINT typeFlag = uFlags & SHCNF_TYPE; + + Pidls[0] = NULL; + Pidls[1] = NULL; + + TRACE("(0x%08x,0x%08x,%p,%p):stub.\n", wEventId, uFlags, dwItem1, dwItem2); + + if( ( wEventId & SHCNE_NOITEMEVENTS ) && ( dwItem1 || dwItem2 ) ) + { + TRACE("dwItem1 and dwItem2 are not zero, but should be\n"); + dwItem1 = 0; + dwItem2 = 0; + return; + } + else if( ( wEventId & SHCNE_ONEITEMEVENTS ) && dwItem2 ) + { + TRACE("dwItem2 is not zero, but should be\n"); + dwItem2 = 0; + return; + } + + if( ( ( wEventId & SHCNE_NOITEMEVENTS ) && + ( wEventId & ~SHCNE_NOITEMEVENTS ) ) || + ( ( wEventId & SHCNE_ONEITEMEVENTS ) && + ( wEventId & ~SHCNE_ONEITEMEVENTS ) ) || + ( ( wEventId & SHCNE_TWOITEMEVENTS ) && + ( wEventId & ~SHCNE_TWOITEMEVENTS ) ) ) + { + WARN("mutually incompatible events listed\n"); + return; + } + + /* convert paths in IDLists*/ + switch (typeFlag) + { + case SHCNF_PATHA: + if (dwItem1) Pidls[0] = SHSimpleIDListFromPathA((LPCSTR)dwItem1); //FIXME + if (dwItem2) Pidls[1] = SHSimpleIDListFromPathA((LPCSTR)dwItem2); //FIXME + break; + case SHCNF_PATHW: + if (dwItem1) Pidls[0] = SHSimpleIDListFromPathW((LPCWSTR)dwItem1); + if (dwItem2) Pidls[1] = SHSimpleIDListFromPathW((LPCWSTR)dwItem2); + break; + case SHCNF_IDLIST: + Pidls[0] = (LPCITEMIDLIST)dwItem1; + Pidls[1] = (LPCITEMIDLIST)dwItem2; + break; + case SHCNF_PRINTERA: + case SHCNF_PRINTERW: + FIXME("SHChangeNotify with (uFlags & SHCNF_PRINTER)\n"); + return; + case SHCNF_DWORD: + default: + FIXME("unknown type %08x\n",typeFlag); + return; + } + + { + WCHAR path[MAX_PATH]; + + if( Pidls[0] && SHGetPathFromIDListW(Pidls[0], path )) + TRACE("notify %08x on item1 = %s\n", wEventId, debugstr_w(path)); + + if( Pidls[1] && SHGetPathFromIDListW(Pidls[1], path )) + TRACE("notify %08x on item2 = %s\n", wEventId, debugstr_w(path)); + } + + EnterCriticalSection(&SHELL32_ChangenotifyCS); + + /* loop through the list */ + for( ptr = head; ptr; ptr = ptr->next ) + { + BOOL notify; + DWORD i; + + notify = FALSE; + + TRACE("trying %p\n", ptr); + + for( i=0; (icidl) && !notify ; i++ ) + { + LPCITEMIDLIST pidl = ptr->apidl[i].pidl; + BOOL subtree = ptr->apidl[i].fRecursive; + + if (wEventId & ptr->wEventMask) + { + if( !pidl ) /* all ? */ + notify = TRUE; + else if( wEventId & SHCNE_NOITEMEVENTS ) + notify = TRUE; + else if( wEventId & ( SHCNE_ONEITEMEVENTS | SHCNE_TWOITEMEVENTS ) ) + notify = should_notify( Pidls[0], pidl, subtree ); + else if( wEventId & SHCNE_TWOITEMEVENTS ) + notify = should_notify( Pidls[1], pidl, subtree ); + } + } + + if( !notify ) + continue; + + ptr->pidlSignaled = ILClone(Pidls[0]); + + TRACE("notifying %s, event %s(%x) before\n", NodeName( ptr ), DumpEvent( + wEventId ),wEventId ); + + ptr->wSignalledEvent |= wEventId; + + if (ptr->dwFlags & SHCNRF_NewDelivery) + SendMessageW(ptr->hwnd, ptr->uMsg, (WPARAM) ptr, (LPARAM) GetCurrentProcessId()); + else + SendMessageW(ptr->hwnd, ptr->uMsg, (WPARAM)Pidls, wEventId); + + TRACE("notifying %s, event %s(%x) after\n", NodeName( ptr ), DumpEvent( + wEventId ),wEventId ); + + } + TRACE("notify Done\n"); + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + + /* if we allocated it, free it. The ANSI flag is also set in its Unicode sibling. */ + if ((typeFlag & SHCNF_PATHA) || (typeFlag & SHCNF_PRINTERA)) + { + SHFree((LPITEMIDLIST)Pidls[0]); + SHFree((LPITEMIDLIST)Pidls[1]); + } +} + +/************************************************************************* + * NTSHChangeNotifyRegister [SHELL32.640] + * NOTES + * Idlist is an array of structures and Count specifies how many items in the array. + * count should always be one when calling SHChangeNotifyRegister, or + * SHChangeNotifyDeregister will not work properly. + */ +EXTERN_C ULONG WINAPI NTSHChangeNotifyRegister( + HWND hwnd, + int fSources, + LONG fEvents, + UINT msg, + int count, + SHChangeNotifyEntry *idlist) +{ + return SHChangeNotifyRegister(hwnd, fSources | SHCNRF_NewDelivery, + fEvents, msg, count, idlist); +} + +/************************************************************************* + * SHChangeNotification_Lock [SHELL32.644] + */ +HANDLE WINAPI SHChangeNotification_Lock( + HANDLE hChange, + DWORD dwProcessId, + LPITEMIDLIST **lppidls, + LPLONG lpwEventId) +{ + DWORD i; + LPNOTIFICATIONLIST node; + LPCITEMIDLIST *idlist; + + TRACE("%p %08x %p %p\n", hChange, dwProcessId, lppidls, lpwEventId); + + /* EnterCriticalSection(&SHELL32_ChangenotifyCS); */ + + node = FindNode( hChange ); + if( node ) + { + idlist = (LPCITEMIDLIST *)SHAlloc( sizeof(LPCITEMIDLIST *) * node->cidl ); + for(i=0; icidl; i++) + idlist[i] = (LPCITEMIDLIST)node->pidlSignaled; + *lpwEventId = node->wSignalledEvent; + *lppidls = (LPITEMIDLIST*)idlist; + node->wSignalledEvent = 0; + } + else + ERR("Couldn't find %p\n", hChange ); + + /* LeaveCriticalSection(&SHELL32_ChangenotifyCS); */ + + return (HANDLE) node; +} + +/************************************************************************* + * SHChangeNotification_Unlock [SHELL32.645] + */ +BOOL WINAPI SHChangeNotification_Unlock ( HANDLE hLock) +{ + TRACE("\n"); + return 1; +} + +/************************************************************************* + * NTSHChangeNotifyDeregister [SHELL32.641] + */ +EXTERN_C DWORD WINAPI NTSHChangeNotifyDeregister(ULONG x1) +{ + FIXME("(0x%08x):semi stub.\n",x1); + + return SHChangeNotifyDeregister( x1 ); +} diff --git a/reactos/dll/win32/shell32/classes.cpp b/reactos/dll/win32/shell32/classes.cpp new file mode 100644 index 00000000000..fe69656db94 --- /dev/null +++ b/reactos/dll/win32/shell32/classes.cpp @@ -0,0 +1,506 @@ +/* + * file type mapping + * (HKEY_CLASSES_ROOT - Stuff) + * + * Copyright 1998, 1999, 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +#define MAX_EXTENSION_LENGTH 20 + +BOOL HCR_MapTypeToValueW(LPCWSTR szExtension, LPWSTR szFileType, LONG len, BOOL bPrependDot) +{ + HKEY hkey; + WCHAR szTemp[MAX_EXTENSION_LENGTH + 2]; + + TRACE("%s %p\n", debugstr_w(szExtension), debugstr_w(szFileType)); + + /* added because we do not want to have double dots */ + if (szExtension[0] == '.') + bPrependDot = 0; + + if (bPrependDot) + szTemp[0] = '.'; + + lstrcpynW(szTemp + (bPrependDot?1:0), szExtension, MAX_EXTENSION_LENGTH); + + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkey)) + { + return FALSE; + } + + if (RegQueryValueW(hkey, NULL, szFileType, &len)) + { + RegCloseKey(hkey); + return FALSE; + } + + RegCloseKey(hkey); + + TRACE("--UE;\n} %s\n", debugstr_w(szFileType)); + + return TRUE; +} + +BOOL HCR_MapTypeToValueA(LPCSTR szExtension, LPSTR szFileType, LONG len, BOOL bPrependDot) +{ + HKEY hkey; + char szTemp[MAX_EXTENSION_LENGTH + 2]; + + TRACE("%s %p\n", szExtension, szFileType); + + /* added because we do not want to have double dots */ + if (szExtension[0] == '.') + bPrependDot = 0; + + if (bPrependDot) + szTemp[0] = '.'; + + lstrcpynA(szTemp + (bPrependDot?1:0), szExtension, MAX_EXTENSION_LENGTH); + + if (RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hkey)) + { + return FALSE; + } + + if (RegLoadMUIStringA(hkey, "FriendlyTypeName", szFileType, len, NULL, 0, NULL) == ERROR_SUCCESS) + { + RegCloseKey(hkey); + return TRUE; + } + + if (RegQueryValueA(hkey, NULL, szFileType, &len)) + { + RegCloseKey(hkey); + return FALSE; + } + + RegCloseKey(hkey); + + TRACE("--UE;\n} %s\n", szFileType); + + return TRUE; +} + +static const WCHAR swShell[] = {'s','h','e','l','l','\\',0}; +static const WCHAR swOpen[] = {'o','p','e','n',0}; +static const WCHAR swCommand[] = {'\\','c','o','m','m','a','n','d',0}; + +BOOL HCR_GetDefaultVerbW( HKEY hkeyClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len ) +{ + WCHAR sTemp[MAX_PATH]; + LONG size; + HKEY hkey; + + TRACE("%p %s %p\n", hkeyClass, debugstr_w(szVerb), szDest); + + if (szVerb) + { + lstrcpynW(szDest, szVerb, len); + return TRUE; + } + + size=len; + *szDest='\0'; + if (!RegQueryValueW(hkeyClass, L"shell", szDest, &size) && *szDest) + { + /* The MSDN says to first try the default verb */ + wcscpy(sTemp, swShell); + wcscat(sTemp, szDest); + wcscat(sTemp, swCommand); + if (!RegOpenKeyExW(hkeyClass, sTemp, 0, KEY_READ, &hkey)) + { + RegCloseKey(hkey); + TRACE("default verb=%s\n", debugstr_w(szDest)); + return TRUE; + } + } + + /* then fallback to 'open' */ + wcscpy(sTemp, swShell); + wcscat(sTemp, swOpen); + wcscat(sTemp, swCommand); + if (!RegOpenKeyExW(hkeyClass, sTemp, 0, KEY_READ, &hkey)) + { + RegCloseKey(hkey); + lstrcpynW(szDest, swOpen, len); + TRACE("default verb=open\n"); + return TRUE; + } + + /* and then just use the first verb on Windows >= 2000 */ + if (!RegOpenKeyExW(hkeyClass, L"shell", 0, KEY_READ, &hkey)) + { + if (!RegEnumKeyW(hkey, 0, szDest, len) && *szDest) + { + TRACE("default verb=first verb=%s\n", debugstr_w(szDest)); + RegCloseKey(hkey); + return TRUE; + } + RegCloseKey(hkey); + } + + + TRACE("no default verb!\n"); + return FALSE; +} + +BOOL HCR_GetExecuteCommandW( HKEY hkeyClass, LPCWSTR szClass, LPCWSTR szVerb, LPWSTR szDest, DWORD len ) +{ + WCHAR sTempVerb[MAX_PATH]; + BOOL ret; + + TRACE("%p %s %s %p\n", hkeyClass, debugstr_w(szClass), debugstr_w(szVerb), szDest); + + if (szClass) + RegOpenKeyExW(HKEY_CLASSES_ROOT, szClass, 0, KEY_READ, &hkeyClass); + if (!hkeyClass) + return FALSE; + ret = FALSE; + + if (HCR_GetDefaultVerbW(hkeyClass, szVerb, sTempVerb, sizeof(sTempVerb))) + { + WCHAR sTemp[MAX_PATH]; + wcscpy(sTemp, swShell); + wcscat(sTemp, sTempVerb); + wcscat(sTemp, swCommand); + ret = (ERROR_SUCCESS == SHGetValueW(hkeyClass, sTemp, NULL, NULL, szDest, &len)); + } + if (szClass) + RegCloseKey(hkeyClass); + + TRACE("-- %s\n", debugstr_w(szDest) ); + return ret; +} + +/*************************************************************************************** +* HCR_GetDefaultIcon [internal] +* +* Gets the icon for a filetype +*/ +static BOOL HCR_RegOpenClassIDKey(REFIID riid, HKEY *hkey) +{ + WCHAR xriid[50]; + swprintf( xriid, L"CLSID\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + riid.Data1, riid.Data2, riid.Data3, + riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3], + riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7] ); + + TRACE("%S\n",xriid ); + + return !RegOpenKeyExW(HKEY_CLASSES_ROOT, xriid, 0, KEY_READ, hkey); +} + +static BOOL HCR_RegGetDefaultIconW(HKEY hkey, LPWSTR szDest, DWORD len, int* picon_idx) +{ + DWORD dwType; + WCHAR sTemp[MAX_PATH]; + WCHAR sNum[7]; + + if (!RegQueryValueExW(hkey, NULL, 0, &dwType, (LPBYTE)szDest, &len)) + { + if (dwType == REG_EXPAND_SZ) + { + ExpandEnvironmentStringsW(szDest, sTemp, MAX_PATH); + lstrcpynW(szDest, sTemp, len); + } + if (ParseFieldW (szDest, 2, sNum, _countof(sNum))) + *picon_idx = atoiW(sNum); + else + *picon_idx=0; /* sometimes the icon number is missing */ + ParseFieldW (szDest, 1, szDest, len); + PathUnquoteSpacesW(szDest); + return TRUE; + } + return FALSE; +} + +static BOOL HCR_RegGetDefaultIconA(HKEY hkey, LPSTR szDest, DWORD len, int* picon_idx) +{ + DWORD dwType; + char sTemp[MAX_PATH]; + char sNum[5]; + + if (!RegQueryValueExA(hkey, NULL, 0, &dwType, (LPBYTE)szDest, &len)) + { + if (dwType == REG_EXPAND_SZ) + { + ExpandEnvironmentStringsA(szDest, sTemp, MAX_PATH); + lstrcpynA(szDest, sTemp, len); + } + if (ParseFieldA (szDest, 2, sNum, 5)) + *picon_idx=atoi(sNum); + else + *picon_idx=0; /* sometimes the icon number is missing */ + ParseFieldA (szDest, 1, szDest, len); + PathUnquoteSpacesA(szDest); + return TRUE; + } + return FALSE; +} + +BOOL HCR_GetDefaultIconW(LPCWSTR szClass, LPWSTR szDest, DWORD len, int* picon_idx) +{ + static const WCHAR swDefaultIcon[] = {'\\','D','e','f','a','u','l','t','I','c','o','n',0}; + HKEY hkey; + WCHAR sTemp[MAX_PATH]; + BOOL ret = FALSE; + + TRACE("%s\n",debugstr_w(szClass) ); + + lstrcpynW(sTemp, szClass, MAX_PATH); + wcscat(sTemp, swDefaultIcon); + + if (!RegOpenKeyExW(HKEY_CLASSES_ROOT, sTemp, 0, KEY_READ, &hkey)) + { + ret = HCR_RegGetDefaultIconW(hkey, szDest, len, picon_idx); + RegCloseKey(hkey); + } + + if(ret) + TRACE("-- %s %i\n", debugstr_w(szDest), *picon_idx); + else + TRACE("-- not found\n"); + + return ret; +} + +BOOL HCR_GetDefaultIconA(LPCSTR szClass, LPSTR szDest, DWORD len, int* picon_idx) +{ + HKEY hkey; + char sTemp[MAX_PATH]; + BOOL ret = FALSE; + + TRACE("%s\n",szClass ); + + sprintf(sTemp, "%s\\DefaultIcon",szClass); + + if (!RegOpenKeyExA(HKEY_CLASSES_ROOT, sTemp, 0, KEY_READ, &hkey)) + { + ret = HCR_RegGetDefaultIconA(hkey, szDest, len, picon_idx); + RegCloseKey(hkey); + } + TRACE("-- %s %i\n", szDest, *picon_idx); + return ret; +} + +BOOL HCR_GetDefaultIconFromGUIDW(REFIID riid, LPWSTR szDest, DWORD len, int* picon_idx) +{ + HKEY hkey; + BOOL ret = FALSE; + + if (HCR_RegOpenClassIDKey(riid, &hkey)) + { + ret = HCR_RegGetDefaultIconW(hkey, szDest, len, picon_idx); + RegCloseKey(hkey); + } + TRACE("-- %s %i\n", debugstr_w(szDest), *picon_idx); + return ret; +} + +/*************************************************************************************** +* HCR_GetClassName [internal] +* +* Gets the name of a registered class +*/ +static const WCHAR swEmpty[] = {0}; + +BOOL HCR_GetClassNameW(REFIID riid, LPWSTR szDest, DWORD len) +{ + HKEY hkey; + BOOL ret = FALSE; + DWORD buflen = len; + WCHAR szName[100]; + LPOLESTR pStr; + + szDest[0] = 0; + + if (StringFromCLSID(riid, &pStr) == S_OK) + { + DWORD dwLen = buflen * sizeof(WCHAR); + swprintf(szName, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", pStr); + if (RegGetValueW(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, NULL, (PVOID)szDest, &dwLen) == ERROR_SUCCESS) + { + ret = TRUE; + } + CoTaskMemFree(pStr); + } + if (!ret && HCR_RegOpenClassIDKey(riid, &hkey)) + { + static const WCHAR wszLocalizedString[] = + { 'L','o','c','a','l','i','z','e','d','S','t','r','i','n','g', 0 }; + if (!RegLoadMUIStringW(hkey, wszLocalizedString, szDest, len, NULL, 0, NULL) || + !RegQueryValueExW(hkey, swEmpty, 0, NULL, (LPBYTE)szDest, &len)) + { + ret = TRUE; + } + RegCloseKey(hkey); + } + + if (!ret || !szDest[0]) + { + if(IsEqualIID(riid, CLSID_ShellDesktop)) + { + if (LoadStringW(shell32_hInstance, IDS_DESKTOP, szDest, buflen)) + ret = TRUE; + } + else if (IsEqualIID(riid, CLSID_MyComputer)) + { + if(LoadStringW(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen)) + ret = TRUE; + } + else if (IsEqualIID(riid, CLSID_MyDocuments)) + { + if(LoadStringW(shell32_hInstance, IDS_PERSONAL, szDest, buflen)) + ret = TRUE; + } + else if (IsEqualIID(riid, CLSID_RecycleBin)) + { + if(LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_FOLDER_NAME, szDest, buflen)) + ret = TRUE; + } + else if (IsEqualIID(riid, CLSID_ControlPanel)) + { + if(LoadStringW(shell32_hInstance, IDS_CONTROLPANEL, szDest, buflen)) + ret = TRUE; + } + else if (IsEqualIID(riid, CLSID_AdminFolderShortcut)) + { + if(LoadStringW(shell32_hInstance, IDS_ADMINISTRATIVETOOLS, szDest, buflen)) + ret = TRUE; + } + + } + TRACE("-- %s\n", debugstr_w(szDest)); + return ret; +} + +BOOL HCR_GetClassNameA(REFIID riid, LPSTR szDest, DWORD len) +{ HKEY hkey; + BOOL ret = FALSE; + DWORD buflen = len; + + szDest[0] = 0; + if (HCR_RegOpenClassIDKey(riid, &hkey)) + { + if (!RegLoadMUIStringA(hkey,"LocalizedString",szDest,len,NULL,0,NULL) || + !RegQueryValueExA(hkey,"",0,NULL,(LPBYTE)szDest,&len)) + { + ret = TRUE; + } + RegCloseKey(hkey); + } + + if (!ret || !szDest[0]) + { + if(IsEqualIID(riid, CLSID_ShellDesktop)) + { + if (LoadStringA(shell32_hInstance, IDS_DESKTOP, szDest, buflen)) + ret = TRUE; + } + else if (IsEqualIID(riid, CLSID_MyComputer)) + { + if(LoadStringA(shell32_hInstance, IDS_MYCOMPUTER, szDest, buflen)) + ret = TRUE; + } + } + + TRACE("-- %s\n", szDest); + + return ret; +} + +/****************************************************************************** + * HCR_GetFolderAttributes [Internal] + * + * Query the registry for a shell folders' attributes + * + * PARAMS + * pidlFolder [I] A simple pidl of type PT_GUID. + * pdwAttributes [IO] In: Attributes to be queried, OUT: Resulting attributes. + * + * RETURNS + * TRUE: Found information for the attributes in the registry + * FALSE: No attribute information found + * + * NOTES + * If queried for an attribute, which is set in the CallForAttributes registry + * value, the function binds to the shellfolder objects and queries it. + */ +BOOL HCR_GetFolderAttributes(LPCITEMIDLIST pidlFolder, LPDWORD pdwAttributes) +{ + HKEY hSFKey; + LPOLESTR pwszCLSID; + LONG lResult; + DWORD dwTemp, dwLen; + static const WCHAR wszAttributes[] = { 'A','t','t','r','i','b','u','t','e','s',0 }; + static const WCHAR wszCallForAttributes[] = { + 'C','a','l','l','F','o','r','A','t','t','r','i','b','u','t','e','s',0 }; + WCHAR wszShellFolderKey[] = { 'C','L','S','I','D','\\','{','0','0','0','2','1','4','0','0','-', + '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-','0','0','0','0','0','0','0', + '0','0','0','4','6','}','\\','S','h','e','l','l','F','o','l','d','e','r',0 }; + + TRACE("(pidlFolder=%p, pdwAttributes=%p)\n", pidlFolder, pdwAttributes); + + if (!_ILIsPidlSimple(pidlFolder)) { + ERR("should be called for simple PIDL's only!\n"); + return FALSE; + } + + if (!_ILIsDesktop(pidlFolder)) { + if (FAILED(StringFromCLSID(*_ILGetGUIDPointer(pidlFolder), &pwszCLSID))) return FALSE; + memcpy(&wszShellFolderKey[6], pwszCLSID, 38 * sizeof(WCHAR)); + CoTaskMemFree(pwszCLSID); + } + + lResult = RegOpenKeyExW(HKEY_CLASSES_ROOT, wszShellFolderKey, 0, KEY_READ, &hSFKey); + if (lResult != ERROR_SUCCESS) return FALSE; + + dwLen = sizeof(DWORD); + lResult = RegQueryValueExW(hSFKey, wszCallForAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen); + if ((lResult == ERROR_SUCCESS) && (dwTemp & *pdwAttributes)) { + CComPtr psfDesktop; + CComPtr psfFolder; + HRESULT hr; + + RegCloseKey(hSFKey); + hr = SHGetDesktopFolder(&psfDesktop); + if (SUCCEEDED(hr)) { + hr = psfDesktop->BindToObject(pidlFolder, NULL, IID_IShellFolder, + (LPVOID*)&psfFolder); + if (SUCCEEDED(hr)) { + hr = psfFolder->GetAttributesOf(0, NULL, pdwAttributes); + } + } + if (FAILED(hr)) return FALSE; + } else { + lResult = RegQueryValueExW(hSFKey, wszAttributes, 0, NULL, (LPBYTE)&dwTemp, &dwLen); + RegCloseKey(hSFKey); + if (lResult == ERROR_SUCCESS) { + *pdwAttributes &= dwTemp; + } else { + return FALSE; + } + } + + TRACE("-- *pdwAttributes == 0x%08x\n", *pdwAttributes); + + return TRUE; +} diff --git a/reactos/dll/win32/shell32/clipboard.cpp b/reactos/dll/win32/shell32/clipboard.cpp new file mode 100644 index 00000000000..b4a6943bf17 --- /dev/null +++ b/reactos/dll/win32/shell32/clipboard.cpp @@ -0,0 +1,240 @@ +/* + * clipboard helper functions + * + * Copyright 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 + * + * NOTES: + * + * For copy & paste functions within contextmenus does the shell use + * the OLE clipboard functions in combination with dataobjects. + * The OLE32.DLL gets loaded with LoadLibrary + * + * - a right mousebutton-copy sets the following formats: + * classic: + * Shell IDList Array + * Preferred Drop Effect + * Shell Object Offsets + * HDROP + * FileName + * ole: + * OlePrivateData (ClipboardDataObjectInterface) + * + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/************************************************************************** + * RenderHDROP + * + * creates a CF_HDROP structure + */ +HGLOBAL RenderHDROP(LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) +{ + UINT i; + int size = 0; + WCHAR wszFileName[MAX_PATH]; + HGLOBAL hGlobal = NULL; + DROPFILES *pDropFiles; + int offset; + LPITEMIDLIST *pidls; + + TRACE("(%p,%p,%u)\n", pidlRoot, apidl, cidl); + + pidls = (LPITEMIDLIST *)HeapAlloc(GetProcessHeap(), 0, cidl * sizeof(*pidls)); + if (!pidls) + goto cleanup; + + /* get the size needed */ + size = sizeof(DROPFILES); + + for (i=0; ipFiles = offset * sizeof(WCHAR); + pDropFiles->fWide = TRUE; + + for (i=0; icidl = cidl; + + /* root pidl */ + offset = sizeof(CIDA) + sizeof (UINT)*(cidl); + pcida->aoffset[0] = offset; /* first element */ + sizePidl = ILGetSize (pidlRoot); + memcpy(((LPBYTE)pcida)+offset, pidlRoot, sizePidl); + offset += sizePidl; + + for(i=0; iaoffset[i+1] = offset; + sizePidl = ILGetSize(apidl[i]); + memcpy(((LPBYTE)pcida)+offset, apidl[i], sizePidl); + offset += sizePidl; + } + + GlobalUnlock(hGlobal); + return hGlobal; +} + +HGLOBAL RenderSHELLIDLISTOFFSET (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) +{ + FIXME("\n"); + return 0; +} + +HGLOBAL RenderFILECONTENTS (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) +{ + FIXME("\n"); + return 0; +} + +HGLOBAL RenderFILEDESCRIPTOR (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) +{ + FIXME("\n"); + return 0; +} + +HGLOBAL RenderFILENAMEA (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) +{ + int size = 0; + char szTemp[MAX_PATH], *szFileName; + LPITEMIDLIST pidl; + HGLOBAL hGlobal; + BOOL bSuccess; + + TRACE("(%p,%p,%u)\n", pidlRoot, apidl, cidl); + + /* get path of combined pidl */ + pidl = ILCombine(pidlRoot, apidl[0]); + if (!pidl) + return 0; + + bSuccess = SHGetPathFromIDListA(pidl, szTemp); + SHFree(pidl); + if (!bSuccess) + return 0; + + size = strlen(szTemp) + 1; + + /* fill the structure */ + hGlobal = GlobalAlloc(GHND|GMEM_SHARE, size); + if(!hGlobal) return hGlobal; + szFileName = (char *)GlobalLock(hGlobal); + memcpy(szFileName, szTemp, size); + GlobalUnlock(hGlobal); + + return hGlobal; +} + +HGLOBAL RenderFILENAMEW (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) +{ + int size = 0; + WCHAR szTemp[MAX_PATH], *szFileName; + LPITEMIDLIST pidl; + HGLOBAL hGlobal; + BOOL bSuccess; + + TRACE("(%p,%p,%u)\n", pidlRoot, apidl, cidl); + + /* get path of combined pidl */ + pidl = ILCombine(pidlRoot, apidl[0]); + if (!pidl) + return 0; + + bSuccess = SHGetPathFromIDListW(pidl, szTemp); + SHFree(pidl); + if (!bSuccess) + return 0; + + size = (wcslen(szTemp)+1) * sizeof(WCHAR); + + /* fill the structure */ + hGlobal = GlobalAlloc(GHND|GMEM_SHARE, size); + if(!hGlobal) return hGlobal; + szFileName = (WCHAR *)GlobalLock(hGlobal); + memcpy(szFileName, szTemp, size); + GlobalUnlock(hGlobal); + + return hGlobal; +} + +HGLOBAL RenderPREFEREDDROPEFFECT (DWORD dwFlags) +{ + DWORD * pdwFlag; + HGLOBAL hGlobal; + + TRACE("(0x%08x)\n", dwFlags); + + hGlobal = GlobalAlloc(GHND|GMEM_SHARE, sizeof(DWORD)); + if(!hGlobal) return hGlobal; + pdwFlag = (DWORD*)GlobalLock(hGlobal); + *pdwFlag = dwFlags; + GlobalUnlock(hGlobal); + return hGlobal; +} diff --git a/reactos/dll/win32/shell32/control.cpp b/reactos/dll/win32/shell32/control.cpp new file mode 100644 index 00000000000..811258e877a --- /dev/null +++ b/reactos/dll/win32/shell32/control.cpp @@ -0,0 +1,524 @@ +/* Control Panel management + * + * Copyright 2001 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 + +WINE_DEFAULT_DEBUG_CHANNEL(shlctrl); + +CPlApplet* Control_UnloadApplet(CPlApplet* applet) +{ + unsigned i; + CPlApplet* next; + + for (i = 0; i < applet->count; i++) { + if (!applet->info[i].dwSize) continue; + applet->proc(applet->hWnd, CPL_STOP, i, applet->info[i].lData); + } + if (applet->proc) applet->proc(applet->hWnd, CPL_EXIT, 0L, 0L); + FreeLibrary(applet->hModule); + next = applet->next; + HeapFree(GetProcessHeap(), 0, applet); + return next; +} + +CPlApplet* Control_LoadApplet(HWND hWnd, LPCWSTR cmd, CPanel* panel) +{ + CPlApplet* applet; + unsigned i; + CPLINFO info; + NEWCPLINFOW newinfo; + + if (!(applet = (CPlApplet *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*applet)))) + return applet; + + applet->hWnd = hWnd; + + if (!(applet->hModule = LoadLibraryW(cmd))) { + WARN("Cannot load control panel applet %s\n", debugstr_w(cmd)); + goto theError; + } + if (!(applet->proc = (APPLET_PROC)GetProcAddress(applet->hModule, "CPlApplet"))) { + WARN("Not a valid control panel applet %s\n", debugstr_w(cmd)); + goto theError; + } + if (!applet->proc(hWnd, CPL_INIT, 0L, 0L)) { + WARN("Init of applet has failed\n"); + goto theError; + } + if ((applet->count = applet->proc(hWnd, CPL_GETCOUNT, 0L, 0L)) == 0) { + WARN("No subprogram in applet\n"); + goto theError; + } + + applet = (CPlApplet *)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, applet, + sizeof(*applet) + (applet->count - 1) * sizeof(NEWCPLINFOW)); + + for (i = 0; i < applet->count; i++) { + ZeroMemory(&newinfo, sizeof(newinfo)); + newinfo.dwSize = sizeof(NEWCPLINFOW); + applet->info[i].dwSize = sizeof(NEWCPLINFOW); + /* proc is supposed to return a null value upon success for + * CPL_INQUIRE and CPL_NEWINQUIRE + * However, real drivers don't seem to behave like this + * So, use introspection rather than return value + */ + applet->proc(hWnd, CPL_NEWINQUIRE, i, (LPARAM)&newinfo); + if (newinfo.hIcon == 0) { + applet->proc(hWnd, CPL_INQUIRE, i, (LPARAM)&info); + if (info.idIcon == 0 || info.idName == 0) { + WARN("Couldn't get info from sp %u\n", i); + applet->info[i].dwSize = 0; + } else { + /* convert the old data into the new structure */ + applet->info[i].dwFlags = 0; + applet->info[i].dwHelpContext = 0; + applet->info[i].lData = info.lData; + applet->info[i].hIcon = LoadIconW(applet->hModule, + MAKEINTRESOURCEW(info.idIcon)); + LoadStringW(applet->hModule, info.idName, + applet->info[i].szName, sizeof(applet->info[i].szName) / sizeof(WCHAR)); + LoadStringW(applet->hModule, info.idInfo, + applet->info[i].szInfo, sizeof(applet->info[i].szInfo) / sizeof(WCHAR)); + applet->info[i].szHelpFile[0] = '\0'; + } + } + else + { + CopyMemory(&applet->info[i], &newinfo, newinfo.dwSize); + if (newinfo.dwSize != sizeof(NEWCPLINFOW)) + { + applet->info[i].dwSize = sizeof(NEWCPLINFOW); + lstrcpyW(applet->info[i].szName, newinfo.szName); + lstrcpyW(applet->info[i].szInfo, newinfo.szInfo); + lstrcpyW(applet->info[i].szHelpFile, newinfo.szHelpFile); + } + } + } + + applet->next = panel->first; + panel->first = applet; + + return applet; + + theError: + Control_UnloadApplet(applet); + return NULL; +} + +static void Control_WndProc_Create(HWND hWnd, const CREATESTRUCTW* cs) +{ + CPanel* panel = (CPanel*)cs->lpCreateParams; + + SetWindowLongPtrW(hWnd, 0, (LONG_PTR)panel); + panel->status = 0; + panel->hWnd = hWnd; +} + +#define XICON 32 +#define XSTEP 128 +#define YICON 32 +#define YSTEP 64 + +static BOOL Control_Localize(const CPanel* panel, int cx, int cy, + CPlApplet** papplet, unsigned* psp) +{ + unsigned int i; + int x = (XSTEP-XICON)/2, y = 0; + CPlApplet* applet; + RECT rc; + + GetClientRect(panel->hWnd, &rc); + for (applet = panel->first; applet; applet = applet->next) { + for (i = 0; i < applet->count; i++) { + if (!applet->info[i].dwSize) continue; + if (x + XSTEP >= rc.right - rc.left) { + x = (XSTEP-XICON)/2; + y += YSTEP; + } + if (cx >= x && cx < x + XICON && cy >= y && cy < y + YSTEP) { + *papplet = applet; + *psp = i; + return TRUE; + } + x += XSTEP; + } + } + return FALSE; +} + +static LRESULT Control_WndProc_Paint(const CPanel* panel, WPARAM wParam) +{ + HDC hdc; + PAINTSTRUCT ps; + RECT rc, txtRect; + unsigned int i; + int x = 0, y = 0; + CPlApplet* applet; + HGDIOBJ hOldFont; + + hdc = (wParam) ? (HDC)wParam : BeginPaint(panel->hWnd, &ps); + hOldFont = SelectObject(hdc, GetStockObject(ANSI_VAR_FONT)); + GetClientRect(panel->hWnd, &rc); + for (applet = panel->first; applet; applet = applet->next) { + for (i = 0; i < applet->count; i++) { + if (x + XSTEP >= rc.right - rc.left) { + x = 0; + y += YSTEP; + } + if (!applet->info[i].dwSize) continue; + DrawIcon(hdc, x + (XSTEP-XICON)/2, y, applet->info[i].hIcon); + txtRect.left = x; + txtRect.right = x + XSTEP; + txtRect.top = y + YICON; + txtRect.bottom = y + YSTEP; + DrawTextW(hdc, applet->info[i].szName, -1, &txtRect, + DT_CENTER | DT_VCENTER); + x += XSTEP; + } + } + SelectObject(hdc, hOldFont); + if (!wParam) EndPaint(panel->hWnd, &ps); + return 0; +} + +static LRESULT Control_WndProc_LButton(CPanel* panel, LPARAM lParam, BOOL up) +{ + unsigned i; + CPlApplet* applet; + + if (Control_Localize(panel, (short)LOWORD(lParam), (short)HIWORD(lParam), &applet, &i)) { + if (up) { + if (panel->clkApplet == applet && panel->clkSP == i) { + applet->proc(applet->hWnd, CPL_DBLCLK, i, applet->info[i].lData); + } + } else { + panel->clkApplet = applet; + panel->clkSP = i; + } + } + return 0; +} + +static LRESULT WINAPI Control_WndProc(HWND hWnd, UINT wMsg, + WPARAM lParam1, LPARAM lParam2) +{ + CPanel* panel = (CPanel*)GetWindowLongPtrW(hWnd, 0); + + if (panel || wMsg == WM_CREATE) { + switch (wMsg) { + case WM_CREATE: + Control_WndProc_Create(hWnd, (CREATESTRUCTW*)lParam2); + return 0; + case WM_DESTROY: + { + CPlApplet* applet = panel->first; + while (applet) + applet = Control_UnloadApplet(applet); + } + PostQuitMessage(0); + break; + case WM_PAINT: + return Control_WndProc_Paint(panel, lParam1); + case WM_LBUTTONUP: + return Control_WndProc_LButton(panel, lParam2, TRUE); + case WM_LBUTTONDOWN: + return Control_WndProc_LButton(panel, lParam2, FALSE); +/* EPP case WM_COMMAND: */ +/* EPP return Control_WndProc_Command(mwi, lParam1, lParam2); */ + } + } + + return DefWindowProcW(hWnd, wMsg, lParam1, lParam2); +} + +static void Control_DoInterface(CPanel* panel, HWND hWnd, HINSTANCE hInst) +{ + WNDCLASSW wc; + MSG msg; + const WCHAR* appName = L"ReactOS Control Panel"; + wc.style = CS_HREDRAW|CS_VREDRAW; + wc.lpfnWndProc = Control_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(CPlApplet*); + wc.hInstance = hInst; + wc.hIcon = 0; + wc.hCursor = 0; + wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = L"Shell_Control_WndClass"; + + if (!RegisterClassW(&wc)) return; + + CreateWindowExW(0, wc.lpszClassName, appName, + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + hWnd, NULL, hInst, panel); + if (!panel->hWnd) return; + + if (!panel->first) { + /* FIXME appName & message should be localized */ + MessageBoxW(panel->hWnd, L"Cannot load any applets", appName, MB_OK); + return; + } + + while (GetMessageW(&msg, panel->hWnd, 0, 0)) { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } +} + +static void Control_DoWindow(CPanel* panel, HWND hWnd, HINSTANCE hInst) +{ + HANDLE h; + WIN32_FIND_DATAW fd; + WCHAR buffer[MAX_PATH]; + static const WCHAR wszAllCpl[] = {'*','.','c','p','l',0}; + WCHAR *p; + + GetSystemDirectoryW( buffer, MAX_PATH ); + p = buffer + wcslen(buffer); + *p++ = '\\'; + wcscpy(p, wszAllCpl); + + if ((h = FindFirstFileW(buffer, &fd)) != INVALID_HANDLE_VALUE) { + do { + wcscpy(p, fd.cFileName); + Control_LoadApplet(hWnd, buffer, panel); + } while (FindNextFileW(h, &fd)); + FindClose(h); + } + + Control_DoInterface(panel, hWnd, hInst); +} + +static void Control_DoLaunch(CPanel* panel, HWND hWnd, LPCWSTR wszCmd) + /* forms to parse: + * foo.cpl,@sp,str + * foo.cpl,@sp + * foo.cpl,,str + * foo.cpl @sp + * foo.cpl str + * "a path\foo.cpl" + */ +{ + LPWSTR buffer; + LPWSTR beg = NULL; + LPWSTR end; + WCHAR ch; + LPCWSTR ptr, ptr2; + WCHAR szName[MAX_PATH]; + unsigned sp = 0; + LPWSTR extraPmts = NULL; + int quoted = 0; + BOOL spSet = FALSE; + HANDLE hMutex; + UINT Length; + + ptr = wcsrchr(wszCmd, L'\\'); + ptr2 = wcsrchr(wszCmd, L','); + if (!ptr2) + { + ptr2 = wszCmd + wcslen(wszCmd) + 1; + } + + if (ptr) + ptr++; + else + ptr = wszCmd; + + Length = (ptr2 - ptr); + if (Length >= MAX_PATH) + return; + + memcpy(szName, (LPVOID)ptr, Length * sizeof(WCHAR)); + szName[Length] = L'\0'; + hMutex = CreateMutexW(NULL, TRUE, szName); + + if ((!hMutex) || (GetLastError() == ERROR_ALREADY_EXISTS)) + return; + buffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(wszCmd) + 1) * sizeof(*wszCmd)); + if (!buffer) + { + CloseHandle(hMutex); + return; + } + end = wcscpy(buffer, wszCmd); + for (;;) { + ch = *end; + if (ch == '"') quoted = !quoted; + if (!quoted && (ch == ' ' || ch == ',' || ch == '\0')) { + *end = '\0'; + if (beg) { + if (*beg == '@') { + sp = atoiW(beg + 1); + spSet = TRUE; + } else if (*beg == '\0') { + sp = 0; + spSet = TRUE; + } else { + extraPmts = beg; + } + } + if (ch == '\0') break; + beg = end + 1; + if (ch == ' ') while (end[1] == ' ') end++; + } + end++; + } + while ((ptr = StrChrW(buffer, '"'))) + memmove((LPVOID)ptr, ptr+1, wcslen(ptr)*sizeof(WCHAR)); + + while ((ptr = StrChrW(extraPmts, '"'))) + memmove((LPVOID)ptr, ptr+1, wcslen(ptr)*sizeof(WCHAR)); + + TRACE("cmd %s, extra %s, sp %d\n", debugstr_w(buffer), debugstr_w(extraPmts), sp); + + Control_LoadApplet(hWnd, buffer, panel); + + if (panel->first) { + CPlApplet* applet = panel->first; + + assert(applet && applet->next == NULL); + if (sp >= applet->count) { + WARN("Out of bounds (%u >= %u), setting to 0\n", sp, applet->count); + sp = 0; + } + + if ((extraPmts) && extraPmts[0] &&(!spSet)) + { + while ((lstrcmpiW(extraPmts, applet->info[sp].szName)) && (sp < applet->count)) + sp++; + + if (sp >= applet->count) + { + ReleaseMutex(hMutex); + CloseHandle(hMutex); + Control_UnloadApplet(applet); + HeapFree(GetProcessHeap(), 0, buffer); + return; + } + } + if (applet->info[sp].dwSize) { + if (!applet->proc(applet->hWnd, CPL_DBLCLK, sp, applet->info[sp].lData)) + applet->proc(applet->hWnd, CPL_STARTWPARMSA, sp, (LPARAM)extraPmts); + } + Control_UnloadApplet(applet); + } + ReleaseMutex(hMutex); + CloseHandle(hMutex); + HeapFree(GetProcessHeap(), 0, buffer); +} + +/************************************************************************* + * Control_RunDLLW [SHELL32.@] + * + */ +EXTERN_C void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow) +{ + CPanel panel; + + TRACE("(%p, %p, %s, 0x%08x)\n", + hWnd, hInst, debugstr_w(cmd), nCmdShow); + + memset(&panel, 0, sizeof(panel)); + + if (!cmd || !*cmd) { + Control_DoWindow(&panel, hWnd, hInst); + } else { + Control_DoLaunch(&panel, hWnd, cmd); + } +} + +/************************************************************************* + * Control_RunDLLA [SHELL32.@] + * + */ +EXTERN_C void WINAPI Control_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) +{ + DWORD len = MultiByteToWideChar(CP_ACP, 0, cmd, -1, NULL, 0 ); + LPWSTR wszCmd = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (wszCmd && MultiByteToWideChar(CP_ACP, 0, cmd, -1, wszCmd, len )) + { + Control_RunDLLW(hWnd, hInst, wszCmd, nCmdShow); + } + HeapFree(GetProcessHeap(), 0, wszCmd); +} + +/************************************************************************* + * Control_FillCache_RunDLLW [SHELL32.@] + * + */ +EXTERN_C HRESULT WINAPI Control_FillCache_RunDLLW(HWND hWnd, HANDLE hModule, DWORD w, DWORD x) +{ + FIXME("%p %p 0x%08x 0x%08x stub\n", hWnd, hModule, w, x); + return 0; +} + +/************************************************************************* + * Control_FillCache_RunDLLA [SHELL32.@] + * + */ +EXTERN_C HRESULT WINAPI Control_FillCache_RunDLLA(HWND hWnd, HANDLE hModule, DWORD w, DWORD x) +{ + return Control_FillCache_RunDLLW(hWnd, hModule, w, x); +} + + +/************************************************************************* + * RunDLL_CallEntry16 [SHELL32.122] + * the name is probably wrong + */ +EXTERN_C void WINAPI RunDLL_CallEntry16( DWORD proc, HWND hwnd, HINSTANCE inst, + LPCSTR cmdline, INT cmdshow ) +{ +#if !defined(__CYGWIN__) && !defined (__MINGW32__) && !defined(_MSC_VER) + WORD args[5]; + SEGPTR cmdline_seg; + + TRACE( "proc %x hwnd %p inst %p cmdline %s cmdshow %d\n", + proc, hwnd, inst, debugstr_a(cmdline), cmdshow ); + + cmdline_seg = MapLS( cmdline ); + args[4] = HWND_16(hwnd); + args[3] = MapHModuleLS(inst); + args[2] = SELECTOROF(cmdline_seg); + args[1] = OFFSETOF(cmdline_seg); + args[0] = cmdshow; + WOWCallback16Ex( proc, WCB16_PASCAL, sizeof(args), args, NULL ); + UnMapLS( cmdline_seg ); +#else + FIXME( "proc %lx hwnd %p inst %p cmdline %s cmdshow %d\n", + proc, hwnd, inst, debugstr_a(cmdline), cmdshow ); +#endif +} + +/************************************************************************* + * CallCPLEntry16 [SHELL32.166] + * + * called by desk.cpl on "Advanced" with: + * hMod("DeskCp16.Dll"), pFunc("CplApplet"), 0, 1, 0xc, 0 + * + */ +LRESULT WINAPI CallCPLEntry16(HINSTANCE hMod, FARPROC pFunc, HWND dw3, UINT dw4, LPARAM dw5, LPARAM dw6) +{ + FIXME("(%p, %p, %08x, %08x, %08x, %08x): stub.\n", hMod, pFunc, dw3, dw4, dw5, dw6); + return 0x0deadbee; +} diff --git a/reactos/dll/win32/shell32/dataobject.cpp b/reactos/dll/win32/shell32/dataobject.cpp new file mode 100644 index 00000000000..19368707ffb --- /dev/null +++ b/reactos/dll/win32/shell32/dataobject.cpp @@ -0,0 +1,391 @@ +/* + * IEnumFORMATETC, IDataObject + * + * selecting and droping objects within the shell and/or common dialogs + * + * Copyright 1998, 1999 + * + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/*********************************************************************** +* IEnumFORMATETC implementation +*/ + +class IEnumFORMATETCImpl : + public CComObjectRootEx, + public IEnumFORMATETC +{ +private: + UINT posFmt; + UINT countFmt; + LPFORMATETC pFmt; +public: + IEnumFORMATETCImpl(); + ~IEnumFORMATETCImpl(); + HRESULT WINAPI Initialize(UINT cfmt, const FORMATETC afmt[]); + + // ***************** + virtual HRESULT WINAPI Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed); + virtual HRESULT WINAPI Skip(ULONG celt); + virtual HRESULT WINAPI Reset(); + virtual HRESULT WINAPI Clone(LPENUMFORMATETC* ppenum); + +BEGIN_COM_MAP(IEnumFORMATETCImpl) + COM_INTERFACE_ENTRY_IID(IID_IEnumFORMATETC, IEnumFORMATETC) +END_COM_MAP() +}; + +IEnumFORMATETCImpl::IEnumFORMATETCImpl() +{ + posFmt = 0; + countFmt = 0; + pFmt = NULL; +} + +IEnumFORMATETCImpl::~IEnumFORMATETCImpl() +{ +} + +HRESULT WINAPI IEnumFORMATETCImpl::Initialize(UINT cfmt, const FORMATETC afmt[]) +{ + DWORD size; + + size = cfmt * sizeof(FORMATETC); + countFmt = cfmt; + pFmt = (LPFORMATETC)SHAlloc(size); + if (pFmt == NULL) + return E_OUTOFMEMORY; + + memcpy(pFmt, afmt, size); + return S_OK; +} + +HRESULT WINAPI IEnumFORMATETCImpl::Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) +{ + UINT i; + + TRACE("(%p)->(%u,%p)\n", this, celt, rgelt); + + if(!pFmt)return S_FALSE; + if(!rgelt) return E_INVALIDARG; + if (pceltFethed) *pceltFethed = 0; + + for(i = 0; posFmt < countFmt && celt > i; i++) + { + *rgelt++ = pFmt[posFmt++]; + } + + if (pceltFethed) *pceltFethed = i; + + return ((i == celt) ? S_OK : S_FALSE); +} + +HRESULT WINAPI IEnumFORMATETCImpl::Skip(ULONG celt) +{ + TRACE("(%p)->(num=%u)\n", this, celt); + + if (posFmt + celt >= countFmt) return S_FALSE; + posFmt += celt; + return S_OK; +} + +HRESULT WINAPI IEnumFORMATETCImpl::Reset() +{ + TRACE("(%p)->()\n", this); + + posFmt = 0; + return S_OK; +} + +HRESULT WINAPI IEnumFORMATETCImpl::Clone(LPENUMFORMATETC* ppenum) +{ + HRESULT hResult; + + TRACE("(%p)->(ppenum=%p)\n", this, ppenum); + + if (!ppenum) return E_INVALIDARG; + hResult = IEnumFORMATETC_Constructor(countFmt, pFmt, ppenum); + if (FAILED (hResult)) + return hResult; + return (*ppenum)->Skip(posFmt); +} + +HRESULT IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[], IEnumFORMATETC **enumerator) +{ + CComObject *theEnumerator; + CComPtr result; + HRESULT hResult; + + if (enumerator == NULL) + return E_POINTER; + *enumerator = NULL; + ATLTRY (theEnumerator = new CComObject); + if (theEnumerator == NULL) + return E_OUTOFMEMORY; + hResult = theEnumerator->QueryInterface (IID_IEnumFORMATETC, (void **)&result); + if (FAILED (hResult)) + { + delete theEnumerator; + return hResult; + } + hResult = theEnumerator->Initialize (cfmt, afmt); + if (FAILED (hResult)) + return hResult; + *enumerator = result.Detach (); + TRACE("(%p)->(%u,%p)\n", *enumerator, cfmt, afmt); + return S_OK; +} + + +/*********************************************************************** +* IDataObject implementation +*/ + +/* number of supported formats */ +#define MAX_FORMATS 4 + +class IDataObjectImpl : + public CComObjectRootEx, + public IDataObject +{ +private: + LPITEMIDLIST pidl; + LPITEMIDLIST * apidl; + UINT cidl; + + FORMATETC pFormatEtc[MAX_FORMATS]; + UINT cfShellIDList; + UINT cfFileNameA; + UINT cfFileNameW; +public: + IDataObjectImpl(); + ~IDataObjectImpl(); + HRESULT WINAPI Initialize(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidlx, UINT cidlx); + + /////////// + virtual HRESULT WINAPI GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium); + virtual HRESULT WINAPI GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium); + virtual HRESULT WINAPI QueryGetData(LPFORMATETC pformatetc); + virtual HRESULT WINAPI GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut); + virtual HRESULT WINAPI SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease); + virtual HRESULT WINAPI EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc); + virtual HRESULT WINAPI DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection); + virtual HRESULT WINAPI DUnadvise(DWORD dwConnection); + virtual HRESULT WINAPI EnumDAdvise(IEnumSTATDATA **ppenumAdvise); + +BEGIN_COM_MAP(IDataObjectImpl) + COM_INTERFACE_ENTRY_IID(IID_IDataObject, IDataObject) +END_COM_MAP() +}; + +IDataObjectImpl::IDataObjectImpl() +{ + pidl = NULL; + apidl = NULL; + cidl = 0; + cfShellIDList = 0; + cfFileNameA = 0; + cfFileNameW = 0; +} + +IDataObjectImpl::~IDataObjectImpl() +{ + TRACE(" destroying IDataObject(%p)\n",this); + _ILFreeaPidl(apidl, cidl); + ILFree(pidl); +} + +HRESULT WINAPI IDataObjectImpl::Initialize(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidlx, UINT cidlx) +{ + pidl = ILClone(pMyPidl); + apidl = _ILCopyaPidl(apidlx, cidlx); + if (pidl == NULL || apidl == NULL) + return E_OUTOFMEMORY; + cidl = cidlx; + + cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST); + cfFileNameA = RegisterClipboardFormatA(CFSTR_FILENAMEA); + cfFileNameW = RegisterClipboardFormatW(CFSTR_FILENAMEW); + InitFormatEtc(pFormatEtc[0], cfShellIDList, TYMED_HGLOBAL); + InitFormatEtc(pFormatEtc[1], CF_HDROP, TYMED_HGLOBAL); + InitFormatEtc(pFormatEtc[2], cfFileNameA, TYMED_HGLOBAL); + InitFormatEtc(pFormatEtc[3], cfFileNameW, TYMED_HGLOBAL); + return S_OK; +} + +/************************************************************************** +* IDataObject_fnGetData +*/ +HRESULT WINAPI IDataObjectImpl::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium) +{ + char szTemp[256]; + + szTemp[0] = 0; + GetClipboardFormatNameA (pformatetcIn->cfFormat, szTemp, 256); + TRACE("(%p)->(%p %p format=%s)\n", this, pformatetcIn, pmedium, szTemp); + + if (pformatetcIn->cfFormat == cfShellIDList) + { + if (cidl < 1) return(E_UNEXPECTED); + pmedium->hGlobal = RenderSHELLIDLIST(pidl, apidl, cidl); + } + else if (pformatetcIn->cfFormat == CF_HDROP) + { + if (cidl < 1) return(E_UNEXPECTED); + pmedium->hGlobal = RenderHDROP(pidl, apidl, cidl); + } + else if (pformatetcIn->cfFormat == cfFileNameA) + { + if (cidl < 1) return(E_UNEXPECTED); + pmedium->hGlobal = RenderFILENAMEA(pidl, apidl, cidl); + } + else if (pformatetcIn->cfFormat == cfFileNameW) + { + if (cidl < 1) return(E_UNEXPECTED); + pmedium->hGlobal = RenderFILENAMEW(pidl, apidl, cidl); + } + else + { + FIXME("-- expected clipformat not implemented\n"); + return (E_INVALIDARG); + } + if (pmedium->hGlobal) + { + pmedium->tymed = TYMED_HGLOBAL; + pmedium->pUnkForRelease = NULL; + return S_OK; + } + return E_OUTOFMEMORY; +} + +HRESULT WINAPI IDataObjectImpl::GetDataHere(LPFORMATETC pformatetc, STGMEDIUM *pmedium) +{ + FIXME("(%p)->()\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI IDataObjectImpl::QueryGetData(LPFORMATETC pformatetc) +{ + UINT i; + + TRACE("(%p)->(fmt=0x%08x tym=0x%08x)\n", this, pformatetc->cfFormat, pformatetc->tymed); + + if(!(DVASPECT_CONTENT & pformatetc->dwAspect)) + return DV_E_DVASPECT; + + /* check our formats table what we have */ + for (i=0; icfFormat) + && (pFormatEtc[i].tymed == pformatetc->tymed)) + { + return S_OK; + } + } + + return DV_E_TYMED; +} + +HRESULT WINAPI IDataObjectImpl::GetCanonicalFormatEtc(LPFORMATETC pformatectIn, LPFORMATETC pformatetcOut) +{ + FIXME("(%p)->()\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI IDataObjectImpl::SetData(LPFORMATETC pformatetc, STGMEDIUM *pmedium, BOOL fRelease) +{ + FIXME("(%p)->()\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI IDataObjectImpl::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) +{ + TRACE("(%p)->()\n", this); + *ppenumFormatEtc = NULL; + + /* only get data */ + if (DATADIR_GET == dwDirection) + { + return IEnumFORMATETC_Constructor(MAX_FORMATS, pFormatEtc, ppenumFormatEtc); + } + + return E_NOTIMPL; +} + +HRESULT WINAPI IDataObjectImpl::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) +{ + FIXME("(%p)->()\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI IDataObjectImpl::DUnadvise(DWORD dwConnection) +{ + FIXME("(%p)->()\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI IDataObjectImpl::EnumDAdvise(IEnumSTATDATA **ppenumAdvise) +{ + FIXME("(%p)->()\n", this); + return E_NOTIMPL; +} + +/************************************************************************** +* IDataObject_Constructor +*/ +HRESULT IDataObject_Constructor(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidl, UINT cidl, IDataObject **dataObject) +{ + CComObject *theDataObject; + CComPtr result; + HRESULT hResult; + + if (dataObject == NULL) + return E_POINTER; + *dataObject = NULL; + ATLTRY (theDataObject = new CComObject); + if (theDataObject == NULL) + return E_OUTOFMEMORY; + hResult = theDataObject->QueryInterface (IID_IDataObject, (void **)&result); + if (FAILED (hResult)) + { + delete theDataObject; + return hResult; + } + hResult = theDataObject->Initialize (hwndOwner, pMyPidl, apidl, cidl); + if (FAILED (hResult)) + return hResult; + *dataObject = result.Detach (); + TRACE("(%p)->(apidl=%p cidl=%u)\n", *dataObject, apidl, cidl); + return S_OK; +} + +/************************************************************************* + * SHCreateDataObject [SHELL32.@] + * + */ + +HRESULT WINAPI SHCreateDataObject(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST* apidl, IDataObject *pdtInner, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, IID_IDataObject)) + { + return CIDLData_CreateFromIDArray(pidlFolder, cidl, apidl, (IDataObject **)ppv); + } + return E_FAIL; +} diff --git a/reactos/dll/win32/shell32/dde.cpp b/reactos/dll/win32/shell32/dde.cpp new file mode 100644 index 00000000000..96139bbdb7a --- /dev/null +++ b/reactos/dll/win32/shell32/dde.cpp @@ -0,0 +1,170 @@ +/* + * Shell DDE Handling + * + * Copyright 2004 Robert Shearman + * + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* String handles */ +static HSZ hszProgmanTopic; +static HSZ hszProgmanService; +static HSZ hszAsterisk; +static HSZ hszShell; +static HSZ hszAppProperties; +static HSZ hszFolders; +/* DDE Instance ID */ +static DWORD dwDDEInst; + + +static BOOL __inline Dde_OnConnect(HSZ hszTopic, HSZ hszService) +{ + if ((hszTopic == hszProgmanTopic) && (hszService == hszProgmanService)) + return TRUE; + if ((hszTopic == hszProgmanTopic) && (hszService == hszAppProperties)) + return TRUE; + if ((hszTopic == hszShell) && (hszService == hszFolders)) + return TRUE; + if ((hszTopic == hszShell) && (hszService == hszAppProperties)) + return TRUE; + return FALSE; +} + +static void __inline Dde_OnConnectConfirm(HCONV hconv, HSZ hszTopic, HSZ hszService) +{ + FIXME("stub\n"); +} + +static BOOL __inline Dde_OnWildConnect(HSZ hszTopic, HSZ hszService) +{ + FIXME("stub\n"); + return FALSE; +} + +static HDDEDATA __inline Dde_OnRequest(UINT uFmt, HCONV hconv, HSZ hszTopic, + HSZ hszItem) +{ + FIXME("stub\n"); + return NULL; +} + +static DWORD __inline Dde_OnExecute(HCONV hconv, HSZ hszTopic, HDDEDATA hdata) +{ + BYTE * pszCommand; + + pszCommand = DdeAccessData(hdata, NULL); + if (!pszCommand) + return DDE_FNOTPROCESSED; + + FIXME("stub: %s\n", pszCommand); + + DdeUnaccessData(hdata); + + return DDE_FNOTPROCESSED; +} + +static void __inline Dde_OnDisconnect(HCONV hconv) +{ + FIXME("stub\n"); +} + +static HDDEDATA CALLBACK DdeCallback( + UINT uType, + UINT uFmt, + HCONV hconv, + HSZ hsz1, + HSZ hsz2, + HDDEDATA hdata, + ULONG_PTR dwData1, + ULONG_PTR dwData2) +{ + switch (uType) + { + case XTYP_CONNECT: + return (HDDEDATA)(DWORD_PTR)Dde_OnConnect(hsz1, hsz2); + case XTYP_CONNECT_CONFIRM: + Dde_OnConnectConfirm(hconv, hsz1, hsz2); + return NULL; + case XTYP_WILDCONNECT: + return (HDDEDATA)(DWORD_PTR)Dde_OnWildConnect(hsz1, hsz2); + case XTYP_REQUEST: + return Dde_OnRequest(uFmt, hconv, hsz1, hsz2); + case XTYP_EXECUTE: + return (HDDEDATA)(DWORD_PTR)Dde_OnExecute(hconv, hsz1, hdata); + case XTYP_DISCONNECT: + Dde_OnDisconnect(hconv); + return NULL; + default: + return NULL; + } +} + +/************************************************************************* + * ShellDDEInit (SHELL32.@) + * + * Registers the Shell DDE services with the system so that applications + * can use them. + * + * PARAMS + * bInit [I] TRUE to initialize the services, FALSE to uninitalize. + * + * RETURNS + * Nothing. + */ +EXTERN_C void WINAPI ShellDDEInit(BOOL bInit) +{ + TRACE("bInit = %s\n", bInit ? "TRUE" : "FALSE"); + + if (bInit) + { + static const WCHAR wszProgman[] = {'P','r','o','g','m','a','n',0}; + static const WCHAR wszAsterisk[] = {'*',0}; + static const WCHAR wszShell[] = {'S','h','e','l','l',0}; + static const WCHAR wszAppProperties[] = + {'A','p','p','P','r','o','p','e','r','t','i','e','s',0}; + static const WCHAR wszFolders[] = {'F','o','l','d','e','r','s',0}; + + DdeInitializeW(&dwDDEInst, DdeCallback, CBF_FAIL_ADVISES | CBF_FAIL_POKES, 0); + + hszProgmanTopic = DdeCreateStringHandleW(dwDDEInst, wszProgman, CP_WINUNICODE); + hszProgmanService = DdeCreateStringHandleW(dwDDEInst, wszProgman, CP_WINUNICODE); + hszAsterisk = DdeCreateStringHandleW(dwDDEInst, wszAsterisk, CP_WINUNICODE); + hszShell = DdeCreateStringHandleW(dwDDEInst, wszShell, CP_WINUNICODE); + hszAppProperties = DdeCreateStringHandleW(dwDDEInst, wszAppProperties, CP_WINUNICODE); + hszFolders = DdeCreateStringHandleW(dwDDEInst, wszFolders, CP_WINUNICODE); + + DdeNameService(dwDDEInst, hszFolders, 0, DNS_REGISTER); + DdeNameService(dwDDEInst, hszProgmanService, 0, DNS_REGISTER); + DdeNameService(dwDDEInst, hszShell, 0, DNS_REGISTER); + } + else + { + /* unregister all services */ + DdeNameService(dwDDEInst, 0, 0, DNS_UNREGISTER); + + DdeFreeStringHandle(dwDDEInst, hszFolders); + DdeFreeStringHandle(dwDDEInst, hszAppProperties); + DdeFreeStringHandle(dwDDEInst, hszShell); + DdeFreeStringHandle(dwDDEInst, hszAsterisk); + DdeFreeStringHandle(dwDDEInst, hszProgmanService); + DdeFreeStringHandle(dwDDEInst, hszProgmanTopic); + + DdeUninitialize(dwDDEInst); + } +} diff --git a/reactos/dll/win32/shell32/debughlp.cpp b/reactos/dll/win32/shell32/debughlp.cpp new file mode 100644 index 00000000000..a64b6f7dfae --- /dev/null +++ b/reactos/dll/win32/shell32/debughlp.cpp @@ -0,0 +1,434 @@ +/* + * Helper functions for debugging + * + * Copyright 1998, 2002 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(pidl); + +static +LPITEMIDLIST _dbg_ILGetNext(LPCITEMIDLIST pidl) +{ + WORD len; + + if(pidl) + { + len = pidl->mkid.cb; + if (len) + { + return (LPITEMIDLIST) (((LPBYTE)pidl)+len); + } + } + return NULL; +} + +static +BOOL _dbg_ILIsDesktop(LPCITEMIDLIST pidl) +{ + return ( !pidl || (pidl && pidl->mkid.cb == 0x00) ); +} + +static +LPPIDLDATA _dbg_ILGetDataPointer(LPCITEMIDLIST pidl) +{ + if(pidl && pidl->mkid.cb != 0x00) + return (LPPIDLDATA) &(pidl->mkid.abID); + return NULL; +} + +static +LPSTR _dbg_ILGetTextPointer(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); + + if (pdata) + { + switch (pdata->type) + { + case PT_GUID: + case PT_SHELLEXT: + case PT_YAGUID: + return NULL; + + case PT_DRIVE: + case PT_DRIVE1: + case PT_DRIVE2: + case PT_DRIVE3: + return (LPSTR)&(pdata->u.drive.szDriveName); + + case PT_FOLDER: + case PT_FOLDER1: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + return (LPSTR)&(pdata->u.file.szNames); + + case PT_WORKGRP: + case PT_COMP: + case PT_NETWORK: + case PT_NETPROVIDER: + case PT_SHARE: + return (LPSTR)&(pdata->u.network.szNames); + } + } + return NULL; +} + +static +LPWSTR _dbg_ILGetTextPointerW(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); + + if (pdata) + { + switch (pdata->type) + { + case PT_GUID: + case PT_SHELLEXT: + case PT_YAGUID: + return NULL; + + case PT_DRIVE: + case PT_DRIVE1: + case PT_DRIVE2: + case PT_DRIVE3: + /* return (LPSTR)&(pdata->u.drive.szDriveName);*/ + return NULL; + + case PT_FOLDER: + case PT_FOLDER1: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + /* return (LPSTR)&(pdata->u.file.szNames); */ + return NULL; + + case PT_WORKGRP: + case PT_COMP: + case PT_NETWORK: + case PT_NETPROVIDER: + case PT_SHARE: + /* return (LPSTR)&(pdata->u.network.szNames); */ + return NULL; + + case PT_VALUEW: + return (LPWSTR)&(pdata->u.file.szNames); + } + } + return NULL; +} + + +static +LPSTR _dbg_ILGetSTextPointer(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); + + if (pdata) + { + switch (pdata->type) + { + case PT_FOLDER: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + return (LPSTR)(pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1); + + case PT_WORKGRP: + return (LPSTR)(pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1); + } + } + return NULL; +} + +static +LPWSTR _dbg_ILGetSTextPointerW(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata =_dbg_ILGetDataPointer(pidl); + + if (pdata) + { + switch (pdata->type) + { + case PT_FOLDER: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + /*return (LPSTR)(pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1); */ + return NULL; + + case PT_WORKGRP: + /* return (LPSTR)(pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1); */ + return NULL; + + case PT_VALUEW: + return (LPWSTR)(pdata->u.file.szNames + wcslen ((LPWSTR)pdata->u.file.szNames) + 1); + } + } + return NULL; +} + + +static +IID* _dbg_ILGetGUIDPointer(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata =_ILGetDataPointer(pidl); + + if (pdata) + { + switch (pdata->type) + { + case PT_SHELLEXT: + case PT_GUID: + case PT_YAGUID: + return &(pdata->u.guid.guid); + } + } + return NULL; +} + +static +void _dbg_ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) +{ + LPSTR szSrc; + LPWSTR szSrcW; + GUID const * riid; + + if (!pidl) return; + + if (szOut) + *szOut = 0; + + if (_dbg_ILIsDesktop(pidl)) + { + /* desktop */ + if (szOut) lstrcpynA(szOut, "Desktop", uOutSize); + } + else if (( szSrc = _dbg_ILGetTextPointer(pidl) )) + { + /* filesystem */ + if (szOut) lstrcpynA(szOut, szSrc, uOutSize); + } + else if (( szSrcW = _dbg_ILGetTextPointerW(pidl) )) + { + CHAR tmp[MAX_PATH]; + /* unicode filesystem */ + WideCharToMultiByte(CP_ACP,0,szSrcW, -1, tmp, MAX_PATH, NULL, NULL); + if (szOut) lstrcpynA(szOut, tmp, uOutSize); + } + else if (( riid = _dbg_ILGetGUIDPointer(pidl) )) + { + if (szOut) + sprintf( szOut, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + riid->Data1, riid->Data2, riid->Data3, + riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3], + riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7] ); + } +} + + + + +void pdump (LPCITEMIDLIST pidl) +{ + LPCITEMIDLIST pidltemp = pidl; + + if (!TRACE_ON(pidl)) return; + + if (! pidltemp) + { + MESSAGE ("-------- pidl=NULL (Desktop)\n"); + } + else + { + MESSAGE ("-------- pidl=%p\n", pidl); + if (pidltemp->mkid.cb) + { + do + { + if (_ILIsUnicode(pidltemp)) + { + DWORD dwAttrib = 0; + LPPIDLDATA pData = _dbg_ILGetDataPointer(pidltemp); + DWORD type = pData ? pData->type : 0; + LPWSTR szLongName = _dbg_ILGetTextPointerW(pidltemp); + LPWSTR szShortName = _dbg_ILGetSTextPointerW(pidltemp); + char szName[MAX_PATH]; + + _dbg_ILSimpleGetText(pidltemp, szName, MAX_PATH); + if ( pData && (PT_FOLDER == type || PT_VALUE == type) ) + dwAttrib = pData->u.file.uFileAttribs; + + MESSAGE ("[%p] size=%04u type=%x attr=0x%08x name=%s (%s,%s)\n", + pidltemp, pidltemp->mkid.cb, type, dwAttrib, + debugstr_a(szName), debugstr_w(szLongName), debugstr_w(szShortName)); + } + else + { + DWORD dwAttrib = 0; + LPPIDLDATA pData = _dbg_ILGetDataPointer(pidltemp); + DWORD type = pData ? pData->type : 0; + LPSTR szLongName = _dbg_ILGetTextPointer(pidltemp); + LPSTR szShortName = _dbg_ILGetSTextPointer(pidltemp); + char szName[MAX_PATH]; + + _dbg_ILSimpleGetText(pidltemp, szName, MAX_PATH); + if ( pData && (PT_FOLDER == type || PT_VALUE == type) ) + dwAttrib = pData->u.file.uFileAttribs; + + MESSAGE ("[%p] size=%04u type=%x attr=0x%08x name=%s (%s,%s)\n", + pidltemp, pidltemp->mkid.cb, type, dwAttrib, + debugstr_a(szName), debugstr_a(szLongName), debugstr_a(szShortName)); + } + + pidltemp = _dbg_ILGetNext(pidltemp); + + } while (pidltemp && pidltemp->mkid.cb); + } + else + { + MESSAGE ("empty pidl (Desktop)\n"); + } + pcheck(pidl); + } +} + +static void dump_pidl_hex( LPCITEMIDLIST pidl ) +{ + const unsigned char *p = (const unsigned char *)pidl; + const int max_bytes = 0x80; +#define max_line 0x10 + char szHex[max_line*3+1], szAscii[max_line+1]; + int i, n; + + n = pidl->mkid.cb; + if( n>max_bytes ) + n = max_bytes; + for( i=0; imkid.cb ) + { + LPPIDLDATA pidlData = _dbg_ILGetDataPointer(pidltemp); + + if (pidlData) + { + type = pidlData->type; + switch( type ) + { + case PT_CPLAPPLET: + case PT_GUID: + case PT_SHELLEXT: + case PT_DRIVE: + case PT_DRIVE1: + case PT_DRIVE2: + case PT_DRIVE3: + case PT_FOLDER: + case PT_VALUE: + case PT_VALUEW: + case PT_FOLDER1: + case PT_WORKGRP: + case PT_COMP: + case PT_NETPROVIDER: + case PT_NETWORK: + case PT_IESPECIAL1: + case PT_YAGUID: + case PT_IESPECIAL2: + case PT_SHARE: + break; + default: + ERR("unknown IDLIST %p [%p] size=%u type=%x\n", + pidl, pidltemp, pidltemp->mkid.cb,type ); + dump_pidl_hex( pidltemp ); + return FALSE; + } + pidltemp = _dbg_ILGetNext(pidltemp); + } + else + { + return FALSE; + } + } + return TRUE; +} + +static const struct { + REFIID riid; + const char *name; +} InterfaceDesc[] = { + {IID_IUnknown, "IID_IUnknown"}, + {IID_IClassFactory, "IID_IClassFactory"}, + {IID_IShellView, "IID_IShellView"}, + {IID_IOleCommandTarget, "IID_IOleCommandTarget"}, + {IID_IDropTarget, "IID_IDropTarget"}, + {IID_IDropSource, "IID_IDropSource"}, + {IID_IViewObject, "IID_IViewObject"}, + {IID_IContextMenu, "IID_IContextMenu"}, + {IID_IShellExtInit, "IID_IShellExtInit"}, + {IID_IShellFolder, "IID_IShellFolder"}, + {IID_IShellFolder2, "IID_IShellFolder2"}, + {IID_IPersist, "IID_IPersist"}, + {IID_IPersistFolder, "IID_IPersistFolder"}, + {IID_IPersistFolder2, "IID_IPersistFolder2"}, + {IID_IPersistFolder3, "IID_IPersistFolder3"}, + {IID_IExtractIconA, "IID_IExtractIconA"}, + {IID_IExtractIconW, "IID_IExtractIconW"}, + {IID_IDataObject, "IID_IDataObject"}, + {IID_IAutoComplete, "IID_IAutoComplete"}, + {IID_IAutoComplete2, "IID_IAutoComplete2"}, + {IID_IShellLinkA, "IID_IShellLinkA"}, + {IID_IShellLinkW, "IID_IShellLinkW"}, + }; + +const char * shdebugstr_guid( const struct _GUID *id ) +{ + unsigned int i; + const char* name = NULL; + char clsidbuf[100]; + + if (!id) return "(null)"; + + for (i=0; i < sizeof(InterfaceDesc) / sizeof(InterfaceDesc[0]); i++) { + if (IsEqualIID(InterfaceDesc[i].riid, *id)) name = InterfaceDesc[i].name; + } + if (!name) { + if (HCR_GetClassNameA(*id, clsidbuf, 100)) + name = clsidbuf; + } + + return wine_dbg_sprintf( "\n\t{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x} (%s)", + id->Data1, id->Data2, id->Data3, + id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], + id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], name ? name : "unknown" ); +} diff --git a/reactos/dll/win32/shell32/desktop.cpp b/reactos/dll/win32/shell32/desktop.cpp new file mode 100644 index 00000000000..c5a6ec6d41f --- /dev/null +++ b/reactos/dll/win32/shell32/desktop.cpp @@ -0,0 +1,561 @@ +/* + * Shell Desktop + * + * Copyright 2008 Thomas Bluemel + * + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL(desktop); + +BOOL WINAPI SetShellWindowEx(HWND, HWND); + +#define SHDESK_TAG 0x4b534544 + +static const WCHAR szProgmanClassName[] = {'P','r','o','g','m','a','n'}; +static const WCHAR szProgmanWindowName[] = { + 'P','r','o','g','r','a','m',' ','M','a','n','a','g','e','r' +}; + +class CDesktopBrowser : + public CComObjectRootEx, + public IShellBrowser, + public ICommDlgBrowser, + public IServiceProvider +{ +public: + DWORD Tag; +private: + HWND hWnd; + HWND hWndShellView; + HWND hWndDesktopListView; + CComPtr ShellDesk; + CComPtr DesktopView; + IShellBrowser *DefaultShellBrowser; + LPITEMIDLIST pidlDesktopDirectory; + LPITEMIDLIST pidlDesktop; +public: + CDesktopBrowser(); + ~CDesktopBrowser(); + HRESULT Initialize(HWND hWndx, IShellDesktopTray *ShellDeskx); + HWND FindDesktopListView (); + BOOL CreateDeskWnd(); + HWND DesktopGetWindowControl(IN UINT id); + static LRESULT CALLBACK ProgmanWindowProc(IN HWND hwnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam); + static BOOL MessageLoop(); + + // *** IOleWindow methods *** + virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd); + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + + // *** IShellBrowser methods *** + virtual HRESULT STDMETHODCALLTYPE InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths); + virtual HRESULT STDMETHODCALLTYPE SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject); + virtual HRESULT STDMETHODCALLTYPE RemoveMenusSB(HMENU hmenuShared); + virtual HRESULT STDMETHODCALLTYPE SetStatusTextSB(LPCOLESTR pszStatusText); + virtual HRESULT STDMETHODCALLTYPE EnableModelessSB(BOOL fEnable); + virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorSB(MSG *pmsg, WORD wID); + virtual HRESULT STDMETHODCALLTYPE BrowseObject(LPCITEMIDLIST pidl, UINT wFlags); + virtual HRESULT STDMETHODCALLTYPE GetViewStateStream(DWORD grfMode, IStream **ppStrm); + virtual HRESULT STDMETHODCALLTYPE GetControlWindow(UINT id, HWND *lphwnd); + virtual HRESULT STDMETHODCALLTYPE SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret); + virtual HRESULT STDMETHODCALLTYPE QueryActiveShellView(struct IShellView **ppshv); + virtual HRESULT STDMETHODCALLTYPE OnViewWindowActive(struct IShellView *ppshv); + virtual HRESULT STDMETHODCALLTYPE SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags); + + // *** ICommDlgBrowser methods *** + virtual HRESULT STDMETHODCALLTYPE OnDefaultCommand (struct IShellView *ppshv); + virtual HRESULT STDMETHODCALLTYPE OnStateChange (struct IShellView *ppshv, ULONG uChange); + virtual HRESULT STDMETHODCALLTYPE IncludeObject (struct IShellView *ppshv, LPCITEMIDLIST pidl); + + // *** IServiceProvider methods *** + virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); + +BEGIN_COM_MAP(CDesktopBrowser) + COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) + COM_INTERFACE_ENTRY_IID(IID_IShellBrowser, IShellBrowser) + COM_INTERFACE_ENTRY_IID(IID_ICommDlgBrowser, ICommDlgBrowser) + COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) +END_COM_MAP() +}; + +CDesktopBrowser::CDesktopBrowser() +{ + Tag = SHDESK_TAG; + hWnd = NULL; + hWndShellView = NULL; + hWndDesktopListView = NULL; + DefaultShellBrowser = NULL; + pidlDesktopDirectory = NULL; + pidlDesktop = NULL; +} + +CDesktopBrowser::~CDesktopBrowser() +{ + if (DesktopView.p != NULL) + { + if (hWndShellView != NULL) + DesktopView->DestroyViewWindow(); + + hWndShellView = NULL; + hWndDesktopListView = NULL; + } + + if (pidlDesktopDirectory != NULL) + { + ILFree(pidlDesktopDirectory); + pidlDesktopDirectory = NULL; + } + + if (pidlDesktop != NULL) + { + ILFree(pidlDesktop); + pidlDesktop = NULL; + } +} + +HRESULT CDesktopBrowser::Initialize(HWND hWndx, IShellDesktopTray *ShellDeskx) +{ + CComPtr psfDesktopFolder; + CSFV csfv; + HRESULT hRet; + + hWnd = hWndx; + ShellDesk = ShellDeskx; + ShellDesk->AddRef(); + + pidlDesktopDirectory = SHCloneSpecialIDList(hWnd, CSIDL_DESKTOPDIRECTORY, FALSE); + hRet = SHGetSpecialFolderLocation(hWnd, CSIDL_DESKTOP, &pidlDesktop); + if (FAILED(hRet)) + return hRet; + + hRet = SHGetDesktopFolder(&psfDesktopFolder); + if (FAILED(hRet)) + return hRet; + + ZeroMemory(&csfv, sizeof(csfv)); + csfv.cbSize = sizeof(csfv); + csfv.pshf = psfDesktopFolder; + csfv.psvOuter = NULL; + + hRet = SHCreateShellFolderViewEx(&csfv, &DesktopView); + + return hRet; +} + +static CDesktopBrowser *SHDESK_Create(HWND hWnd, LPCREATESTRUCT lpCreateStruct) +{ + IShellDesktopTray *ShellDesk; + CComObject *pThis; + HRESULT hRet; + + ShellDesk = (IShellDesktopTray *)lpCreateStruct->lpCreateParams; + if (ShellDesk == NULL) + { + WARN("No IShellDesk interface provided!"); + return NULL; + } + + pThis = new CComObject; + if (pThis == NULL) + return NULL; + pThis->AddRef(); + + hRet = pThis->Initialize(hWnd, ShellDesk); + if (FAILED(hRet)) + { + pThis->Release(); + return NULL; + } + + return pThis; +} + +HWND CDesktopBrowser::FindDesktopListView () +{ + return FindWindowExW(hWndShellView, NULL, WC_LISTVIEW, NULL); +} + +BOOL CDesktopBrowser::CreateDeskWnd() +{ + FOLDERSETTINGS fs; + RECT rcClient; + HRESULT hRet; + + if (!GetClientRect(hWnd, &rcClient)) + { + return FALSE; + } + + fs.ViewMode = FVM_ICON; + fs.fFlags = FWF_DESKTOP | FWF_NOCLIENTEDGE | FWF_NOSCROLL | FWF_TRANSPARENT; + hRet = DesktopView->CreateViewWindow(NULL, &fs, (IShellBrowser *)this, &rcClient, &hWndShellView); + if (!SUCCEEDED(hRet)) + return FALSE; + + SetShellWindowEx(hWnd, FindDesktopListView()); + + return TRUE; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetWindow(HWND *phwnd) +{ + if (hWnd != NULL) + { + *phwnd = hWnd; + return S_OK; + } + + *phwnd = NULL; + return E_UNEXPECTED; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::ContextSensitiveHelp(BOOL fEnterMode) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::RemoveMenusSB(HMENU hmenuShared) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetStatusTextSB(LPCOLESTR lpszStatusText) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::EnableModelessSB(BOOL fEnable) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::TranslateAcceleratorSB(LPMSG lpmsg, WORD wID) +{ + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetViewStateStream(DWORD grfMode, IStream **ppStrm) +{ + return E_NOTIMPL; +} + +HWND CDesktopBrowser::DesktopGetWindowControl(IN UINT id) +{ + switch (id) + { + case FCW_TOOLBAR: + case FCW_STATUS: + case FCW_TREE: + case FCW_PROGRESS: + return NULL; + + default: + return NULL; + } + +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetControlWindow(UINT id, HWND *lphwnd) +{ + HWND hWnd; + + hWnd = DesktopGetWindowControl(id); + if (hWnd != NULL) + { + *lphwnd = hWnd; + return S_OK; + } + + *lphwnd = NULL; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret) +{ + HWND hWnd; + + if (pret == NULL) + return E_POINTER; + + hWnd = DesktopGetWindowControl(id); + if (hWnd != NULL) + { + *pret = SendMessageW(hWnd, + uMsg, + wParam, + lParam); + return S_OK; + } + + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryActiveShellView(IShellView **ppshv) +{ + *ppshv = DesktopView; + if (DesktopView != NULL) + DesktopView->AddRef(); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnViewWindowActive(IShellView *ppshv) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnDefaultCommand(IShellView *ppshv) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnStateChange(IShellView *ppshv, ULONG uChange) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::IncludeObject(IShellView *ppshv, LPCITEMIDLIST pidl) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryService(REFGUID guidService, REFIID riid, PVOID *ppv) +{ + /* FIXME - handle guidService */ + return QueryInterface(riid, ppv); +} + +BOOL CDesktopBrowser::MessageLoop() +{ + MSG Msg; + BOOL bRet; + + while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0) + { + if (bRet != -1) + { + TranslateMessage(&Msg); + DispatchMessageW(&Msg); + } + } + + return TRUE; +} + +LRESULT CALLBACK CDesktopBrowser::ProgmanWindowProc(IN HWND hwnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) +{ + CDesktopBrowser *pThis = NULL; + LRESULT Ret = FALSE; + + if (uMsg != WM_NCCREATE) + { + pThis = (CDesktopBrowser*)GetWindowLongPtrW(hwnd, + 0); + if (pThis == NULL) + goto DefMsgHandler; + } + + if (pThis != NULL || uMsg == WM_NCCREATE) + { + switch (uMsg) + { + case WM_ERASEBKGND: + return (LRESULT)PaintDesktop((HDC)wParam); + + case WM_GETISHELLBROWSER: + Ret = (LRESULT)((IShellBrowser *)pThis); + break; + + case WM_SIZE: + if (wParam == SIZE_MINIMIZED) + { + /* Hey, we're the desktop!!! */ + ShowWindow(hwnd, + SW_RESTORE); + } + else + { + RECT rcDesktop; + + rcDesktop.left = GetSystemMetrics(SM_XVIRTUALSCREEN); + rcDesktop.top = GetSystemMetrics(SM_YVIRTUALSCREEN); + rcDesktop.right = GetSystemMetrics(SM_CXVIRTUALSCREEN); + rcDesktop.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + /* FIXME: Update work area */ + } + break; + + case WM_SYSCOLORCHANGE: + { + InvalidateRect(pThis->hWnd, + NULL, + TRUE); + + if (pThis->hWndShellView != NULL) + { + /* Forward the message */ + SendMessageW(pThis->hWndShellView, + WM_SYSCOLORCHANGE, + wParam, + lParam); + } + break; + } + + case WM_CREATE: + { + pThis->ShellDesk->RegisterDesktopWindow(pThis->hWnd); + + if (!pThis->CreateDeskWnd()) + WARN("Could not create the desktop view control!\n"); + break; + } + + case WM_NCCREATE: + { + LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam; + pThis = SHDESK_Create(hwnd, CreateStruct); + if (pThis == NULL) + { + WARN("Failed to create desktop structure\n"); + break; + } + + SetWindowLongPtrW(hwnd, + 0, + (LONG_PTR)pThis); + Ret = TRUE; + break; + } + + case WM_NCDESTROY: + { + pThis->Release(); + break; + } + + default: +DefMsgHandler: + Ret = DefWindowProcW(hwnd, uMsg, wParam, lParam); + break; + } + } + + return Ret; +} + +static BOOL +RegisterProgmanWindowClass(VOID) +{ + WNDCLASSW wcProgman; + + wcProgman.style = CS_DBLCLKS; + wcProgman.lpfnWndProc = CDesktopBrowser::ProgmanWindowProc; + wcProgman.cbClsExtra = 0; + wcProgman.cbWndExtra = sizeof(CDesktopBrowser *); + wcProgman.hInstance = shell32_hInstance; + wcProgman.hIcon = NULL; + wcProgman.hCursor = LoadCursorW(NULL, IDC_ARROW); + wcProgman.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1); + wcProgman.lpszMenuName = NULL; + wcProgman.lpszClassName = szProgmanClassName; + + return RegisterClassW(&wcProgman) != 0; +} + + +/************************************************************************* + * SHCreateDesktop [SHELL32.200] + * + */ +HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk) +{ + HWND hWndDesk; + RECT rcDesk; + + if (ShellDesk == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + if (RegisterProgmanWindowClass() == 0) + { + WARN("Failed to register the Progman window class!\n"); + return NULL; + } + + rcDesk.left = GetSystemMetrics(SM_XVIRTUALSCREEN); + rcDesk.top = GetSystemMetrics(SM_YVIRTUALSCREEN); + rcDesk.right = rcDesk.left + GetSystemMetrics(SM_CXVIRTUALSCREEN); + rcDesk.bottom = rcDesk.top + GetSystemMetrics(SM_CYVIRTUALSCREEN); + + if (IsRectEmpty(&rcDesk)) + { + rcDesk.left = rcDesk.top = 0; + rcDesk.right = GetSystemMetrics(SM_CXSCREEN); + rcDesk.bottom = GetSystemMetrics(SM_CYSCREEN); + } + + hWndDesk = CreateWindowExW(0, szProgmanClassName, szProgmanWindowName, + WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, + rcDesk.left, rcDesk.top, rcDesk.right, rcDesk.bottom, + NULL, NULL, shell32_hInstance, (LPVOID)ShellDesk); + if (hWndDesk != NULL) + return (HANDLE)GetWindowLongPtrW(hWndDesk, 0); + + return NULL; +} + +/************************************************************************* + * SHCreateDesktop [SHELL32.201] + * + */ +BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop) +{ + CDesktopBrowser *Desk = (CDesktopBrowser *)hDesktop; + + if (Desk == NULL || Desk->Tag != SHDESK_TAG) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + return Desk->MessageLoop(); +} diff --git a/reactos/dll/win32/shell32/dialogs.cpp b/reactos/dll/win32/shell32/dialogs.cpp new file mode 100644 index 00000000000..89e40644998 --- /dev/null +++ b/reactos/dll/win32/shell32/dialogs.cpp @@ -0,0 +1,738 @@ +/* + * common shell dialogs + * + * Copyright 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 + */ + +#include + + +typedef struct +{ + HWND hwndOwner ; + HICON hIcon ; + LPCWSTR lpstrDirectory ; + LPCWSTR lpstrTitle ; + LPCWSTR lpstrDescription ; + UINT uFlags ; +} RUNFILEDLGPARAMS ; + +typedef BOOL (WINAPI * LPFNOFN) (OPENFILENAMEW *) ; + +WINE_DEFAULT_DEBUG_CHANNEL(shell); +static INT_PTR CALLBACK RunDlgProc (HWND, UINT, WPARAM, LPARAM) ; +static void FillList (HWND, char *, BOOL) ; + + +/************************************************************************* + * PickIconDlg [SHELL32.62] + * + */ + +typedef struct +{ + HMODULE hLibrary; + HWND hDlgCtrl; + WCHAR szName[MAX_PATH]; + INT Index; +}PICK_ICON_CONTEXT, *PPICK_ICON_CONTEXT; + +BOOL CALLBACK EnumPickIconResourceProc(HMODULE hModule, + LPCWSTR lpszType, + LPWSTR lpszName, + LONG_PTR lParam +) +{ + WCHAR szName[100]; + int index; + HICON hIcon; + PPICK_ICON_CONTEXT pIconContext = (PPICK_ICON_CONTEXT)lParam; + + if (IS_INTRESOURCE(lpszName)) + swprintf(szName, L"%u", lpszName); + else + wcscpy(szName, (WCHAR*)lpszName); + + + hIcon = LoadIconW(pIconContext->hLibrary, (LPCWSTR)lpszName); + if (hIcon == NULL) + return TRUE; + + index = SendMessageW(pIconContext->hDlgCtrl, LB_ADDSTRING, 0, (LPARAM)szName); + if (index != LB_ERR) + SendMessageW(pIconContext->hDlgCtrl, LB_SETITEMDATA, index, (LPARAM)hIcon); + + return TRUE; +} + +void +DestroyIconList(HWND hDlgCtrl) +{ + int count; + int index; + + count = SendMessage(hDlgCtrl, LB_GETCOUNT, 0, 0); + if (count == LB_ERR) + return; + + for(index = 0; index < count; index++) + { + HICON hIcon = (HICON)SendMessageW(hDlgCtrl, LB_GETITEMDATA, index, 0); + DestroyIcon(hIcon); + } +} + +INT_PTR CALLBACK PickIconProc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + LPMEASUREITEMSTRUCT lpmis; + LPDRAWITEMSTRUCT lpdis; + HICON hIcon; + INT index, count; + WCHAR szText[MAX_PATH], szTitle[100], szFilter[100]; + OPENFILENAMEW ofn = {0}; + + PPICK_ICON_CONTEXT pIconContext = (PPICK_ICON_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER); + + switch(uMsg) + { + case WM_INITDIALOG: + pIconContext = (PPICK_ICON_CONTEXT)lParam; + SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG)pIconContext); + pIconContext->hDlgCtrl = GetDlgItem(hwndDlg, IDC_PICKICON_LIST); + EnumResourceNamesW(pIconContext->hLibrary, RT_ICON, EnumPickIconResourceProc, (LPARAM)pIconContext); + if (PathUnExpandEnvStringsW(pIconContext->szName, szText, MAX_PATH)) + SendDlgItemMessageW(hwndDlg, IDC_EDIT_PATH, WM_SETTEXT, 0, (LPARAM)szText); + else + SendDlgItemMessageW(hwndDlg, IDC_EDIT_PATH, WM_SETTEXT, 0, (LPARAM)pIconContext->szName); + + count = SendMessage(pIconContext->hDlgCtrl, LB_GETCOUNT, 0, 0); + if (count != LB_ERR) + { + if (count > pIconContext->Index) + SendMessageW(pIconContext->hDlgCtrl, LB_SETCURSEL, pIconContext->Index, 0); + else + SendMessageW(pIconContext->hDlgCtrl, LB_SETCURSEL, 0, 0); + } + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + index = SendMessageW(pIconContext->hDlgCtrl, LB_GETCURSEL, 0, 0); + pIconContext->Index = index; + SendDlgItemMessageW(hwndDlg, IDC_EDIT_PATH, WM_GETTEXT, MAX_PATH, (LPARAM)pIconContext->szName); + DestroyIconList(pIconContext->hDlgCtrl); + EndDialog(hwndDlg, 1); + break; + case IDCANCEL: + DestroyIconList(pIconContext->hDlgCtrl); + EndDialog(hwndDlg, 0); + break; + case IDC_PICKICON_LIST: + if (HIWORD(wParam) == LBN_SELCHANGE) + InvalidateRect((HWND)lParam, NULL, TRUE); // FIXME USE UPDATE RECT + break; + case IDC_BUTTON_PATH: + szText[0] = 0; + szTitle[0] = 0; + szFilter[0] = 0; + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwndDlg; + ofn.lpstrFile = szText; + ofn.nMaxFile = MAX_PATH; + LoadStringW(shell32_hInstance, IDS_PICK_ICON_TITLE, szTitle, sizeof(szTitle) / sizeof(WCHAR)); + ofn.lpstrTitle = szTitle; + LoadStringW(shell32_hInstance, IDS_PICK_ICON_FILTER, szFilter, sizeof(szFilter) / sizeof(WCHAR)); + ofn.lpstrFilter = szFilter; + if (GetOpenFileNameW(&ofn)) + { + HMODULE hLibrary; + + if (!wcsicmp(pIconContext->szName, szText)) + break; + + DestroyIconList(pIconContext->hDlgCtrl); + + hLibrary = LoadLibraryExW(szText, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + if (hLibrary == NULL) + break; + FreeLibrary(pIconContext->hLibrary); + pIconContext->hLibrary = hLibrary; + wcscpy(pIconContext->szName, szText); + EnumResourceNamesW(pIconContext->hLibrary, RT_ICON, EnumPickIconResourceProc, (LPARAM)pIconContext); + if (PathUnExpandEnvStringsW(pIconContext->szName, szText, MAX_PATH)) + SendDlgItemMessageW(hwndDlg, IDC_EDIT_PATH, WM_SETTEXT, 0, (LPARAM)szText); + else + SendDlgItemMessageW(hwndDlg, IDC_EDIT_PATH, WM_SETTEXT, 0, (LPARAM)pIconContext->szName); + + SendMessageW(pIconContext->hDlgCtrl, LB_SETCURSEL, 0, 0); + } + break; + } + break; + case WM_MEASUREITEM: + lpmis = (LPMEASUREITEMSTRUCT) lParam; + lpmis->itemHeight = 32; + lpmis->itemWidth = 64; + return TRUE; + case WM_DRAWITEM: + lpdis = (LPDRAWITEMSTRUCT) lParam; + if (lpdis->itemID == (UINT)-1) + { + break; + } + switch (lpdis->itemAction) + { + case ODA_SELECT: + case ODA_DRAWENTIRE: + index = SendMessageW(pIconContext->hDlgCtrl, LB_GETCURSEL, 0, 0); + hIcon =(HICON)SendMessage(lpdis->hwndItem, LB_GETITEMDATA, lpdis->itemID, (LPARAM) 0); + + if (lpdis->itemID == (UINT)index) + { + HBRUSH hBrush; + hBrush = CreateSolidBrush(RGB(0, 0, 255)); + FillRect(lpdis->hDC, &lpdis->rcItem, hBrush); + DeleteObject(hBrush); + } + else + { + HBRUSH hBrush; + hBrush = CreateSolidBrush(RGB(255, 255, 255)); + FillRect(lpdis->hDC, &lpdis->rcItem, hBrush); + DeleteObject(hBrush); + } + DrawIconEx(lpdis->hDC, lpdis->rcItem.left,lpdis->rcItem.top, hIcon, + 0, + 0, + 0, + NULL, + DI_NORMAL); + break; + } + break; + } + + return FALSE; +} + +BOOL WINAPI PickIconDlg( + HWND hwndOwner, + LPWSTR lpstrFile, + UINT nMaxFile, + INT* lpdwIconIndex) +{ + HMODULE hLibrary; + int res; + PICK_ICON_CONTEXT IconContext; + + hLibrary = LoadLibraryExW(lpstrFile, NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE); + IconContext.hLibrary = hLibrary; + IconContext.Index = *lpdwIconIndex; + wcscpy(IconContext.szName, lpstrFile); + + res = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(IDD_PICK_ICON_DIALOG), hwndOwner, PickIconProc, (LPARAM)&IconContext); + if (res) + { + wcscpy(lpstrFile, IconContext.szName); + *lpdwIconIndex = IconContext.Index; + } + + FreeLibrary(hLibrary); + return res; +} + +/************************************************************************* + * RunFileDlg [internal] + * + * The Unicode function that is available as ordinal 61 on Windows NT/2000/XP/... + */ +void WINAPI RunFileDlg( + HWND hwndOwner, + HICON hIcon, + LPCWSTR lpstrDirectory, + LPCWSTR lpstrTitle, + LPCWSTR lpstrDescription, + UINT uFlags) +{ + static const WCHAR resnameW[] = {'S','H','E','L','L','_','R','U','N','_','D','L','G',0}; + RUNFILEDLGPARAMS rfdp; + HRSRC hRes; + LPVOID tmplate; + TRACE("\n"); + + rfdp.hwndOwner = hwndOwner; + rfdp.hIcon = hIcon; + rfdp.lpstrDirectory = lpstrDirectory; + rfdp.lpstrTitle = lpstrTitle; + rfdp.lpstrDescription = lpstrDescription; + rfdp.uFlags = uFlags; + + if (!(hRes = FindResourceW(shell32_hInstance, resnameW, (LPWSTR)RT_DIALOG)) || + !(tmplate = LoadResource(shell32_hInstance, hRes))) + { + ERR("Couldn't load SHELL_RUN_DLG resource\n"); + ShellMessageBoxW(shell32_hInstance, hwndOwner, MAKEINTRESOURCEW(IDS_RUNDLG_ERROR), NULL, MB_OK | MB_ICONERROR); + return; + } + + DialogBoxIndirectParamW(shell32_hInstance, + (LPCDLGTEMPLATEW)tmplate, hwndOwner, RunDlgProc, (LPARAM)&rfdp); + +} + + +/* find the directory that contains the file being run */ +static LPWSTR RunDlg_GetParentDir(LPCWSTR cmdline) +{ + const WCHAR *src; + WCHAR *dest, *result, *result_end=NULL; + static const WCHAR dotexeW[] = {'.','e','x','e',0}; + + result = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(strlenW(cmdline)+5)); + + if (NULL == result) + { + TRACE("HeapAlloc couldn't allocate %d bytes\n", sizeof(WCHAR)*(strlenW(cmdline)+5)); + return NULL; + } + + src = cmdline; + dest = result; + + if (*src == '"') + { + src++; + while (*src && *src != '"') + { + if (*src == '\\') + result_end = dest; + *dest++ = *src++; + } + } + else { + while (*src) + { + if (isspaceW(*src)) + { + *dest = 0; + if (INVALID_FILE_ATTRIBUTES != GetFileAttributesW(result)) + break; + strcatW(dest, dotexeW); + if (INVALID_FILE_ATTRIBUTES != GetFileAttributesW(result)) + break; + } + else if (*src == '\\') + result_end = dest; + *dest++ = *src++; + } + } + + if (result_end) + { + *result_end = 0; + return result; + } + else + { + HeapFree(GetProcessHeap(), 0, result); + return NULL; + } +} + + +/* Dialog procedure for RunFileDlg */ +static INT_PTR CALLBACK RunDlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) + { + RUNFILEDLGPARAMS *prfdp = (RUNFILEDLGPARAMS *)GetWindowLongPtrW(hwnd, DWLP_USER); + + switch (message) + { + case WM_INITDIALOG : + prfdp = (RUNFILEDLGPARAMS *)lParam ; + SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR)prfdp); + + if (prfdp->lpstrTitle) + SetWindowTextW(hwnd, prfdp->lpstrTitle); + if (prfdp->lpstrDescription) + SetWindowTextW(GetDlgItem(hwnd, IDC_RUNDLG_DESCRIPTION), prfdp->lpstrDescription); + if (prfdp->uFlags & RFF_NOBROWSE) + { + HWND browse = GetDlgItem(hwnd, IDC_RUNDLG_BROWSE); + ShowWindow(browse, SW_HIDE); + EnableWindow(browse, FALSE); + } + if (prfdp->uFlags & RFF_NOLABEL) + ShowWindow(GetDlgItem(hwnd, IDC_RUNDLG_LABEL), SW_HIDE); + if (prfdp->uFlags & RFF_CALCDIRECTORY) + FIXME("RFF_CALCDIRECTORY not supported\n"); + + if (prfdp->hIcon == NULL) + prfdp->hIcon = LoadIconW(NULL, (LPCWSTR)IDI_WINLOGO); + SendMessageW(hwnd, WM_SETICON, ICON_BIG, (LPARAM)prfdp->hIcon); + SendMessageW(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)prfdp->hIcon); + SendMessageW(GetDlgItem(hwnd, IDC_RUNDLG_ICON), STM_SETICON, (WPARAM)prfdp->hIcon, 0); + + FillList (GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH), NULL, (prfdp->uFlags & RFF_NODEFAULT) == 0) ; + SetFocus (GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH)) ; + return TRUE ; + + case WM_COMMAND : + switch (LOWORD (wParam)) + { + case IDOK : + { + int ic ; + HWND htxt = GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH); + if ((ic = GetWindowTextLengthW (htxt))) + { + WCHAR *psz, *parent=NULL ; + SHELLEXECUTEINFOW sei ; + + ZeroMemory (&sei, sizeof(sei)) ; + sei.cbSize = sizeof(sei) ; + psz = (WCHAR *)HeapAlloc( GetProcessHeap(), 0, (ic + 1)*sizeof(WCHAR) ); + + if (psz) + { + GetWindowTextW (htxt, psz, ic + 1) ; + + /* according to http://www.codeproject.com/KB/shell/runfiledlg.aspx we should send a + * WM_NOTIFY before execution */ + + sei.hwnd = hwnd; + sei.nShow = SW_SHOWNORMAL; + sei.lpFile = psz; + + if (prfdp->lpstrDirectory) + sei.lpDirectory = prfdp->lpstrDirectory; + else + sei.lpDirectory = parent = RunDlg_GetParentDir(sei.lpFile); + + if (!ShellExecuteExW( &sei )) + { + HeapFree(GetProcessHeap(), 0, psz); + HeapFree(GetProcessHeap(), 0, parent); + SendMessageA (htxt, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ; + return TRUE ; + } + + /* FillList is still ANSI */ + GetWindowTextA (htxt, (LPSTR)psz, ic + 1) ; + FillList (htxt, (LPSTR)psz, FALSE) ; + + HeapFree(GetProcessHeap(), 0, psz); + HeapFree(GetProcessHeap(), 0, parent); + EndDialog (hwnd, 0); + } + } + } + + case IDCANCEL : + EndDialog (hwnd, 0) ; + return TRUE ; + + case IDC_RUNDLG_BROWSE : + { + HMODULE hComdlg = NULL ; + LPFNOFN ofnProc = NULL ; + static const WCHAR comdlg32W[] = {'c','o','m','d','l','g','3','2',0}; + WCHAR szFName[1024] = {0}; + WCHAR filter[MAX_PATH], szCaption[MAX_PATH]; + OPENFILENAMEW ofn; + + LoadStringW(shell32_hInstance, IDS_RUNDLG_BROWSE_FILTER, filter, MAX_PATH); + LoadStringW(shell32_hInstance, IDS_RUNDLG_BROWSE_CAPTION, szCaption, MAX_PATH); + + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = filter; + ofn.lpstrFile = szFName; + ofn.nMaxFile = 1023; + ofn.lpstrTitle = szCaption; + ofn.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST; + ofn.lpstrInitialDir = prfdp->lpstrDirectory; + + if (NULL == (hComdlg = LoadLibraryExW (comdlg32W, NULL, 0)) || + NULL == (ofnProc = (LPFNOFN)GetProcAddress (hComdlg, "GetOpenFileNameW"))) + { + ERR("Couldn't get GetOpenFileName function entry (lib=%p, proc=%p)\n", hComdlg, ofnProc); + ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(IDS_RUNDLG_BROWSE_ERROR), NULL, MB_OK | MB_ICONERROR); + return TRUE ; + } + + if (ofnProc(&ofn)) + { + SetFocus (GetDlgItem (hwnd, IDOK)) ; + SetWindowTextW (GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH), szFName) ; + SendMessageW (GetDlgItem (hwnd, IDC_RUNDLG_EDITPATH), CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ; + SetFocus (GetDlgItem (hwnd, IDOK)) ; + } + + FreeLibrary (hComdlg) ; + + return TRUE ; + } + } + return TRUE ; + } + return FALSE ; + } + +/* This grabs the MRU list from the registry and fills the combo for the "Run" dialog above */ +/* fShowDefault ignored if pszLatest != NULL */ +static void FillList (HWND hCb, char *pszLatest, BOOL fShowDefault) +{ + HKEY hkey ; +/* char szDbgMsg[256] = "" ; */ + char *pszList = NULL, *pszCmd = NULL, cMatch = 0, cMax = 0x60, szIndex[2] = "-" ; + DWORD icList = 0, icCmd = 0 ; + UINT Nix ; + + SendMessageA (hCb, CB_RESETCONTENT, 0, 0) ; + + if (ERROR_SUCCESS != RegCreateKeyExA ( + HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU", + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL)) + MessageBoxA (hCb, "Unable to open registry key !", "Nix", MB_OK) ; + + RegQueryValueExA (hkey, "MRUList", NULL, NULL, NULL, &icList) ; + + if (icList > 0) + { + pszList = (char *)HeapAlloc( GetProcessHeap(), 0, icList) ; + + if (pszList) + { + if (ERROR_SUCCESS != RegQueryValueExA (hkey, "MRUList", NULL, NULL, (LPBYTE)pszList, &icList)) + MessageBoxA (hCb, "Unable to grab MRUList !", "Nix", MB_OK); + } + else + { + TRACE("HeapAlloc failed to allocate %d bytes\n", icList); + } + } + else + { + icList = 1 ; + pszList = (char *)HeapAlloc( GetProcessHeap(), 0, icList) ; + pszList[0] = 0 ; + } + + for (Nix = 0 ; Nix < icList - 1 ; Nix++) + { + if (pszList[Nix] > cMax) + cMax = pszList[Nix] ; + + szIndex[0] = pszList[Nix] ; + + if (ERROR_SUCCESS != RegQueryValueExA (hkey, szIndex, NULL, NULL, NULL, &icCmd)) + MessageBoxA (hCb, "Unable to grab size of index", "Nix", MB_OK) ; + if( pszCmd ) + pszCmd = (char *)HeapReAlloc(GetProcessHeap(), 0, pszCmd, icCmd) ; + else + pszCmd = (char *)HeapAlloc(GetProcessHeap(), 0, icCmd) ; + if (ERROR_SUCCESS != RegQueryValueExA (hkey, szIndex, NULL, NULL, (LPBYTE)pszCmd, &icCmd)) + MessageBoxA (hCb, "Unable to grab index", "Nix", MB_OK) ; + + if (NULL != pszLatest) + { + if (!lstrcmpiA(pszCmd, pszLatest)) + { + /* + sprintf (szDbgMsg, "Found existing (%d).\n", Nix) ; + MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ; + */ + SendMessageA (hCb, CB_INSERTSTRING, 0, (LPARAM)pszCmd) ; + SetWindowTextA (hCb, pszCmd) ; + SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ; + + cMatch = pszList[Nix] ; + memmove (&pszList[1], pszList, Nix) ; + pszList[0] = cMatch ; + continue ; + } + } + + if (26 != icList - 1 || icList - 2 != Nix || cMatch || NULL == pszLatest) + { + /* + sprintf (szDbgMsg, "Happily appending (%d).\n", Nix) ; + MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ; + */ + SendMessageA (hCb, CB_ADDSTRING, 0, (LPARAM)pszCmd) ; + if (!Nix && fShowDefault) + { + SetWindowTextA (hCb, pszCmd) ; + SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ; + } + } + else + { + /* + sprintf (szDbgMsg, "Doing loop thing.\n") ; + MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ; + */ + SendMessageA (hCb, CB_INSERTSTRING, 0, (LPARAM)pszLatest) ; + SetWindowTextA (hCb, pszLatest) ; + SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ; + + cMatch = pszList[Nix] ; + memmove (&pszList[1], pszList, Nix) ; + pszList[0] = cMatch ; + szIndex[0] = cMatch ; + RegSetValueExA (hkey, szIndex, 0, REG_SZ, (LPBYTE)pszLatest, strlen (pszLatest) + 1) ; + } + } + + if (!cMatch && NULL != pszLatest) + { + /* + sprintf (szDbgMsg, "Simply inserting (increasing list).\n") ; + MessageBoxA (hCb, szDbgMsg, "Nix", MB_OK) ; + */ + SendMessageA (hCb, CB_INSERTSTRING, 0, (LPARAM)pszLatest) ; + SetWindowTextA (hCb, pszLatest) ; + SendMessageA (hCb, CB_SETEDITSEL, 0, MAKELPARAM (0, -1)) ; + + cMatch = ++cMax ; + if (pszList) + pszList = (char *)HeapReAlloc(GetProcessHeap(), 0, pszList, ++icList) ; + else + pszList = (char *)HeapAlloc(GetProcessHeap(), 0, ++icList) ; + + if (pszList) + { + memmove (&pszList[1], pszList, icList - 1) ; + pszList[0] = cMatch ; + szIndex[0] = cMatch ; + RegSetValueExA (hkey, szIndex, 0, REG_SZ, (LPBYTE)pszLatest, strlen (pszLatest) + 1) ; + } + else + { + TRACE("HeapAlloc or HeapReAlloc failed to allocate enough bytes\n"); + } + } + + RegSetValueExA (hkey, "MRUList", 0, REG_SZ, (LPBYTE)pszList, strlen (pszList) + 1) ; + + HeapFree( GetProcessHeap(), 0, pszCmd) ; + HeapFree( GetProcessHeap(), 0, pszList) ; +} + + +/************************************************************************* + * ConfirmDialog [internal] + * + * Put up a confirm box, return TRUE if the user confirmed + */ +static BOOL ConfirmDialog(HWND hWndOwner, UINT PromptId, UINT TitleId) +{ + WCHAR Prompt[256]; + WCHAR Title[256]; + + LoadStringW(shell32_hInstance, PromptId, Prompt, sizeof(Prompt) / sizeof(WCHAR)); + LoadStringW(shell32_hInstance, TitleId, Title, sizeof(Title) / sizeof(WCHAR)); + return MessageBoxW(hWndOwner, Prompt, Title, MB_YESNO|MB_ICONQUESTION) == IDYES; +} + + +/************************************************************************* + * RestartDialogEx [SHELL32.730] + */ + +int WINAPI RestartDialogEx(HWND hWndOwner, LPCWSTR lpwstrReason, DWORD uFlags, DWORD uReason) +{ + TRACE("(%p)\n", hWndOwner); + + /* FIXME: use lpwstrReason */ + if (ConfirmDialog(hWndOwner, IDS_RESTART_PROMPT, IDS_RESTART_TITLE)) + { + HANDLE hToken; + TOKEN_PRIVILEGES npr; + + /* enable the shutdown privilege for the current process */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + LookupPrivilegeValueA(0, "SeShutdownPrivilege", &npr.Privileges[0].Luid); + npr.PrivilegeCount = 1; + npr.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(hToken, FALSE, &npr, 0, 0, 0); + CloseHandle(hToken); + } + ExitWindowsEx(EWX_REBOOT, uReason); + } + + return 0; +} + + +/************************************************************************* + * LogoffWindowsDialog [SHELL32.54] + */ + +EXTERN_C int WINAPI LogoffWindowsDialog(HWND hWndOwner) +{ + if (ConfirmDialog(hWndOwner, IDS_LOGOFF_PROMPT, IDS_LOGOFF_TITLE)) + { + ExitWindowsEx(EWX_LOGOFF, 0); + } + return 0;} + + +/************************************************************************* + * RestartDialog [SHELL32.59] + */ + +int WINAPI RestartDialog(HWND hWndOwner, LPCWSTR lpstrReason, DWORD uFlags) +{ + return RestartDialogEx(hWndOwner, lpstrReason, uFlags, 0); +} + + +/************************************************************************* + * ExitWindowsDialog [SHELL32.60] + * + * NOTES + * exported by ordinal + */ +void WINAPI ExitWindowsDialog (HWND hWndOwner) +{ + TRACE("(%p)\n", hWndOwner); + + if (ConfirmDialog(hWndOwner, IDS_SHUTDOWN_PROMPT, IDS_SHUTDOWN_TITLE)) + { + HANDLE hToken; + TOKEN_PRIVILEGES npr; + + /* enable shutdown privilege for current process */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + { + LookupPrivilegeValueA(0, "SeShutdownPrivilege", &npr.Privileges[0].Luid); + npr.PrivilegeCount = 1; + npr.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + AdjustTokenPrivileges(hToken, FALSE, &npr, 0, 0, 0); + CloseHandle(hToken); + } + ExitWindowsEx(EWX_SHUTDOWN, 0); + } +} diff --git a/reactos/dll/win32/shell32/dragdrophelper.cpp b/reactos/dll/win32/shell32/dragdrophelper.cpp new file mode 100644 index 00000000000..bb554416ad3 --- /dev/null +++ b/reactos/dll/win32/shell32/dragdrophelper.cpp @@ -0,0 +1,67 @@ +/* + * file system 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 + +WINE_DEFAULT_DEBUG_CHANNEL (shell); + +/*********************************************************************** +* IDropTargetHelper implementation +*/ + +IDropTargetHelperImpl::IDropTargetHelperImpl() +{ +} + +IDropTargetHelperImpl::~IDropTargetHelperImpl() +{ +} + +HRESULT WINAPI IDropTargetHelperImpl::DragEnter (HWND hwndTarget, IDataObject* pDataObject, POINT* ppt, DWORD dwEffect) +{ + FIXME ("(%p)->(%p %p %p 0x%08x)\n", this, hwndTarget, pDataObject, ppt, dwEffect); + return E_NOTIMPL; +} + +HRESULT WINAPI IDropTargetHelperImpl::DragLeave() +{ + FIXME ("(%p)->()\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI IDropTargetHelperImpl::DragOver(POINT *ppt, DWORD dwEffect) +{ + FIXME ("(%p)->(%p 0x%08x)\n", this, ppt, dwEffect); + return E_NOTIMPL; +} + +HRESULT WINAPI IDropTargetHelperImpl::Drop(IDataObject* pDataObject, POINT* ppt, DWORD dwEffect) +{ + FIXME ("(%p)->(%p %p 0x%08x)\n", this, pDataObject, ppt, dwEffect); + return E_NOTIMPL; +} + +HRESULT WINAPI IDropTargetHelperImpl::Show(BOOL fShow) +{ + FIXME ("(%p)->(%u)\n", this, fShow); + return E_NOTIMPL; +} diff --git a/reactos/dll/win32/shell32/dragdrophelper.h b/reactos/dll/win32/shell32/dragdrophelper.h new file mode 100644 index 00000000000..c850bf69d14 --- /dev/null +++ b/reactos/dll/win32/shell32/dragdrophelper.h @@ -0,0 +1,53 @@ +/* + * file system 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 + */ + +#ifndef _DRAGDROPHELPER_H_ +#define _DRAGDROPHELPER_H_ + +class IDropTargetHelperImpl : + public CComCoClass, + public CComObjectRootEx, + public IDropTargetHelper +{ +private: +public: + IDropTargetHelperImpl(); + ~IDropTargetHelperImpl(); + + //////// + virtual HRESULT WINAPI DragEnter (HWND hwndTarget, IDataObject* pDataObject, POINT* ppt, DWORD dwEffect); + virtual HRESULT WINAPI DragLeave(); + virtual HRESULT WINAPI DragOver(POINT *ppt, DWORD dwEffect); + virtual HRESULT WINAPI Drop(IDataObject* pDataObject, POINT* ppt, DWORD dwEffect); + virtual HRESULT WINAPI Show(BOOL fShow); + +DECLARE_REGISTRY_RESOURCEID(IDR_DRAGDROPHELPER) +DECLARE_NOT_AGGREGATABLE(IDropTargetHelperImpl) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(IDropTargetHelperImpl) + COM_INTERFACE_ENTRY_IID(IID_IDropTargetHelper, IDropTargetHelper) +END_COM_MAP() +}; + +#endif // _DRAGDROPHELPER_H_ diff --git a/reactos/dll/win32/shell32/drive.cpp b/reactos/dll/win32/shell32/drive.cpp new file mode 100644 index 00000000000..3863c4b2923 --- /dev/null +++ b/reactos/dll/win32/shell32/drive.cpp @@ -0,0 +1,1288 @@ +/* + * Shell Library Functions + * + * Copyright 2005 Johannes Anderwald + * + * 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 + */ + +#include + +#define MAX_PROPERTY_SHEET_PAGE 32 + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +typedef enum +{ + HWPD_STANDARDLIST = 0, + HWPD_LARGELIST, + HWPD_MAX = HWPD_LARGELIST +} HWPAGE_DISPLAYMODE, *PHWPAGE_DISPLAYMODE; + +typedef +BOOLEAN +(NTAPI *INITIALIZE_FMIFS)( + IN PVOID hinstDll, + IN DWORD dwReason, + IN PVOID reserved +); +typedef +BOOLEAN +(NTAPI *QUERY_AVAILABLEFSFORMAT)( + IN DWORD Index, + IN OUT PWCHAR FileSystem, + OUT UCHAR* Major, + OUT UCHAR* Minor, + OUT BOOLEAN* LastestVersion +); +typedef +BOOLEAN +(NTAPI *ENABLEVOLUMECOMPRESSION)( + IN PWCHAR DriveRoot, + IN USHORT Compression +); + +typedef +VOID +(NTAPI *FORMAT_EX)( + IN PWCHAR DriveRoot, + IN FMIFS_MEDIA_FLAG MediaFlag, + IN PWCHAR Format, + IN PWCHAR Label, + IN BOOLEAN QuickFormat, + IN ULONG ClusterSize, + IN PFMIFSCALLBACK Callback +); + +typedef +VOID +(NTAPI *CHKDSK)( + IN PWCHAR DriveRoot, + IN PWCHAR Format, + IN BOOLEAN CorrectErrors, + IN BOOLEAN Verbose, + IN BOOLEAN CheckOnlyIfDirty, + IN BOOLEAN ScanDrive, + IN PVOID Unused2, + IN PVOID Unused3, + IN PFMIFSCALLBACK Callback +); + + +typedef struct +{ + WCHAR Drive; + UINT Options; + HMODULE hLibrary; + QUERY_AVAILABLEFSFORMAT QueryAvailableFileSystemFormat; + FORMAT_EX FormatEx; + ENABLEVOLUMECOMPRESSION EnableVolumeCompression; + CHKDSK Chkdsk; + UINT Result; +}FORMAT_DRIVE_CONTEXT, *PFORMAT_DRIVE_CONTEXT; + +BOOL InitializeFmifsLibrary(PFORMAT_DRIVE_CONTEXT pContext); +BOOL GetDefaultClusterSize(LPWSTR szFs, PDWORD pClusterSize, PULARGE_INTEGER TotalNumberOfBytes); +EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj); +EXTERN_C HWND WINAPI +DeviceCreateHardwarePageEx(HWND hWndParent, + LPGUID lpGuids, + UINT uNumberOfGuids, + HWPAGE_DISPLAYMODE DisplayMode); + +HPROPSHEETPAGE SH_CreatePropertySheetPage(LPCSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle); + +#define DRIVE_PROPERTY_PAGES (3) + +static const GUID GUID_DEVCLASS_DISKDRIVE = {0x4d36e967L, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}; + + +VOID +GetDriveNameWithLetter(LPWSTR szText, UINT Length, WCHAR Drive) +{ + WCHAR szDrive[] = {'C',':','\\', 0}; + DWORD dwMaxComp, dwFileSys, TempLength = 0; + + szDrive[0] = Drive; + if (GetVolumeInformationW(szDrive, szText, Length, NULL, &dwMaxComp, &dwFileSys, NULL, 0)) + { + szText[Length-1] = L'\0'; + TempLength = wcslen(szText); + if (!TempLength) + { + /* load default volume label */ + TempLength = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2); + } + } + if (TempLength + 4 < Length) + { + szText[TempLength] = L' '; + szText[TempLength+1] = L'('; + szText[TempLength+2] = szDrive[0]; + szText[TempLength+3] = L')'; + TempLength +=4; + } + + if (TempLength < Length) + szText[TempLength] = L'\0'; + else + szText[Length-1] = L'\0'; +} + + +VOID +InitializeChkDskDialog(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext) +{ + WCHAR szText[100]; + UINT Length; + SetWindowLongPtr(hwndDlg, DWLP_USER, (INT_PTR)pContext); + + Length = GetWindowTextW(hwndDlg, szText, sizeof(szText)/sizeof(WCHAR)); + + GetDriveNameWithLetter(&szText[Length +1], (sizeof(szText)/sizeof(WCHAR))-Length-1, pContext->Drive); + szText[Length] = L' '; + szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0'; + SetWindowText(hwndDlg, szText); +} + +HWND ChkdskDrvDialog = NULL; +BOOLEAN bChkdskSuccess = FALSE; + +BOOLEAN +NTAPI +ChkdskCallback( + IN CALLBACKCOMMAND Command, + IN ULONG SubAction, + IN PVOID ActionInfo) +{ + PDWORD Progress; + PBOOLEAN pSuccess; + switch(Command) + { + case PROGRESS: + Progress = (PDWORD)ActionInfo; + SendDlgItemMessageW(ChkdskDrvDialog, 14002, PBM_SETPOS, (WPARAM)*Progress, 0); + break; + case DONE: + pSuccess = (PBOOLEAN)ActionInfo; + bChkdskSuccess = (*pSuccess); + break; + + case VOLUMEINUSE: + case INSUFFICIENTRIGHTS: + case FSNOTSUPPORTED: + case CLUSTERSIZETOOSMALL: + bChkdskSuccess = FALSE; + FIXME("\n"); + break; + + default: + break; + } + + return TRUE; +} + +VOID +ChkDskNow(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext) +{ + DWORD ClusterSize = 0, dwMaxComponentLength, FileSystemFlags; + WCHAR szFs[30]; + WCHAR szDrive[] = {'C',':','\\', 0}; + WCHAR szVolumeLabel[40]; + ULARGE_INTEGER TotalNumberOfFreeBytes, FreeBytesAvailableUser; + BOOLEAN bCorrectErrors = FALSE, bScanDrive = FALSE; + + szDrive[0] = pContext->Drive; + if(!GetVolumeInformationW(szDrive, szVolumeLabel, sizeof(szVolumeLabel)/sizeof(WCHAR), NULL, &dwMaxComponentLength, &FileSystemFlags, szFs, sizeof(szFs)/sizeof(WCHAR))) + { + FIXME("failed to get drive fs type\n"); + return; + } + + if (!GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfFreeBytes, NULL)) + { + FIXME("failed to get drive space type\n"); + return; + } + + if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfFreeBytes)) + { + FIXME("invalid cluster size\n"); + return; + } + + if (SendDlgItemMessageW(hwndDlg, 14000, BM_GETCHECK, 0, 0) == BST_CHECKED) + bCorrectErrors = TRUE; + + if (SendDlgItemMessageW(hwndDlg, 14001, BM_GETCHECK, 0, 0) == BST_CHECKED) + bScanDrive = TRUE; + + ChkdskDrvDialog = hwndDlg; + bChkdskSuccess = FALSE; + SendDlgItemMessageW(hwndDlg, 14002, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + pContext->Chkdsk(szDrive, szFs, bCorrectErrors, TRUE, FALSE, bScanDrive, NULL, NULL, ChkdskCallback); + + ChkdskDrvDialog = NULL; + pContext->Result = bChkdskSuccess; + bChkdskSuccess = FALSE; + +} + +INT_PTR +CALLBACK +ChkDskDlg( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + PFORMAT_DRIVE_CONTEXT pContext; + switch(uMsg) + { + case WM_INITDIALOG: + SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam); + InitializeChkDskDialog(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam); + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDCANCEL: + EndDialog(hwndDlg, 0); + break; + case IDOK: + pContext = (PFORMAT_DRIVE_CONTEXT) GetWindowLongPtr(hwndDlg, DWLP_USER); + ChkDskNow(hwndDlg, pContext); + break; + } + break; + } + + return FALSE; +} + + +static +ULONGLONG +GetFreeBytesShare(ULONGLONG TotalNumberOfFreeBytes, ULONGLONG TotalNumberOfBytes) +{ + ULONGLONG Temp; + + if (TotalNumberOfFreeBytes == 0LL) + { + return 0; + } + + Temp = TotalNumberOfBytes / 100; + if (Temp >= TotalNumberOfFreeBytes) + { + return 1; + } + else + { + return TotalNumberOfFreeBytes / Temp; + } +} + +static +void +PaintStaticControls(HWND hwndDlg, LPDRAWITEMSTRUCT drawItem) +{ + HBRUSH hBrush; + + if (drawItem->CtlID == 14013) + { + hBrush = CreateSolidBrush(RGB(0, 0, 255)); + if (hBrush) + { + FillRect(drawItem->hDC, &drawItem->rcItem, hBrush); + DeleteObject((HGDIOBJ)hBrush); + } + } + else if (drawItem->CtlID == 14014) + { + hBrush = CreateSolidBrush(RGB(255, 0, 255)); + if (hBrush) + { + FillRect(drawItem->hDC, &drawItem->rcItem, hBrush); + DeleteObject((HGDIOBJ)hBrush); + } + } + else if (drawItem->CtlID == 14015) + { + HBRUSH hBlueBrush; + HBRUSH hMagBrush; + RECT rect; + LONG horzsize; + LONGLONG Result; + WCHAR szBuffer[20]; + + hBlueBrush = CreateSolidBrush(RGB(0, 0, 255)); + hMagBrush = CreateSolidBrush(RGB(255, 0, 255)); + + SendDlgItemMessageW(hwndDlg, 14006, WM_GETTEXT, 20, (LPARAM)szBuffer); + Result = _wtoi(szBuffer); + + CopyRect(&rect, &drawItem->rcItem); + horzsize = rect.right - rect.left; + Result = (Result * horzsize) / 100; + + rect.right = drawItem->rcItem.right - Result; + FillRect(drawItem->hDC, &rect, hBlueBrush); + rect.left = rect.right; + rect.right = drawItem->rcItem.right; + FillRect(drawItem->hDC, &rect, hMagBrush); + DeleteObject(hBlueBrush); + DeleteObject(hMagBrush); + } +} + +static +void +InitializeGeneralDriveDialog(HWND hwndDlg, WCHAR * szDrive) +{ + WCHAR szVolumeName[MAX_PATH+1] = {0}; + DWORD MaxComponentLength = 0; + DWORD FileSystemFlags = 0; + WCHAR FileSystemName[MAX_PATH+1] = {0}; + WCHAR szFormat[50]; + WCHAR szBuffer[128]; + BOOL ret; + UINT DriveType; + ULARGE_INTEGER FreeBytesAvailable; + LARGE_INTEGER TotalNumberOfFreeBytes; + LARGE_INTEGER TotalNumberOfBytes; + + ret = GetVolumeInformationW(szDrive, szVolumeName, MAX_PATH+1, NULL, &MaxComponentLength, &FileSystemFlags, FileSystemName, MAX_PATH+1); + if (ret) + { + /* set volume label */ + SendDlgItemMessageW(hwndDlg, 14000, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szVolumeName); + + /* set filesystem type */ + SendDlgItemMessageW(hwndDlg, 14002, WM_SETTEXT, (WPARAM)NULL, (LPARAM)FileSystemName); + + } + + DriveType = GetDriveTypeW(szDrive); + if (DriveType == DRIVE_FIXED || DriveType == DRIVE_CDROM) + { + + if(GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable, (PULARGE_INTEGER)&TotalNumberOfBytes, (PULARGE_INTEGER)&TotalNumberOfFreeBytes)) + { + WCHAR szResult[128]; + LONGLONG Result; + HANDLE hVolume; + DWORD BytesReturned = 0; + + swprintf(szResult, L"\\\\.\\%c:", towupper(szDrive[0])); + hVolume = CreateFileW(szResult, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (hVolume != INVALID_HANDLE_VALUE) + { + ret = DeviceIoControl(hVolume, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, (LPVOID)&TotalNumberOfBytes, sizeof(ULARGE_INTEGER), &BytesReturned, NULL); + if (ret && StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR))) + SendDlgItemMessageW(hwndDlg, 14007, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult); + + CloseHandle(hVolume); + } + + TRACE("szResult %s hVOlume %p ret %d LengthInformation %ul Bytesreturned %d\n", debugstr_w(szResult), hVolume, ret, TotalNumberOfBytes.QuadPart, BytesReturned); + + if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart - FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR))) + SendDlgItemMessageW(hwndDlg, 14003, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult); + + if (StrFormatByteSizeW(FreeBytesAvailable.QuadPart, szResult, sizeof(szResult) / sizeof(WCHAR))) + SendDlgItemMessageW(hwndDlg, 14005, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szResult); + + Result = GetFreeBytesShare(TotalNumberOfFreeBytes.QuadPart, TotalNumberOfBytes.QuadPart); + /* set free bytes percentage */ + swprintf(szResult, L"%02d%%", Result); + SendDlgItemMessageW(hwndDlg, 14006, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult); + /* store used share amount */ + Result = 100 - Result; + swprintf(szResult, L"%02d%%", Result); + SendDlgItemMessageW(hwndDlg, 14004, WM_SETTEXT, (WPARAM)0, (LPARAM)szResult); + if (DriveType == DRIVE_FIXED) + { + if (LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) + SendDlgItemMessageW(hwndDlg, 14001, WM_SETTEXT, (WPARAM)0, (LPARAM)szBuffer); + } + else /* DriveType == DRIVE_CDROM) */ + { + if (LoadStringW(shell32_hInstance, IDS_DRIVE_CDROM, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) + SendDlgItemMessageW(hwndDlg, 14001, WM_SETTEXT, (WPARAM)0, (LPARAM)szBuffer); + } + } + } + /* set drive description */ + SendDlgItemMessageW(hwndDlg, 14009, WM_GETTEXT, (WPARAM)50, (LPARAM)szFormat); + swprintf(szBuffer, szFormat, szDrive); + SendDlgItemMessageW(hwndDlg, 14009, WM_SETTEXT, (WPARAM)NULL, (LPARAM)szBuffer); +} + + +INT_PTR +CALLBACK +DriveGeneralDlg( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + LPPROPSHEETPAGEW ppsp; + LPDRAWITEMSTRUCT drawItem; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + WCHAR * lpstr; + WCHAR szPath[MAX_PATH]; + UINT length; + LPPSHNOTIFY lppsn; + + switch(uMsg) + { + case WM_INITDIALOG: + ppsp = (LPPROPSHEETPAGEW)lParam; + if (ppsp == NULL) + break; + lpstr = (WCHAR *)ppsp->lParam; + SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lpstr); + InitializeGeneralDriveDialog(hwndDlg, lpstr); + return TRUE; + case WM_DRAWITEM: + drawItem = (LPDRAWITEMSTRUCT)lParam; + if (drawItem->CtlID >= 14013 && drawItem->CtlID <= 14015) + { + PaintStaticControls(hwndDlg, drawItem); + return TRUE; + } + break; + case WM_COMMAND: + if (LOWORD(wParam) == 14010) /* Disk Cleanup */ + { + lpstr = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER); + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + if (!GetSystemDirectoryW(szPath, MAX_PATH)) + break; + wcscat(szPath, L"\\cleanmgr.exe /D "); + length = wcslen(szPath); + szPath[length] = lpstr[0]; + szPath[length+1] = L'\0'; + if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + break; + } + case WM_NOTIFY: + lppsn = (LPPSHNOTIFY) lParam; + if (LOWORD(wParam) == 14000) + { + if (HIWORD(wParam) == EN_CHANGE) + { + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + } + break; + } + if (lppsn->hdr.code == PSN_APPLY) + { + lpstr = (LPWSTR)GetWindowLongPtr(hwndDlg, DWLP_USER); + if (lpstr && SendDlgItemMessageW(hwndDlg, 14000, WM_GETTEXT, sizeof(szPath)/sizeof(WCHAR), (LPARAM)szPath)) + { + szPath[(sizeof(szPath)/sizeof(WCHAR))-1] = L'\0'; + SetVolumeLabelW(lpstr, szPath); + } + SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR ); + return TRUE; + } + break; + + default: + break; + } + + + return FALSE; +} + +INT_PTR +CALLBACK +DriveExtraDlg( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + STARTUPINFOW si; + PROCESS_INFORMATION pi; + WCHAR szPath[MAX_PATH + 10]; + WCHAR szArg[MAX_PATH]; + WCHAR * szDrive; + LPPROPSHEETPAGEW ppsp; + DWORD dwSize; + FORMAT_DRIVE_CONTEXT Context; + + switch (uMsg) + { + case WM_INITDIALOG: + ppsp = (LPPROPSHEETPAGEW)lParam; + SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ppsp->lParam); + return TRUE; + case WM_COMMAND: + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + ZeroMemory( &pi, sizeof(pi) ); + + szDrive = (WCHAR*)GetWindowLongPtr(hwndDlg, DWLP_USER); + switch(LOWORD(wParam)) + { + case 14000: + if (InitializeFmifsLibrary(&Context)) + { + Context.Drive = szDrive[0]; + DialogBoxParamW(shell32_hInstance, L"CHKDSK_DLG", hwndDlg, ChkDskDlg, (LPARAM)&Context); + FreeLibrary(Context.hLibrary); + } + break; + case 14001: + dwSize = sizeof(szPath); + if (RegGetValueW(HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\DefragPath", + NULL, + RRF_RT_REG_EXPAND_SZ, + NULL, + (PVOID)szPath, + &dwSize) == S_OK) + { + swprintf(szArg, szPath, szDrive[0]); + if (!GetSystemDirectoryW(szPath, MAX_PATH)) + break; + szDrive = PathAddBackslashW(szPath); + if (!szDrive) + break; + + wcscat(szDrive, L"mmc.exe"); + if (CreateProcessW(szPath, szArg, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + } + break; + case 14002: + dwSize = sizeof(szPath); + if (RegGetValueW(HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\BackupPath", + NULL, + RRF_RT_REG_EXPAND_SZ, + NULL, + (PVOID)szPath, + &dwSize) == S_OK) + { + if (CreateProcessW(szPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + } + } + break; + } + return FALSE; +} + +INT_PTR +CALLBACK +DriveHardwareDlg( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + GUID Guids[1]; + Guids[0] = GUID_DEVCLASS_DISKDRIVE; + + UNREFERENCED_PARAMETER(lParam); + UNREFERENCED_PARAMETER(wParam); + + switch(uMsg) + { + case WM_INITDIALOG: + /* create the hardware page */ + DeviceCreateHardwarePageEx(hwndDlg, + Guids, + sizeof(Guids) / sizeof(Guids[0]), + HWPD_STANDARDLIST); + break; + } + + return FALSE; +} + +static +const +struct +{ + LPCSTR resname; + DLGPROC dlgproc; + UINT DriveType; +} PropPages[] = +{ + { "DRIVE_GENERAL_DLG", DriveGeneralDlg, -1}, + { "DRIVE_EXTRA_DLG", DriveExtraDlg, DRIVE_FIXED}, + { "DRIVE_HARDWARE_DLG", DriveHardwareDlg, -1}, +}; + +HRESULT +CALLBACK +AddPropSheetPageProc(HPROPSHEETPAGE hpage, LPARAM lParam) +{ + PROPSHEETHEADER *ppsh = (PROPSHEETHEADER *)lParam; + if (ppsh != NULL && ppsh->nPages < MAX_PROPERTY_SHEET_PAGE) + { + ppsh->phpage[ppsh->nPages++] = hpage; + return TRUE; + } + return FALSE; +} + +BOOL +SH_ShowDriveProperties(WCHAR * drive, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST * apidl) +{ + HPSXA hpsx = NULL; + HPROPSHEETPAGE hpsp[MAX_PROPERTY_SHEET_PAGE]; + PROPSHEETHEADERW psh; + BOOL ret; + UINT i; + WCHAR szName[MAX_PATH+6]; + DWORD dwMaxComponent, dwFileSysFlags; + CComPtr pDataObj; + UINT DriveType; + + ZeroMemory(&psh, sizeof(PROPSHEETHEADERW)); + psh.dwSize = sizeof(PROPSHEETHEADERW); + //psh.dwFlags = PSH_USECALLBACK | PSH_PROPTITLE; + psh.hwndParent = NULL; + psh.nStartPage = 0; + psh.phpage = hpsp; + + if (GetVolumeInformationW(drive, szName, sizeof(szName)/sizeof(WCHAR), NULL, &dwMaxComponent, + &dwFileSysFlags, NULL, 0)) + { + psh.pszCaption = szName; + psh.dwFlags |= PSH_PROPTITLE; + if (!wcslen(szName)) + { + /* FIXME + * check if disk is a really a local hdd + */ + i = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, szName, sizeof(szName)/sizeof(WCHAR)-6); + if (i > 0 && i < (sizeof(szName)/sizeof(WCHAR)) - 6) + { + szName[i] = L' '; + szName[i+1] = L'('; + wcscpy(&szName[i+2], drive); + szName[i+4] = L')'; + szName[i+5] = L'\0'; + } + } + } + + DriveType = GetDriveTypeW(drive); + for (i = 0; i < DRIVE_PROPERTY_PAGES; i++) + { + if (PropPages[i].DriveType == (UINT)-1 || (PropPages[i].DriveType != (UINT)-1 && PropPages[i].DriveType == DriveType)) + { + HPROPSHEETPAGE hprop = SH_CreatePropertySheetPage(PropPages[i].resname, PropPages[i].dlgproc, (LPARAM)drive, NULL); + if (hprop) + { + hpsp[psh.nPages] = hprop; + psh.nPages++; + } + } + } + + if (SHCreateDataObject(pidlFolder, 1, apidl, NULL, IID_IDataObject, (void **)&pDataObj) == S_OK) + { + hpsx = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, L"Drive", MAX_PROPERTY_SHEET_PAGE-DRIVE_PROPERTY_PAGES, pDataObj); + if (hpsx) + { + SHAddFromPropSheetExtArray(hpsx, (LPFNADDPROPSHEETPAGE)AddPropSheetPageProc, (LPARAM)&psh); + } + } + + ret = PropertySheetW(&psh); + + if (hpsx) + SHDestroyPropSheetExtArray(hpsx); + + if (ret < 0) + return FALSE; + else + return TRUE; +} + +BOOL +GetDefaultClusterSize(LPWSTR szFs, PDWORD pClusterSize, PULARGE_INTEGER TotalNumberOfBytes) +{ + DWORD ClusterSize; + + if (!wcsicmp(szFs, L"FAT16") || + !wcsicmp(szFs, L"FAT")) //REACTOS HACK + { + if (TotalNumberOfBytes->QuadPart <= (16 * 1024 * 1024)) + ClusterSize = 2048; + else if (TotalNumberOfBytes->QuadPart <= (32 * 1024 * 1024)) + ClusterSize = 512; + else if (TotalNumberOfBytes->QuadPart <= (64 * 1024 * 1024)) + ClusterSize = 1024; + else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024)) + ClusterSize = 2048; + else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024)) + ClusterSize = 4096; + else if (TotalNumberOfBytes->QuadPart <= (512 * 1024 * 1024)) + ClusterSize = 8192; + else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024)) + ClusterSize = 16384; + else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL)) + ClusterSize = 32768; + else if (TotalNumberOfBytes->QuadPart <= (4096LL * 1024LL * 1024LL)) + ClusterSize = 8192; + else + return FALSE; + } + else if (!wcsicmp(szFs, L"FAT32")) + { + if (TotalNumberOfBytes->QuadPart <=(64 * 1024 * 1024)) + ClusterSize = 512; + else if (TotalNumberOfBytes->QuadPart <= (128 * 1024 * 1024)) + ClusterSize = 1024; + else if (TotalNumberOfBytes->QuadPart <= (256 * 1024 * 1024)) + ClusterSize = 2048; + else if (TotalNumberOfBytes->QuadPart <= (8192LL * 1024LL * 1024LL)) + ClusterSize = 2048; + else if (TotalNumberOfBytes->QuadPart <= (16384LL * 1024LL * 1024LL)) + ClusterSize = 8192; + else if (TotalNumberOfBytes->QuadPart <= (32768LL * 1024LL * 1024LL)) + ClusterSize = 16384; + else + return FALSE; + } + else if (!wcsicmp(szFs, L"NTFS")) + { + if (TotalNumberOfBytes->QuadPart <=(512 * 1024 * 1024)) + ClusterSize = 512; + else if (TotalNumberOfBytes->QuadPart <= (1024 * 1024 * 1024)) + ClusterSize = 1024; + else if (TotalNumberOfBytes->QuadPart <= (2048LL * 1024LL * 1024LL)) + ClusterSize = 2048; + else + ClusterSize = 2048; + } + else + return FALSE; + + *pClusterSize = ClusterSize; + return TRUE; +} + + +VOID +InsertDefaultClusterSizeForFs(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext) +{ + WCHAR szFs[100] = {0}; + WCHAR szDrive[4] = { L'C', ':', '\\', 0 }; + INT iSelIndex; + ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes; + DWORD ClusterSize; + LRESULT lIndex; + HWND hDlgCtrl; + + hDlgCtrl = GetDlgItem(hwndDlg, 28677); + iSelIndex = SendMessage(hDlgCtrl, CB_GETCURSEL, 0, 0); + if (iSelIndex == CB_ERR) + return; + + if (SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFs) == CB_ERR) + return; + + szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0'; + szDrive[0] = pContext->Drive + 'A'; + + if (!GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL)) + return; + + if (!wcsicmp(szFs, L"FAT16") || + !wcsicmp(szFs, L"FAT")) //REACTOS HACK + { + if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfBytes)) + { + TRACE("FAT16 is not supported on hdd larger than 4G current %lu\n", TotalNumberOfBytes.QuadPart); + SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0); + return; + } + + if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR))) + { + hDlgCtrl = GetDlgItem(hwndDlg, 28680); + szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0'; + SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0); + lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs); + if (lIndex != CB_ERR) + SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize); + SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0); + } + } + else if (!wcsicmp(szFs, L"FAT32")) + { + if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfBytes)) + { + TRACE("FAT32 is not supported on hdd larger than 32G current %lu\n", TotalNumberOfBytes.QuadPart); + SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0); + return; + } + + if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR))) + { + hDlgCtrl = GetDlgItem(hwndDlg, 28680); + szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0'; + SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0); + lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs); + if (lIndex != CB_ERR) + SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize); + SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0); + } + } + else if (!wcsicmp(szFs, L"NTFS")) + { + if (!GetDefaultClusterSize(szFs, &ClusterSize, &TotalNumberOfBytes)) + { + TRACE("NTFS is not supported on hdd larger than 2TB current %lu\n", TotalNumberOfBytes.QuadPart); + SendMessageW(hDlgCtrl, CB_DELETESTRING, iSelIndex, 0); + return; + } + + hDlgCtrl = GetDlgItem(hwndDlg, 28680); + if (LoadStringW(shell32_hInstance, IDS_DEFAULT_CLUSTER_SIZE, szFs, sizeof(szFs)/sizeof(WCHAR))) + { + szFs[(sizeof(szFs)/sizeof(WCHAR))-1] = L'\0'; + SendMessageW(hDlgCtrl, CB_RESETCONTENT, 0, 0); + lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs); + if (lIndex != CB_ERR) + SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize); + SendMessageW(hDlgCtrl, CB_SETCURSEL, 0, 0); + } + ClusterSize = 512; + for (lIndex = 0; lIndex < 4; lIndex++) + { + TotalNumberOfBytes.QuadPart = ClusterSize; + if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szFs, sizeof(szFs)/sizeof(WCHAR))) + { + lIndex = SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szFs); + if (lIndex != CB_ERR) + SendMessageW(hDlgCtrl, CB_SETITEMDATA, lIndex, (LPARAM)ClusterSize); + } + ClusterSize *= 2; + } + } + else + { + FIXME("unknown fs\n"); + SendDlgItemMessageW(hwndDlg, 28680, CB_RESETCONTENT, iSelIndex, 0); + return; + } +} + +VOID +InitializeFormatDriveDlg(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext) +{ + WCHAR szText[120]; + WCHAR szDrive[4] = { L'C', ':', '\\', 0 }; + WCHAR szFs[30] = {0}; + INT Length, TempLength; + DWORD dwSerial, dwMaxComp, dwFileSys; + ULARGE_INTEGER FreeBytesAvailableUser, TotalNumberOfBytes; + DWORD dwIndex, dwDefault; + UCHAR uMinor, uMajor; + BOOLEAN Latest; + HWND hDlgCtrl; + + Length = GetWindowTextW(hwndDlg, szText, sizeof(szText)/sizeof(WCHAR)); + if (Length < 0) + Length = 0; + szDrive[0] = pContext->Drive + L'A'; + if (GetVolumeInformationW(szDrive, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2, &dwSerial, &dwMaxComp, &dwFileSys, szFs, sizeof(szFs)/sizeof(WCHAR))) + { + szText[Length] = L' '; + szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0'; + TempLength = wcslen(&szText[Length+1]); + if (!TempLength) + { + /* load default volume label */ + TempLength = LoadStringW(shell32_hInstance, IDS_DRIVE_FIXED, &szText[Length+1], (sizeof(szText)/sizeof(WCHAR))- Length - 2); + } + else + { + /* set volume label */ + szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0'; + SendDlgItemMessageW(hwndDlg, 28679, WM_SETTEXT, 0, (LPARAM)&szText[Length+1]); + } + Length += TempLength + 1; + } + + if ((DWORD)Length + 4 < (sizeof(szText)/sizeof(WCHAR))) + { + szText[Length] = L' '; + szText[Length+1] = L'('; + szText[Length+2] = szDrive[0]; + szText[Length+3] = L')'; + Length +=4; + } + + if ((DWORD)Length < (sizeof(szText)/sizeof(WCHAR))) + szText[Length] = L'\0'; + else + szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0'; + + /* set window text */ + SetWindowTextW(hwndDlg, szText); + + if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailableUser, &TotalNumberOfBytes, NULL)) + { + if (StrFormatByteSizeW(TotalNumberOfBytes.QuadPart, szText, sizeof(szText)/sizeof(WCHAR))) + { + /* add drive capacity */ + szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0'; + SendDlgItemMessageW(hwndDlg, 28673, CB_ADDSTRING, 0, (LPARAM)szText); + SendDlgItemMessageW(hwndDlg, 28673, CB_SETCURSEL, 0, (LPARAM)0); + } + } + + if (pContext->Options & SHFMT_OPT_FULL) + { + /* check quick format button */ + SendDlgItemMessageW(hwndDlg, 28674, BM_SETCHECK, BST_CHECKED, 0); + } + + /* enumerate all available filesystems */ + dwIndex = 0; + dwDefault = 0; + hDlgCtrl = GetDlgItem(hwndDlg, 28677); + + while(pContext->QueryAvailableFileSystemFormat(dwIndex, szText, &uMajor, &uMinor, &Latest)) + { + szText[(sizeof(szText)/sizeof(WCHAR))-1] = L'\0'; + if (!wcsicmp(szText, szFs)) + dwDefault = dwIndex; + + SendMessageW(hDlgCtrl, CB_ADDSTRING, 0, (LPARAM)szText); + dwIndex++; + } + + if (!dwIndex) + { + ERR("no filesystem providers\n"); + return; + } + + /* select default filesys */ + SendMessageW(hDlgCtrl, CB_SETCURSEL, dwDefault, 0); + /* setup cluster combo */ + InsertDefaultClusterSizeForFs(hwndDlg, pContext); + /* hide progress control */ + ShowWindow(GetDlgItem(hwndDlg, 28678), SW_HIDE); +} + +HWND FormatDrvDialog = NULL; +BOOLEAN bSuccess = FALSE; + + +BOOLEAN +NTAPI +FormatExCB( + IN CALLBACKCOMMAND Command, + IN ULONG SubAction, + IN PVOID ActionInfo) +{ + PDWORD Progress; + PBOOLEAN pSuccess; + switch(Command) + { + case PROGRESS: + Progress = (PDWORD)ActionInfo; + SendDlgItemMessageW(FormatDrvDialog, 28678, PBM_SETPOS, (WPARAM)*Progress, 0); + break; + case DONE: + pSuccess = (PBOOLEAN)ActionInfo; + bSuccess = (*pSuccess); + break; + + case VOLUMEINUSE: + case INSUFFICIENTRIGHTS: + case FSNOTSUPPORTED: + case CLUSTERSIZETOOSMALL: + bSuccess = FALSE; + FIXME("\n"); + break; + + default: + break; + } + + return TRUE; +} + + + + + +VOID +FormatDrive(HWND hwndDlg, PFORMAT_DRIVE_CONTEXT pContext) +{ + WCHAR szDrive[4] = { L'C', ':', '\\', 0 }; + WCHAR szFileSys[40] = {0}; + WCHAR szLabel[40] = {0}; + INT iSelIndex; + UINT Length; + HWND hDlgCtrl; + BOOL QuickFormat; + DWORD ClusterSize; + + /* set volume path */ + szDrive[0] = pContext->Drive; + + /* get filesystem */ + hDlgCtrl = GetDlgItem(hwndDlg, 28677); + iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0); + if (iSelIndex == CB_ERR) + { + FIXME("\n"); + return; + } + Length = SendMessageW(hDlgCtrl, CB_GETLBTEXTLEN, iSelIndex, 0); + if ((int)Length == CB_ERR || Length + 1> sizeof(szFileSys)/sizeof(WCHAR)) + { + FIXME("\n"); + return; + } + + /* retrieve the file system */ + SendMessageW(hDlgCtrl, CB_GETLBTEXT, iSelIndex, (LPARAM)szFileSys); + szFileSys[(sizeof(szFileSys)/sizeof(WCHAR))-1] = L'\0'; + + /* retrieve the volume label */ + hDlgCtrl = GetWindow(hwndDlg, 28679); + Length = SendMessageW(hDlgCtrl, WM_GETTEXTLENGTH, 0, 0); + if (Length + 1 > sizeof(szLabel)/sizeof(WCHAR)) + { + FIXME("\n"); + return; + } + SendMessageW(hDlgCtrl, WM_GETTEXT, sizeof(szLabel)/sizeof(WCHAR), (LPARAM)szLabel); + szLabel[(sizeof(szLabel)/sizeof(WCHAR))-1] = L'\0'; + + /* check for quickformat */ + if (SendDlgItemMessageW(hwndDlg, 28674, BM_GETCHECK, 0, 0) == BST_CHECKED) + QuickFormat = TRUE; + else + QuickFormat = FALSE; + + /* get the cluster size */ + hDlgCtrl = GetDlgItem(hwndDlg, 28680); + iSelIndex = SendMessageW(hDlgCtrl, CB_GETCURSEL, 0, 0); + if (iSelIndex == CB_ERR) + { + FIXME("\n"); + return; + } + ClusterSize = SendMessageW(hDlgCtrl, CB_GETITEMDATA, iSelIndex, 0); + if ((int)ClusterSize == CB_ERR) + { + FIXME("\n"); + return; + } + + hDlgCtrl = GetDlgItem(hwndDlg, 28680); + ShowWindow(hDlgCtrl, SW_SHOW); + SendMessageW(hDlgCtrl, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); + bSuccess = FALSE; + + /* FIXME + * will cause display problems + * when performing more than one format + */ + FormatDrvDialog = hwndDlg; + + pContext->FormatEx(szDrive, + FMIFS_HARDDISK, /* FIXME */ + szFileSys, + szLabel, + QuickFormat, + ClusterSize, + FormatExCB); + + ShowWindow(hDlgCtrl, SW_HIDE); + FormatDrvDialog = NULL; + if (!bSuccess) + { + pContext->Result = SHFMT_ERROR; + } + else if (QuickFormat) + { + pContext->Result = SHFMT_OPT_FULL; + } + else + { + pContext->Result = FALSE; + } +} + + +BOOL +CALLBACK +FormatDriveDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PFORMAT_DRIVE_CONTEXT pContext; + + switch(uMsg) + { + case WM_INITDIALOG: + InitializeFormatDriveDlg(hwndDlg, (PFORMAT_DRIVE_CONTEXT)lParam); + SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam); + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER); + FormatDrive(hwndDlg, pContext); + break; + case IDCANCEL: + pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER); + EndDialog(hwndDlg, pContext->Result); + break; + case 28677: // filesystem combo + if (HIWORD(wParam) == CBN_SELENDOK) + { + pContext = (PFORMAT_DRIVE_CONTEXT)GetWindowLongPtr(hwndDlg, DWLP_USER); + InsertDefaultClusterSizeForFs(hwndDlg, pContext); + } + break; + } + } + return FALSE; +} + + +BOOL +InitializeFmifsLibrary(PFORMAT_DRIVE_CONTEXT pContext) +{ + INITIALIZE_FMIFS InitFmifs; + BOOLEAN ret; + HMODULE hLibrary; + + hLibrary = pContext->hLibrary = LoadLibraryW(L"fmifs.dll"); + if(!hLibrary) + { + ERR("failed to load fmifs.dll\n"); + return FALSE; + } + + InitFmifs = (INITIALIZE_FMIFS)GetProcAddress(hLibrary, "InitializeFmIfs"); + if (!InitFmifs) + { + ERR("InitializeFmIfs export is missing\n"); + FreeLibrary(hLibrary); + return FALSE; + } + + ret = (*InitFmifs)(NULL, DLL_PROCESS_ATTACH, NULL); + if (!ret) + { + ERR("fmifs failed to initialize\n"); + FreeLibrary(hLibrary); + return FALSE; + } + + pContext->QueryAvailableFileSystemFormat = (QUERY_AVAILABLEFSFORMAT)GetProcAddress(hLibrary, "QueryAvailableFileSystemFormat"); + if (!pContext->QueryAvailableFileSystemFormat) + { + ERR("QueryAvailableFileSystemFormat export is missing\n"); + FreeLibrary(hLibrary); + return FALSE; + } + + pContext->FormatEx = (FORMAT_EX) GetProcAddress(hLibrary, "FormatEx"); + if (!pContext->FormatEx) + { + ERR("FormatEx export is missing\n"); + FreeLibrary(hLibrary); + return FALSE; + } + + pContext->EnableVolumeCompression = (ENABLEVOLUMECOMPRESSION) GetProcAddress(hLibrary, "EnableVolumeCompression"); + if (!pContext->FormatEx) + { + ERR("EnableVolumeCompression export is missing\n"); + FreeLibrary(hLibrary); + return FALSE; + } + + pContext->Chkdsk = (CHKDSK) GetProcAddress(hLibrary, "Chkdsk"); + if (!pContext->Chkdsk) + { + ERR("Chkdsk export is missing\n"); + FreeLibrary(hLibrary); + return FALSE; + } + + return TRUE; +} + +/************************************************************************* + * SHFormatDrive (SHELL32.@) + */ + +DWORD +WINAPI +SHFormatDrive(HWND hwnd, UINT drive, UINT fmtID, UINT options) +{ + FORMAT_DRIVE_CONTEXT Context; + int result; + + TRACE("%p, 0x%08x, 0x%08x, 0x%08x - stub\n", hwnd, drive, fmtID, options); + + if (!InitializeFmifsLibrary(&Context)) + { + ERR("failed to initialize fmifs\n"); + return SHFMT_NOFORMAT; + } + + Context.Drive = drive; + Context.Options = options; + + result = DialogBoxParamW(shell32_hInstance, L"FORMAT_DLG", hwnd, FormatDriveDlg, (LPARAM)&Context); + + FreeLibrary(Context.hLibrary); + return result; +} + + diff --git a/reactos/dll/win32/shell32/enumidlist.cpp b/reactos/dll/win32/shell32/enumidlist.cpp new file mode 100644 index 00000000000..e44d0b22b6e --- /dev/null +++ b/reactos/dll/win32/shell32/enumidlist.cpp @@ -0,0 +1,301 @@ +/* + * IEnumIDList + * + * Copyright 1998 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +IEnumIDListImpl::IEnumIDListImpl() +{ + mpFirst = NULL; + mpLast = NULL; + mpCurrent = NULL; +} + +IEnumIDListImpl::~IEnumIDListImpl() +{ +} + +/************************************************************************** + * AddToEnumList() + */ +BOOL IEnumIDListImpl::AddToEnumList(LPITEMIDLIST pidl) +{ + ENUMLIST *pNew; + + TRACE("(%p)->(pidl=%p)\n", this, pidl); + + if (!pidl) + return FALSE; + + pNew = (ENUMLIST *)SHAlloc(sizeof(ENUMLIST)); + if (pNew) + { + /*set the next pointer */ + pNew->pNext = NULL; + pNew->pidl = pidl; + + /*is This the first item in the list? */ + if (!mpFirst) + { + mpFirst = pNew; + mpCurrent = pNew; + } + + if (mpLast) + { + /*add the new item to the end of the list */ + mpLast->pNext = pNew; + } + + /*update the last item pointer */ + mpLast = pNew; + TRACE("-- (%p)->(first=%p, last=%p)\n", this, mpFirst, mpLast); + return TRUE; + } + return FALSE; +} + +/************************************************************************** +* DeleteList() +*/ +BOOL IEnumIDListImpl::DeleteList() +{ + ENUMLIST *pDelete; + + TRACE("(%p)->()\n", this); + + while (mpFirst) + { + pDelete = mpFirst; + mpFirst = pDelete->pNext; + SHFree(pDelete->pidl); + SHFree(pDelete); + } + mpFirst = NULL; + mpLast = NULL; + mpCurrent = NULL; + return TRUE; +} + +/************************************************************************** + * HasItemWithCLSID() + */ +BOOL IEnumIDListImpl::HasItemWithCLSID(LPITEMIDLIST pidl) +{ + ENUMLIST *pCur; + IID *ptr = _ILGetGUIDPointer(pidl); + + if (ptr) + { + REFIID refid = *ptr; + pCur = mpFirst; + + while(pCur) + { + LPGUID curid = _ILGetGUIDPointer(pCur->pidl); + if (curid && IsEqualGUID(*curid, refid)) + { + return TRUE; + } + pCur = pCur->pNext; + } + } + + return FALSE; +} + + +/************************************************************************** + * CreateFolderEnumList() + */ +BOOL IEnumIDListImpl::CreateFolderEnumList( + LPCWSTR lpszPath, + DWORD dwFlags) +{ + LPITEMIDLIST pidl=NULL; + WIN32_FIND_DATAW stffile; + HANDLE hFile; + WCHAR szPath[MAX_PATH]; + BOOL succeeded = TRUE; + static const WCHAR stars[] = { '*','.','*',0 }; + static const WCHAR dot[] = { '.',0 }; + static const WCHAR dotdot[] = { '.','.',0 }; + + TRACE("(%p)->(path=%s flags=0x%08x)\n", this, debugstr_w(lpszPath), dwFlags); + + if(!lpszPath || !lpszPath[0]) return FALSE; + + wcscpy(szPath, lpszPath); + PathAddBackslashW(szPath); + wcscat(szPath,stars); + + hFile = FindFirstFileW(szPath,&stffile); + if ( hFile != INVALID_HANDLE_VALUE ) + { + BOOL findFinished = FALSE; + + do + { + if ( !(stffile.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + || (dwFlags & SHCONTF_INCLUDEHIDDEN) ) + { + if ( (stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && + dwFlags & SHCONTF_FOLDERS && + strcmpW(stffile.cFileName, dot) && strcmpW(stffile.cFileName, dotdot)) + { + pidl = _ILCreateFromFindDataW(&stffile); + succeeded = succeeded && AddToEnumList(pidl); + } + else if (!(stffile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + && dwFlags & SHCONTF_NONFOLDERS) + { + pidl = _ILCreateFromFindDataW(&stffile); + succeeded = succeeded && AddToEnumList(pidl); + } + } + if (succeeded) + { + if (!FindNextFileW(hFile, &stffile)) + { + if (GetLastError() == ERROR_NO_MORE_FILES) + findFinished = TRUE; + else + succeeded = FALSE; + } + } + } while (succeeded && !findFinished); + FindClose(hFile); + } + + return succeeded; +} + +/************************************************************************** + * IEnumIDList_fnNext + */ + +HRESULT WINAPI IEnumIDListImpl::Next( + ULONG celt, + LPITEMIDLIST * rgelt, + ULONG *pceltFetched) +{ + ULONG i; + HRESULT hr = S_OK; + LPITEMIDLIST temp; + + TRACE("(%p)->(%d,%p, %p)\n", this, celt, rgelt, pceltFetched); + +/* It is valid to leave pceltFetched NULL when celt is 1. Some of explorer's + * subsystems actually use it (and so may a third party browser) + */ + if(pceltFetched) + *pceltFetched = 0; + + *rgelt=0; + + if(celt > 1 && !pceltFetched) + { return E_INVALIDARG; + } + + if(celt > 0 && !mpCurrent) + { return S_FALSE; + } + + for(i = 0; i < celt; i++) + { if(!mpCurrent) + break; + + temp = ILClone(mpCurrent->pidl); + rgelt[i] = temp; + mpCurrent = mpCurrent->pNext; + } + if(pceltFetched) + { *pceltFetched = i; + } + + return hr; +} + +/************************************************************************** +* IEnumIDList_fnSkip +*/ +HRESULT WINAPI IEnumIDListImpl::Skip( + ULONG celt) +{ + DWORD dwIndex; + HRESULT hr = S_OK; + + TRACE("(%p)->(%u)\n", this, celt); + + for(dwIndex = 0; dwIndex < celt; dwIndex++) + { if(!mpCurrent) + { hr = S_FALSE; + break; + } + mpCurrent = mpCurrent->pNext; + } + return hr; +} + +/************************************************************************** +* IEnumIDList_fnReset +*/ +HRESULT WINAPI IEnumIDListImpl::Reset() +{ + TRACE("(%p)\n", this); + mpCurrent = mpFirst; + return S_OK; +} + +/************************************************************************** +* IEnumIDList_fnClone +*/ +HRESULT WINAPI IEnumIDListImpl::Clone(LPENUMIDLIST *ppenum) +{ + TRACE("(%p)->() to (%p)->() E_NOTIMPL\n", this, ppenum); + return E_NOTIMPL; +} + +/************************************************************************** + * IEnumIDList_Folder_Constructor + * + */ +HRESULT IEnumIDList_Constructor(IEnumIDList **enumerator) +{ + CComObject *theEnumerator; + CComPtr result; + HRESULT hResult; + + if (enumerator == NULL) + return E_POINTER; + *enumerator = NULL; + ATLTRY (theEnumerator = new CComObject); + if (theEnumerator == NULL) + return E_OUTOFMEMORY; + hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result); + if (FAILED (hResult)) + { + delete theEnumerator; + return hResult; + } + *enumerator = result.Detach (); + return S_OK; +} diff --git a/reactos/dll/win32/shell32/enumidlist.h b/reactos/dll/win32/shell32/enumidlist.h index 1cd7370c2ee..b68265acd29 100644 --- a/reactos/dll/win32/shell32/enumidlist.h +++ b/reactos/dll/win32/shell32/enumidlist.h @@ -18,14 +18,37 @@ #include "shlobj.h" -/* Creates an IEnumIDList; add LPITEMIDLISTs to it with AddToEnumList. */ -LPENUMIDLIST IEnumIDList_Constructor(void); -BOOL AddToEnumList(IEnumIDList *list, LPITEMIDLIST pidl); -BOOL HasItemWithCLSID(IEnumIDList *list, LPITEMIDLIST pidl); +struct ENUMLIST +{ + ENUMLIST *pNext; + LPITEMIDLIST pidl; +}; -/* Enumerates the folders and/or files (depending on dwFlags) in lpszPath and - * adds them to the already-created list. - */ -BOOL CreateFolderEnumList(IEnumIDList *list, LPCWSTR lpszPath, DWORD dwFlags); +class IEnumIDListImpl : + public CComObjectRootEx, + public IEnumIDList +{ +private: + ENUMLIST *mpFirst; + ENUMLIST *mpLast; + ENUMLIST *mpCurrent; +public: + IEnumIDListImpl(); + ~IEnumIDListImpl(); + BOOL AddToEnumList(LPITEMIDLIST pidl); + BOOL DeleteList(); + BOOL HasItemWithCLSID(LPITEMIDLIST pidl); + BOOL CreateFolderEnumList(LPCWSTR lpszPath, DWORD dwFlags); + + // *** IEnumIDList methods *** + virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched); + virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt); + virtual HRESULT STDMETHODCALLTYPE Reset(); + virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum); + +BEGIN_COM_MAP(IEnumIDListImpl) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) +END_COM_MAP() +}; #endif /* ndef __ENUMIDLIST_H__ */ diff --git a/reactos/dll/win32/shell32/extracticon.cpp b/reactos/dll/win32/shell32/extracticon.cpp new file mode 100644 index 00000000000..4a4e5ccaf18 --- /dev/null +++ b/reactos/dll/win32/shell32/extracticon.cpp @@ -0,0 +1,358 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Registry namespace extension + * FILE: dll/win32/shell32/extracticon.c + * PURPOSE: Icon extraction + * + * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org) + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +struct IconLocation +{ + LPWSTR file; + UINT index; +}; + +class IconExtraction : + public CComObjectRootEx, + public IDefaultExtractIconInit, + public IExtractIconW, + public IExtractIconA, + public IPersistFile +{ +private: + UINT flags; + struct IconLocation defaultIcon; + struct IconLocation normalIcon; + struct IconLocation openIcon; + struct IconLocation shortcutIcon; +public: + IconExtraction(); + ~IconExtraction(); + + // IDefaultExtractIconInit + virtual HRESULT STDMETHODCALLTYPE SetDefaultIcon(LPCWSTR pszFile, int iIcon); + virtual HRESULT STDMETHODCALLTYPE SetFlags(UINT uFlags); + virtual HRESULT STDMETHODCALLTYPE SetKey(HKEY hkey); + virtual HRESULT STDMETHODCALLTYPE SetNormalIcon(LPCWSTR pszFile, int iIcon); + virtual HRESULT STDMETHODCALLTYPE SetOpenIcon(LPCWSTR pszFile, int iIcon); + virtual HRESULT STDMETHODCALLTYPE SetShortcutIcon(LPCWSTR pszFile, int iIcon); + + // IExtractIconW + virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags); + virtual HRESULT STDMETHODCALLTYPE Extract(LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); + + // IExtractIconA + virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags); + virtual HRESULT STDMETHODCALLTYPE Extract(LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); + + // IPersist + virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID); + virtual HRESULT STDMETHODCALLTYPE IsDirty(); + + // IPersistFile + virtual HRESULT STDMETHODCALLTYPE Load(LPCOLESTR pszFileName, DWORD dwMode); + virtual HRESULT STDMETHODCALLTYPE Save(LPCOLESTR pszFileName, BOOL fRemember); + virtual HRESULT STDMETHODCALLTYPE SaveCompleted(LPCOLESTR pszFileName); + virtual HRESULT STDMETHODCALLTYPE GetCurFile(LPOLESTR *ppszFileName); + +BEGIN_COM_MAP(IconExtraction) + COM_INTERFACE_ENTRY_IID(IID_IDefaultExtractIconInit, IDefaultExtractIconInit) + COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW) + COM_INTERFACE_ENTRY_IID(IID_IExtractIconA, IExtractIconA) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) + COM_INTERFACE_ENTRY_IID(IID_IPersistFile, IPersistFile) +END_COM_MAP() +}; + +VOID DuplicateString( + LPCWSTR Source, + LPWSTR *Destination) +{ + SIZE_T cb; + + if (*Destination) + CoTaskMemFree(*Destination); + + cb = (wcslen(Source) + 1) * sizeof(WCHAR); + *Destination = (LPWSTR)CoTaskMemAlloc(cb); + if (!*Destination) + return; + CopyMemory(*Destination, Source, cb); +} + +IconExtraction::IconExtraction() +{ + flags = 0; + memset(&defaultIcon, 0, sizeof(defaultIcon)); + memset(&normalIcon, 0, sizeof(normalIcon)); + memset(&openIcon, 0, sizeof(openIcon)); + memset(&shortcutIcon, 0, sizeof(shortcutIcon)); +} + +IconExtraction::~IconExtraction() +{ + if (defaultIcon.file) CoTaskMemFree(defaultIcon.file); + if (normalIcon.file) CoTaskMemFree(normalIcon.file); + if (openIcon.file) CoTaskMemFree(openIcon.file); + if (shortcutIcon.file) CoTaskMemFree(shortcutIcon.file); +} + +HRESULT STDMETHODCALLTYPE IconExtraction::SetDefaultIcon( + LPCWSTR pszFile, + int iIcon) +{ + TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon); + + DuplicateString(pszFile, &defaultIcon.file); + if (!defaultIcon.file) + return E_OUTOFMEMORY; + defaultIcon.index = iIcon; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::SetFlags( + UINT uFlags) +{ + TRACE("(%p, 0x%x)\n", this, uFlags); + + flags = uFlags; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::SetKey( + HKEY hkey) +{ + FIXME("(%p, %p)\n", this, hkey); + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::SetNormalIcon( + LPCWSTR pszFile, + int iIcon) +{ + TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon); + + DuplicateString(pszFile, &normalIcon.file); + if (!normalIcon.file) + return E_OUTOFMEMORY; + normalIcon.index = iIcon; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::SetOpenIcon( + LPCWSTR pszFile, + int iIcon) +{ + TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon); + + DuplicateString(pszFile, &openIcon.file); + if (!openIcon.file) + return E_OUTOFMEMORY; + openIcon.index = iIcon; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::SetShortcutIcon( + LPCWSTR pszFile, + int iIcon) +{ + TRACE("(%p, %s, %d)\n", this, debugstr_w(pszFile), iIcon); + + DuplicateString(pszFile, &shortcutIcon.file); + if (!shortcutIcon.file) + return E_OUTOFMEMORY; + shortcutIcon.index = iIcon; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::GetIconLocation( + UINT uFlags, + LPWSTR szIconFile, + UINT cchMax, + int *piIndex, + UINT *pwFlags) +{ + const struct IconLocation *icon = NULL; + SIZE_T cb; + + TRACE("(%p, 0x%x, %s, 0x%x, %p, %p)\n", this, uFlags, debugstr_w(szIconFile), cchMax, piIndex, pwFlags); + + if (!piIndex || !pwFlags) + return E_POINTER; + + if (uFlags & GIL_DEFAULTICON) + icon = defaultIcon.file ? &defaultIcon : &normalIcon; + else if (uFlags & GIL_FORSHORTCUT) + icon = shortcutIcon.file ? &shortcutIcon : &normalIcon; + else if (uFlags & GIL_OPENICON) + icon = openIcon.file ? &openIcon : &normalIcon; + else + icon = &normalIcon; + + if (!icon->file) + return E_FAIL; + + cb = wcslen(icon->file) + 1; + if (cchMax < (UINT)cb) + return E_FAIL; + CopyMemory(szIconFile, icon->file, cb * sizeof(WCHAR)); + *piIndex = icon->index; + *pwFlags = flags; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::Extract( + LPCWSTR pszFile, + UINT nIconIndex, + HICON *phiconLarge, + HICON *phiconSmall, + UINT nIconSize) +{ + TRACE("(%p, %s, %u, %p, %p, %u)\n", this, debugstr_w(pszFile), nIconIndex, phiconLarge, phiconSmall, nIconSize); + + /* Nothing to do, ExtractIconW::GetIconLocation should be enough */ + return S_FALSE; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::GetIconLocation( + UINT uFlags, + LPSTR szIconFile, + UINT cchMax, + int *piIndex, + UINT *pwFlags) +{ + LPWSTR szIconFileW = NULL; + HRESULT hr; + + if (cchMax > 0) + { + szIconFileW = (LPWSTR)CoTaskMemAlloc(cchMax * sizeof(WCHAR)); + if (!szIconFileW) + return E_OUTOFMEMORY; + } + + hr = GetIconLocation( + uFlags, szIconFileW, cchMax, piIndex, pwFlags); + if (SUCCEEDED(hr) && cchMax > 0) + if (0 == WideCharToMultiByte(CP_ACP, 0, szIconFileW, cchMax, szIconFile, cchMax, NULL, NULL)) + hr = E_FAIL; + + if (szIconFileW) + CoTaskMemFree(szIconFileW); + return hr; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::Extract( + LPCSTR pszFile, + UINT nIconIndex, + HICON *phiconLarge, + HICON *phiconSmall, + UINT nIconSize) +{ + LPWSTR pszFileW = NULL; + int nLength; + HRESULT hr; + + if (pszFile) + { + nLength = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0); + if (nLength == 0) + return E_FAIL; + pszFileW = (LPWSTR)CoTaskMemAlloc(nLength * sizeof(WCHAR)); + if (!pszFileW) + return E_OUTOFMEMORY; + if (!MultiByteToWideChar(CP_ACP, 0, pszFile, nLength, pszFileW, nLength)) + { + CoTaskMemFree(pszFileW); + return E_FAIL; + } + } + + hr = Extract( + pszFileW, nIconIndex, phiconLarge, phiconSmall, nIconSize); + + if (pszFileW) + CoTaskMemFree(pszFileW); + return hr; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::GetClassID( + CLSID *pClassID) +{ + TRACE("(%p, %p)\n", this, pClassID); + + if (!pClassID) + return E_POINTER; + + *pClassID = GUID_NULL; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::IsDirty() +{ + FIXME("(%p)\n", this); + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::Load( + LPCOLESTR pszFileName, + DWORD dwMode) +{ + FIXME("(%p, %s, %u)\n", this, debugstr_w(pszFileName), dwMode); + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::Save( + LPCOLESTR pszFileName, + BOOL fRemember) +{ + FIXME("(%p, %s, %d)\n", this, debugstr_w(pszFileName), fRemember); + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::SaveCompleted( + LPCOLESTR pszFileName) +{ + FIXME("(%p, %s)\n", this, debugstr_w(pszFileName)); + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE IconExtraction::GetCurFile( + LPOLESTR *ppszFileName) +{ + FIXME("(%p, %p)\n", this, ppszFileName); + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT WINAPI SHCreateDefaultExtractIcon(REFIID riid, void **ppv) +{ + CComObject *theExtractor; + CComPtr result; + HRESULT hResult; + + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; + ATLTRY (theExtractor = new CComObject); + if (theExtractor == NULL) + return E_OUTOFMEMORY; + hResult = theExtractor->QueryInterface (riid, (void **)&result); + if (FAILED (hResult)) + { + delete theExtractor; + return hResult; + } + *ppv = result.Detach (); + return S_OK; +} diff --git a/reactos/dll/win32/shell32/folder_options.cpp b/reactos/dll/win32/shell32/folder_options.cpp new file mode 100644 index 00000000000..f091877c1bd --- /dev/null +++ b/reactos/dll/win32/shell32/folder_options.cpp @@ -0,0 +1,827 @@ +/* + * Open With Context Menu extension + * + * Copyright 2007 Johannes Anderwald + * + * 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 + + +WINE_DEFAULT_DEBUG_CHANNEL (fprop); +#define MAX_PROPERTY_SHEET_PAGE (32) + +/// Folder Options: +/// CLASSKEY = HKEY_CLASSES_ROOT\CLSID\{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF} +/// DefaultIcon = %SystemRoot%\system32\SHELL32.dll,-210 +/// Verbs: Open / RunAs +/// Cmd: rundll32.exe shell32.dll,Options_RunDLL 0 + +/// ShellFolder Attributes: 0x0 + +typedef struct +{ + DWORD cFiles; + DWORD cFolder; + LARGE_INTEGER bSize; + HWND hwndDlg; + WCHAR szFolderPath[MAX_PATH]; +}FOLDER_PROPERTIES_CONTEXT, *PFOLDER_PROPERTIES_CONTEXT; + +typedef struct +{ + WCHAR FileExtension[30]; + WCHAR FileDescription[100]; + WCHAR ClassKey[MAX_PATH]; +}FOLDER_FILE_TYPE_ENTRY, *PFOLDER_FILE_TYPE_ENTRY; + +typedef struct +{ + LPCWSTR szKeyName; + UINT ResourceID; +}FOLDER_VIEW_ENTRY, PFOLDER_VIEW_ENTRY; +/* +static FOLDER_VIEW_ENTRY s_Options[] = +{ + { L"AlwaysShowMenus", IDS_ALWAYSSHOWMENUS }, + { L"AutoCheckSelect", -1 }, + { L"ClassicViewState", -1 }, + { L"DontPrettyPath", -1 }, + { L"Filter", -1 }, + { L"FolderContentsInfoTip", IDS_FOLDERCONTENTSTIP }, + { L"FriendlyTree", -1 }, + { L"Hidden", -1, }, + { L"HideFileExt", IDS_HIDEFILEEXT }, + { L"HideIcons", -1}, + { L"IconsOnly", -1}, + { L"ListviewAlphaSelect", -1}, + { L"ListviewShadow", -1}, + { L"ListviewWatermark", -1}, + { L"MapNetDrvBtn", -1}, + { L"PersistBrowsers", -1}, + { L"SeperateProcess", IDS_SEPERATEPROCESS}, + { L"ServerAdminUI", -1}, + { L"SharingWizardOn", IDS_USESHAREWIZARD}, + { L"ShowCompColor", IDS_COMPCOLOR}, + { L"ShowInfoTip", IDS_SHOWINFOTIP}, + { L"ShowPreviewHandlers", -1}, + { L"ShowSuperHidden", IDS_HIDEOSFILES}, + { L"ShowTypeOverlay", -1}, + { L"Start_ShowMyGames", -1}, + { L"StartMenuInit", -1}, + { L"SuperHidden", -1}, + { L"TypeAhead", -1}, + { L"Webview", -1}, + { NULL, -1} + +}; +*/ + +EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj); + +INT_PTR +CALLBACK +FolderOptionsGeneralDlg( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + + + + return FALSE; +} + +static +VOID +InitializeFolderOptionsListCtrl(HWND hwndDlg) +{ + RECT clientRect; + LVCOLUMNW col; + WCHAR szName[50]; + HWND hDlgCtrl; + + hDlgCtrl = GetDlgItem(hwndDlg, 14003); + + if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR))) + szName[0] = 0; + szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0; + + GetClientRect(hDlgCtrl, &clientRect); + ZeroMemory(&col, sizeof(LV_COLUMN)); + col.mask = LVCF_SUBITEM | LVCF_WIDTH | LVCF_FMT; + col.iSubItem = 0; + col.pszText = szName; + col.fmt = LVCFMT_LEFT; + col.cx = (clientRect.right - clientRect.left) - GetSystemMetrics(SM_CXVSCROLL); + (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMN, 0, (LPARAM)&col); + + + +} + + +INT_PTR +CALLBACK +FolderOptionsViewDlg( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + switch(uMsg) + { + case WM_INITDIALOG: + InitializeFolderOptionsListCtrl(hwndDlg); + return TRUE; + } + + return FALSE; + +} + +VOID +InitializeFileTypesListCtrlColumns(HWND hDlgCtrl) +{ + RECT clientRect; + LVCOLUMNW col; + WCHAR szName[50]; + DWORD dwStyle; + int columnSize = 140; + + + if (!LoadStringW(shell32_hInstance, IDS_COLUMN_EXTENSION, szName, sizeof(szName) / sizeof(WCHAR))) + { + /* default to english */ + wcscpy(szName, L"Extensions"); + } + + /* make sure its null terminated */ + szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0; + + GetClientRect(hDlgCtrl, &clientRect); + ZeroMemory(&col, sizeof(LV_COLUMN)); + columnSize = 140; //FIXME + col.iSubItem = 0; + col.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT; + col.fmt = LVCFMT_FIXED_WIDTH; + col.cx = columnSize | LVCFMT_LEFT; + col.cchTextMax = wcslen(szName); + col.pszText = szName; + (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&col); + + if (!LoadStringW(shell32_hInstance, IDS_FILE_TYPES, szName, sizeof(szName) / sizeof(WCHAR))) + { + /* default to english */ + wcscpy(szName, L"FileTypes"); + } + + col.iSubItem = 1; + col.cx = clientRect.right - clientRect.left - columnSize; + col.cchTextMax = wcslen(szName); + col.pszText = szName; + (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&col); + + /* set full select style */ + dwStyle = (DWORD) SendMessage(hDlgCtrl, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + dwStyle = dwStyle | LVS_EX_FULLROWSELECT; + SendMessage(hDlgCtrl, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle); +} + +INT +FindItem(HWND hDlgCtrl, WCHAR * ItemName) +{ + LVFINDINFOW findInfo; + ZeroMemory(&findInfo, sizeof(LVFINDINFOW)); + + findInfo.flags = LVFI_STRING; + findInfo.psz = ItemName; + return ListView_FindItem(hDlgCtrl, 0, &findInfo); +} + +VOID +InsertFileType(HWND hDlgCtrl, WCHAR * szName, PINT iItem, WCHAR * szFile) +{ + PFOLDER_FILE_TYPE_ENTRY Entry; + HKEY hKey; + LVITEMW lvItem; + DWORD dwSize; + + if (szName[0] != L'.') + { + /* FIXME handle URL protocol handlers */ + return; + } + + /* allocate file type entry */ + Entry = (PFOLDER_FILE_TYPE_ENTRY)HeapAlloc(GetProcessHeap(), 0, sizeof(FOLDER_FILE_TYPE_ENTRY)); + + if (!Entry) + return; + + /* open key */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szName, 0, KEY_READ, &hKey) != ERROR_SUCCESS) + return; + + /* FIXME check for duplicates */ + + /* query for the default key */ + dwSize = sizeof(Entry->ClassKey); + if (RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->ClassKey, &dwSize) != ERROR_SUCCESS) + { + /* no link available */ + Entry->ClassKey[0] = 0; + } + + if (Entry->ClassKey[0]) + { + HKEY hTemp; + /* try open linked key */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, Entry->ClassKey, 0, KEY_READ, &hTemp) == ERROR_SUCCESS) + { + /* use linked key */ + RegCloseKey(hKey); + hKey = hTemp; + } + } + + /* read friendly type name */ + if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", Entry->FileDescription, sizeof(Entry->FileDescription), NULL, 0, NULL) != ERROR_SUCCESS) + { + /* read file description */ + dwSize = sizeof(Entry->FileDescription); + Entry->FileDescription[0] = 0; + + /* read default key */ + RegQueryValueExW(hKey, NULL, NULL, NULL, (LPBYTE)Entry->FileDescription, &dwSize); + } + + /* close key */ + RegCloseKey(hKey); + + /* convert extension to upper case */ + wcscpy(Entry->FileExtension, szName); + _wcsupr(Entry->FileExtension); + + if (!Entry->FileDescription[0]) + { + /* construct default 'FileExtensionFile' */ + wcscpy(Entry->FileDescription, &Entry->FileExtension[1]); + wcscat(Entry->FileDescription, L" "); + wcscat(Entry->FileDescription, szFile); + } + + ZeroMemory(&lvItem, sizeof(LVITEMW)); + lvItem.mask = LVIF_TEXT | LVIF_PARAM; + lvItem.iSubItem = 0; + lvItem.pszText = &Entry->FileExtension[1]; + lvItem.iItem = *iItem; + lvItem.lParam = (LPARAM)Entry; + (void)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&lvItem); + + ZeroMemory(&lvItem, sizeof(LVITEMW)); + lvItem.mask = LVIF_TEXT; + lvItem.pszText = Entry->FileDescription; + lvItem.iItem = *iItem; + lvItem.iSubItem = 1; + + (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&lvItem); + (*iItem)++; +} + +int +CALLBACK +ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) +{ + PFOLDER_FILE_TYPE_ENTRY Entry1, Entry2; + + Entry1 = (PFOLDER_FILE_TYPE_ENTRY)lParam1; + Entry2 = (PFOLDER_FILE_TYPE_ENTRY)lParam2; + + return wcsicmp(Entry1->FileExtension, Entry2->FileExtension); +} + +BOOL +InitializeFileTypesListCtrl(HWND hwndDlg) +{ + HWND hDlgCtrl; + DWORD dwIndex = 0; + WCHAR szName[50]; + WCHAR szFile[100]; + DWORD dwName; + LVITEMW lvItem; + INT iItem = 0; + + hDlgCtrl = GetDlgItem(hwndDlg, 14000); + InitializeFileTypesListCtrlColumns(hDlgCtrl); + + szFile[0] = 0; + if (!LoadStringW(shell32_hInstance, IDS_SHV_COLUMN1, szFile, sizeof(szFile) / sizeof(WCHAR))) + { + /* default to english */ + wcscpy(szFile, L"File"); + } + szFile[(sizeof(szFile)/sizeof(WCHAR))-1] = 0; + + dwName = sizeof(szName) / sizeof(WCHAR); + + while(RegEnumKeyExW(HKEY_CLASSES_ROOT, dwIndex++, szName, &dwName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) + { + InsertFileType(hDlgCtrl, szName, &iItem, szFile); + dwName = sizeof(szName) / sizeof(WCHAR); + } + + /* sort list */ + ListView_SortItems(hDlgCtrl, ListViewCompareProc, NULL); + + /* select first item */ + ZeroMemory(&lvItem, sizeof(LVITEMW)); + lvItem.mask = LVIF_STATE; + lvItem.stateMask = (UINT)-1; + lvItem.state = LVIS_FOCUSED|LVIS_SELECTED; + lvItem.iItem = 0; + (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&lvItem); + + return TRUE; +} + +PFOLDER_FILE_TYPE_ENTRY +FindSelectedItem( + HWND hDlgCtrl) +{ + UINT Count, Index; + LVITEMW lvItem; + + Count = ListView_GetItemCount(hDlgCtrl); + + for (Index = 0; Index < Count; Index++) + { + ZeroMemory(&lvItem, sizeof(LVITEM)); + lvItem.mask = LVIF_PARAM | LVIF_STATE; + lvItem.iItem = Index; + lvItem.stateMask = (UINT)-1; + + if (ListView_GetItem(hDlgCtrl, &lvItem)) + { + if (lvItem.state & LVIS_SELECTED) + return (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; + } + } + + return NULL; +} + +INT_PTR +CALLBACK +FolderOptionsFileTypesDlg( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + LPNMLISTVIEW lppl; + LVITEMW lvItem; + WCHAR Buffer[255], FormatBuffer[255]; + PFOLDER_FILE_TYPE_ENTRY pItem; + OPENASINFO Info; + + switch(uMsg) + { + case WM_INITDIALOG: + InitializeFileTypesListCtrl(hwndDlg); + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case 14006: + pItem = FindSelectedItem(GetDlgItem(hwndDlg, 14000)); + if (pItem) + { + Info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT; + Info.pcszClass = pItem->FileExtension; + SHOpenWithDialog(hwndDlg, &Info); + } + break; + } + + break; + case WM_NOTIFY: + lppl = (LPNMLISTVIEW) lParam; + + if (lppl->hdr.code == LVN_ITEMCHANGING) + { + ZeroMemory(&lvItem, sizeof(LVITEM)); + lvItem.mask = LVIF_PARAM; + lvItem.iItem = lppl->iItem; + if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&lvItem)) + return TRUE; + + pItem = (PFOLDER_FILE_TYPE_ENTRY)lvItem.lParam; + if (!pItem) + return TRUE; + + if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED)) + { + /* new focused item */ + if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILS, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR))) + { + /* use default english format string */ + wcscpy(FormatBuffer, L"Details for '%s' extension"); + } + + /* format buffer */ + swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1]); + /* update dialog */ + SendDlgItemMessageW(hwndDlg, 14003, WM_SETTEXT, 0, (LPARAM)Buffer); + + if (!LoadStringW(shell32_hInstance, IDS_FILE_DETAILSADV, FormatBuffer, sizeof(FormatBuffer) / sizeof(WCHAR))) + { + /* use default english format string */ + wcscpy(FormatBuffer, L"Files with extension '%s' are of type '%s'. To change settings that affect all '%s' files, click Advanced."); + } + /* format buffer */ + swprintf(Buffer, FormatBuffer, &pItem->FileExtension[1], &pItem->FileDescription[0], &pItem->FileDescription[0]); + /* update dialog */ + SendDlgItemMessageW(hwndDlg, 14007, WM_SETTEXT, 0, (LPARAM)Buffer); + } + } + break; + } + + return FALSE; +} + + +VOID +ShowFolderOptionsDialog(HWND hWnd, HINSTANCE hInst) +{ + PROPSHEETHEADERW pinfo; + HPROPSHEETPAGE hppages[3]; + HPROPSHEETPAGE hpage; + UINT num_pages = 0; + WCHAR szOptions[100]; + + hpage = SH_CreatePropertySheetPage("FOLDER_OPTIONS_GENERAL_DLG", FolderOptionsGeneralDlg, 0, NULL); + if (hpage) + hppages[num_pages++] = hpage; + + hpage = SH_CreatePropertySheetPage("FOLDER_OPTIONS_VIEW_DLG", FolderOptionsViewDlg, 0, NULL); + if (hpage) + hppages[num_pages++] = hpage; + + hpage = SH_CreatePropertySheetPage("FOLDER_OPTIONS_FILETYPES_DLG", FolderOptionsFileTypesDlg, 0, NULL); + if (hpage) + hppages[num_pages++] = hpage; + + szOptions[0] = L'\0'; + LoadStringW(shell32_hInstance, IDS_FOLDER_OPTIONS, szOptions, sizeof(szOptions) / sizeof(WCHAR)); + szOptions[(sizeof(szOptions)/sizeof(WCHAR))-1] = L'\0'; + + memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW)); + pinfo.dwSize = sizeof(PROPSHEETHEADERW); + pinfo.dwFlags = PSH_NOCONTEXTHELP; + pinfo.nPages = num_pages; + pinfo.phpage = hppages; + pinfo.pszCaption = szOptions; + + PropertySheetW(&pinfo); +} + +VOID +Options_RunDLLCommon(HWND hWnd, HINSTANCE hInst, int fOptions, DWORD nCmdShow) +{ + switch(fOptions) + { + case 0: + ShowFolderOptionsDialog(hWnd, hInst); + break; + case 1: + // show taskbar options dialog + FIXME("notify explorer to show taskbar options dialog"); + //PostMessage(GetShellWindow(), WM_USER+22, fOptions, 0); + break; + default: + FIXME("unrecognized options id %d\n", fOptions); + } +} + +/************************************************************************* + * Options_RunDLL (SHELL32.@) + */ +EXTERN_C VOID WINAPI Options_RunDLL(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) +{ + Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow); +} + +/************************************************************************* + * Options_RunDLLA (SHELL32.@) + */ +EXTERN_C VOID WINAPI Options_RunDLLA(HWND hWnd, HINSTANCE hInst, LPCSTR cmd, DWORD nCmdShow) +{ + Options_RunDLLCommon(hWnd, hInst, StrToIntA(cmd), nCmdShow); +} + +/************************************************************************* + * Options_RunDLLW (SHELL32.@) + */ +EXTERN_C VOID WINAPI Options_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow) +{ + Options_RunDLLCommon(hWnd, hInst, StrToIntW(cmd), nCmdShow); +} + +static +DWORD WINAPI +CountFolderAndFiles(LPVOID lParam) +{ + WIN32_FIND_DATAW FindData; + HANDLE hFile; + UINT Length; + LPWSTR pOffset; + BOOL ret; + PFOLDER_PROPERTIES_CONTEXT pContext = (PFOLDER_PROPERTIES_CONTEXT) lParam; + + pOffset = PathAddBackslashW(pContext->szFolderPath); + if (!pOffset) + return 0; + + Length = pOffset - pContext->szFolderPath; + + wcscpy(pOffset, L"*.*"); + hFile = FindFirstFileW(pContext->szFolderPath, &FindData); + if (hFile == INVALID_HANDLE_VALUE) + return 0; + + do + { + ret = FindNextFileW(hFile, &FindData); + if (ret) + { + if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (FindData.cFileName[0] == L'.' && FindData.cFileName[1] == L'.' && + FindData.cFileName[2] == L'\0') + continue; + + pContext->cFolder++; + wcscpy(pOffset, FindData.cFileName); + CountFolderAndFiles((LPVOID)pContext); + pOffset[0] = L'\0'; + } + else + { + pContext->cFiles++; + pContext->bSize.u.LowPart += FindData.nFileSizeLow; + pContext->bSize.u.HighPart += FindData.nFileSizeHigh; + } + } + else if (GetLastError() == ERROR_NO_MORE_FILES) + { + break; + } + }while(1); + + FindClose(hFile); + return 1; +} + +static +VOID +InitializeFolderGeneralDlg(PFOLDER_PROPERTIES_CONTEXT pContext) +{ + LPWSTR pFolderName; + WIN32_FILE_ATTRIBUTE_DATA FolderAttribute; + FILETIME ft; + SYSTEMTIME dt; + WCHAR szBuffer[MAX_PATH+5]; + WCHAR szFormat[30] = {0}; + + static const WCHAR wFormat[] = {'%','0','2','d','/','%','0','2','d','/','%','0','4','d',' ',' ','%','0','2','d',':','%','0','2','u',0}; + + pFolderName = wcsrchr(pContext->szFolderPath, L'\\'); + if (!pFolderName) + return; + + /* set folder name */ + SendDlgItemMessageW(pContext->hwndDlg, 14001, WM_SETTEXT, 0, (LPARAM) (pFolderName + 1)); + /* set folder location */ + pFolderName[0] = L'\0'; + if (wcslen(pContext->szFolderPath) == 2) + { + /* folder is located at root */ + WCHAR szDrive[4] = {L'C',L':',L'\\',L'\0'}; + szDrive[0] = pContext->szFolderPath[0]; + SendDlgItemMessageW(pContext->hwndDlg, 14007, WM_SETTEXT, 0, (LPARAM) szDrive); + } + else + { + SendDlgItemMessageW(pContext->hwndDlg, 14007, WM_SETTEXT, 0, (LPARAM) pContext->szFolderPath); + } + pFolderName[0] = L'\\'; + /* get folder properties */ + if (GetFileAttributesExW(pContext->szFolderPath, GetFileExInfoStandard, (LPVOID)&FolderAttribute)) + { + if (FolderAttribute.dwFileAttributes & FILE_ATTRIBUTE_READONLY) + { + /* check readonly button */ + SendDlgItemMessage(pContext->hwndDlg, 14021, BM_SETCHECK, BST_CHECKED, 0); + } + + if (FolderAttribute.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) + { + /* check hidden button */ + SendDlgItemMessage(pContext->hwndDlg, 14022, BM_SETCHECK, BST_CHECKED, 0); + } + + if (FileTimeToLocalFileTime(&FolderAttribute.ftCreationTime, &ft)) + { + FileTimeToSystemTime(&ft, &dt); + swprintf (szBuffer, wFormat, dt.wDay, dt.wMonth, dt.wYear, dt.wHour, dt.wMinute); + SendDlgItemMessageW(pContext->hwndDlg, 14015, WM_SETTEXT, 0, (LPARAM) szBuffer); + } + } + /* now enumerate enumerate contents */ + wcscpy(szBuffer, pContext->szFolderPath); + CountFolderAndFiles((LPVOID)pContext); + wcscpy(pContext->szFolderPath, szBuffer); + /* set folder details */ + LoadStringW(shell32_hInstance, IDS_FILE_FOLDER, szFormat, sizeof(szFormat)/sizeof(WCHAR)); + szFormat[(sizeof(szFormat)/sizeof(WCHAR))-1] = L'\0'; + swprintf(szBuffer, szFormat, pContext->cFiles, pContext->cFolder); + SendDlgItemMessageW(pContext->hwndDlg, 14011, WM_SETTEXT, 0, (LPARAM) szBuffer); + + if (StrFormatByteSizeW(pContext->bSize.QuadPart, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + /* store folder size */ + SendDlgItemMessageW(pContext->hwndDlg, 14009, WM_SETTEXT, 0, (LPARAM) szBuffer); + } +} + + +INT_PTR +CALLBACK +FolderPropertiesGeneralDlg( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + LPPROPSHEETPAGEW ppsp; + PFOLDER_PROPERTIES_CONTEXT pContext; + HICON hIcon; + WIN32_FILE_ATTRIBUTE_DATA FolderAttribute; + LONG res; + LPPSHNOTIFY lppsn; + DWORD Attribute; + + switch(uMsg) + { + case WM_INITDIALOG: + ppsp = (LPPROPSHEETPAGEW)lParam; + if (ppsp == NULL) + break; + hIcon = LoadIconW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_FOLDER_OPEN)); + if (hIcon) + SendDlgItemMessageW(hwndDlg, 14000, STM_SETICON, (WPARAM)hIcon, 0); + + pContext = (FOLDER_PROPERTIES_CONTEXT *)SHAlloc(sizeof(FOLDER_PROPERTIES_CONTEXT)); + if (pContext) + { + ZeroMemory(pContext, sizeof(FOLDER_PROPERTIES_CONTEXT)); + pContext->hwndDlg = hwndDlg; + wcscpy(pContext->szFolderPath, (LPWSTR)ppsp->lParam); + SetWindowLongPtr(hwndDlg, DWL_USER, (LONG_PTR)pContext); + InitializeFolderGeneralDlg(pContext); + } + return TRUE; + case WM_COMMAND: + if (HIWORD(wParam) == BN_CLICKED) + { + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + } + break; + case WM_DESTROY: + pContext = (PFOLDER_PROPERTIES_CONTEXT)GetWindowLongPtr(hwndDlg, DWL_USER); + SHFree((LPVOID)pContext); + break; + case WM_NOTIFY: + pContext = (PFOLDER_PROPERTIES_CONTEXT)GetWindowLongPtr(hwndDlg, DWL_USER); + lppsn = (LPPSHNOTIFY) lParam; + if (lppsn->hdr.code == PSN_APPLY) + { + if (GetFileAttributesExW(pContext->szFolderPath, GetFileExInfoStandard, (LPVOID)&FolderAttribute)) + { + res = SendDlgItemMessageW(hwndDlg, 14021, BM_GETCHECK, 0, 0); + if (res == BST_CHECKED) + FolderAttribute.dwFileAttributes |= FILE_ATTRIBUTE_READONLY; + else + FolderAttribute.dwFileAttributes &= (~FILE_ATTRIBUTE_READONLY); + + res = SendDlgItemMessageW(hwndDlg, 14022, BM_GETCHECK, 0, 0); + if (res == BST_CHECKED) + FolderAttribute.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN; + else + FolderAttribute.dwFileAttributes &= (~FILE_ATTRIBUTE_HIDDEN); + + Attribute = FolderAttribute.dwFileAttributes & +(FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY); + + SetFileAttributesW(pContext->szFolderPath, Attribute); + } + SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR ); + return TRUE; + } + break; + } + return FALSE; +} + +static +BOOL +CALLBACK +FolderAddPropSheetPageProc(HPROPSHEETPAGE hpage, LPARAM lParam) +{ + PROPSHEETHEADERW *ppsh = (PROPSHEETHEADERW *)lParam; + if (ppsh != NULL && ppsh->nPages < MAX_PROPERTY_SHEET_PAGE) + { + ppsh->phpage[ppsh->nPages++] = hpage; + return TRUE; + } + return FALSE; +} + +BOOL +SH_ShowFolderProperties(LPWSTR pwszFolder, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST * apidl) +{ + HPROPSHEETPAGE hppages[MAX_PROPERTY_SHEET_PAGE]; + HPROPSHEETPAGE hpage; + PROPSHEETHEADERW psh; + BOOL ret; + WCHAR szName[MAX_PATH] = {0}; + HPSXA hpsx = NULL; + LPWSTR pFolderName; + CComPtr pDataObj; + + if (!PathIsDirectoryW(pwszFolder)) + return FALSE; + + pFolderName = wcsrchr(pwszFolder, L'\\'); + if (!pFolderName) + return FALSE; + + wcscpy(szName, pFolderName + 1); + + hpage = SH_CreatePropertySheetPage("SHELL_FOLDER_GENERAL_DLG", FolderPropertiesGeneralDlg, (LPARAM)pwszFolder, NULL); + if (!hpage) + return FALSE; + + ZeroMemory(&psh, sizeof(PROPSHEETHEADERW)); + hppages[psh.nPages] = hpage; + psh.nPages++; + psh.dwSize = sizeof(PROPSHEETHEADERW); + psh.dwFlags = PSH_PROPTITLE; + psh.hwndParent = NULL; + psh.phpage = hppages; + psh.pszCaption = szName; + + + if (SHCreateDataObject(pidlFolder, 1, apidl, NULL, IID_IDataObject, (void**)&pDataObj) == S_OK) + { + hpsx = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, L"Directory", MAX_PROPERTY_SHEET_PAGE-1, pDataObj); + if (hpsx) + { + SHAddFromPropSheetExtArray(hpsx, + (LPFNADDPROPSHEETPAGE)FolderAddPropSheetPageProc, + (LPARAM)&psh); + } + } + + ret = PropertySheetW(&psh); + + if (hpsx) + SHDestroyPropSheetExtArray(hpsx); + + if (ret < 0) + return FALSE; + else + return TRUE; +} + + diff --git a/reactos/dll/win32/shell32/folders.cpp b/reactos/dll/win32/shell32/folders.cpp new file mode 100644 index 00000000000..dc08d49a99d --- /dev/null +++ b/reactos/dll/win32/shell32/folders.cpp @@ -0,0 +1,380 @@ +/* + * Copyright 1997 Marcus Meissner + * Copyright 1998 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +WCHAR swShell32Name[MAX_PATH]; + +DWORD NumIconOverlayHandlers = 0; +IShellIconOverlayIdentifier ** Handlers = NULL; + +static HRESULT getIconLocationForFolder(LPCITEMIDLIST pidl, UINT uFlags, + LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags) +{ + int icon_idx; + WCHAR wszPath[MAX_PATH]; + WCHAR wszCLSIDValue[CHARS_IN_GUID]; + static const WCHAR shellClassInfo[] = { '.','S','h','e','l','l','C','l','a','s','s','I','n','f','o',0 }; + static const WCHAR iconFile[] = { 'I','c','o','n','F','i','l','e',0 }; + static const WCHAR clsid[] = { 'C','L','S','I','D',0 }; + static const WCHAR clsid2[] = { 'C','L','S','I','D','2',0 }; + static const WCHAR iconIndex[] = { 'I','c','o','n','I','n','d','e','x',0 }; + + if (SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, iconFile, + wszPath, MAX_PATH)) + { + WCHAR wszIconIndex[10]; + SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, iconIndex, + wszIconIndex, 10); + *piIndex = _wtoi(wszIconIndex); + } + else if (SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, clsid, + wszCLSIDValue, CHARS_IN_GUID) && + HCR_GetDefaultIconW(wszCLSIDValue, szIconFile, cchMax, &icon_idx)) + { + *piIndex = icon_idx; + } + else if (SHELL32_GetCustomFolderAttribute(pidl, shellClassInfo, clsid2, + wszCLSIDValue, CHARS_IN_GUID) && + HCR_GetDefaultIconW(wszCLSIDValue, szIconFile, cchMax, &icon_idx)) + { + *piIndex = icon_idx; + } + else + { + static const WCHAR folder[] = { 'F','o','l','d','e','r',0 }; + + if (!HCR_GetDefaultIconW(folder, szIconFile, cchMax, &icon_idx)) + { + lstrcpynW(szIconFile, swShell32Name, cchMax); + icon_idx = -IDI_SHELL_FOLDER; + } + + if (uFlags & GIL_OPENICON) + *piIndex = icon_idx<0? icon_idx-1: icon_idx+1; + else + *piIndex = icon_idx; + } + + return S_OK; +} + +void InitIconOverlays(void) +{ + HKEY hKey; + DWORD dwIndex, dwResult, dwSize; + WCHAR szName[MAX_PATH]; + WCHAR szValue[100]; + CLSID clsid; + IShellIconOverlayIdentifier * Overlay; + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers",0, KEY_READ, &hKey) != ERROR_SUCCESS) + return; + + if (RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &dwResult, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + return; + } + + Handlers = (IShellIconOverlayIdentifier **)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwResult * sizeof(IShellIconOverlayIdentifier*)); + if (!Handlers) + { + RegCloseKey(hKey); + return; + } + + dwIndex = 0; + + CoInitialize(0); + + do + { + dwSize = sizeof(szName) / sizeof(WCHAR); + dwResult = RegEnumKeyExW(hKey, dwIndex, szName, &dwSize, NULL, NULL, NULL, NULL); + + if (dwResult == ERROR_NO_MORE_ITEMS) + break; + + if (dwResult == ERROR_SUCCESS) + { + dwSize = sizeof(szValue) / sizeof(WCHAR); + if (RegGetValueW(hKey, szName, NULL, RRF_RT_REG_SZ, NULL, szValue, &dwSize) == ERROR_SUCCESS) + { + + CLSIDFromString(szValue, &clsid); + dwResult = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (LPVOID*)&Overlay); + if (dwResult == S_OK) + { + Handlers[NumIconOverlayHandlers] = Overlay; + NumIconOverlayHandlers++; + } + } + } + + dwIndex++; + + }while(1); + + RegCloseKey(hKey); +} + +BOOL +GetIconOverlay(LPCITEMIDLIST pidl, WCHAR * wTemp, int* pIndex) +{ + DWORD Index; + HRESULT hResult; + int Priority; + int HighestPriority; + ULONG IconIndex; + ULONG Flags; + WCHAR szPath[MAX_PATH]; + + if(!SHGetPathFromIDListW(pidl, szPath)) + return FALSE; + + + HighestPriority = 101; + IconIndex = NumIconOverlayHandlers; + for(Index = 0; Index < NumIconOverlayHandlers; Index++) + { + hResult = Handlers[Index]->IsMemberOf(szPath, SFGAO_FILESYSTEM); + if (hResult == S_OK) + { + hResult = Handlers[Index]->GetPriority(&Priority); + if (hResult == S_OK) + { + if (Priority < HighestPriority) + { + HighestPriority = Priority; + IconIndex = Index; + } + } + } + } + + if (IconIndex == NumIconOverlayHandlers) + return FALSE; + + hResult = Handlers[IconIndex]->GetOverlayInfo(wTemp, MAX_PATH, pIndex, &Flags); + + if (hResult == S_OK) + return TRUE; + else + return FALSE; +} + +/************************************************************************** +* IExtractIconW_Constructor +*/ +IExtractIconW* IExtractIconW_Constructor(LPCITEMIDLIST pidl) +{ + CComPtr initIcon; + IExtractIconW *extractIcon; + GUID const * riid; + int icon_idx; + UINT flags; + CHAR sTemp[MAX_PATH]; + WCHAR wTemp[MAX_PATH]; + LPITEMIDLIST pSimplePidl = ILFindLastID(pidl); + HRESULT hr; + + hr = SHCreateDefaultExtractIcon(IID_IDefaultExtractIconInit, (void **)&initIcon); + if (FAILED(hr)) + return NULL; + + hr = initIcon->QueryInterface(IID_IExtractIconW, (void **)&extractIcon); + if (FAILED(hr)) + return NULL; + + if (_ILIsDesktop(pSimplePidl)) + { + initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DESKTOP); + } + else if ((riid = _ILGetGUIDPointer(pSimplePidl))) + { + /* my computer and other shell extensions */ + static const WCHAR fmt[] = { 'C','L','S','I','D','\\', + '{','%','0','8','l','x','-','%','0','4','x','-','%','0','4','x','-', + '%','0','2','x','%','0','2','x','-','%','0','2','x', '%','0','2','x', + '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0 }; + WCHAR xriid[50]; + + swprintf(xriid, fmt, + riid->Data1, riid->Data2, riid->Data3, + riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3], + riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]); + + if (HCR_GetDefaultIconW(xriid, wTemp, MAX_PATH, &icon_idx)) + { + initIcon->SetNormalIcon(wTemp, icon_idx); + } + else + { + if (IsEqualGUID(*riid, CLSID_MyComputer)) + initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_COMPUTER); + else if (IsEqualGUID(*riid, CLSID_MyDocuments)) + initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_DOCUMENTS); + else if (IsEqualGUID(*riid, CLSID_NetworkPlaces)) + initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_NETWORK_PLACES); + else + initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_FOLDER); + } + } + + else if (_ILIsDrive (pSimplePidl)) + { + static const WCHAR drive[] = { 'D','r','i','v','e',0 }; + int icon_idx = -1; + + if (_ILGetDrive(pSimplePidl, sTemp, MAX_PATH)) + { + switch(GetDriveTypeA(sTemp)) + { + case DRIVE_REMOVABLE: icon_idx = IDI_SHELL_FLOPPY; break; + case DRIVE_CDROM: icon_idx = IDI_SHELL_CDROM; break; + case DRIVE_REMOTE: icon_idx = IDI_SHELL_NETDRIVE; break; + case DRIVE_RAMDISK: icon_idx = IDI_SHELL_RAMDISK; break; + case DRIVE_NO_ROOT_DIR: icon_idx = IDI_SHELL_CDROM; break; + } + } + + if (icon_idx != -1) + { + initIcon->SetNormalIcon(swShell32Name, -icon_idx); + } + else + { + if (HCR_GetDefaultIconW(drive, wTemp, MAX_PATH, &icon_idx)) + initIcon->SetNormalIcon(wTemp, icon_idx); + else + initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DRIVE); + } + } + + else if (_ILIsFolder (pSimplePidl)) + { + if (SUCCEEDED(getIconLocationForFolder( + pidl, 0, wTemp, MAX_PATH, + &icon_idx, + &flags))) + { + initIcon->SetNormalIcon(wTemp, icon_idx); + } + if (SUCCEEDED(getIconLocationForFolder( + pidl, GIL_DEFAULTICON, wTemp, MAX_PATH, + &icon_idx, + &flags))) + { + initIcon->SetDefaultIcon(wTemp, icon_idx); + } + if (SUCCEEDED(getIconLocationForFolder( + pidl, GIL_FORSHORTCUT, wTemp, MAX_PATH, + &icon_idx, + &flags))) + { + initIcon->SetShortcutIcon(wTemp, icon_idx); + } + if (SUCCEEDED(getIconLocationForFolder( + pidl, GIL_OPENICON, wTemp, MAX_PATH, + &icon_idx, + &flags))) + { + initIcon->SetOpenIcon(wTemp, icon_idx); + } + } + else + { + BOOL found = FALSE; + + if (_ILIsCPanelStruct(pSimplePidl)) + { + if (SUCCEEDED(CPanel_GetIconLocationW(pSimplePidl, wTemp, MAX_PATH, &icon_idx))) + found = TRUE; + } + else if (_ILGetExtension(pSimplePidl, sTemp, MAX_PATH)) + { + if (HCR_MapTypeToValueA(sTemp, sTemp, MAX_PATH, TRUE) + && HCR_GetDefaultIconA(sTemp, sTemp, MAX_PATH, &icon_idx)) + { + if (!lstrcmpA("%1", sTemp)) /* icon is in the file */ + { + SHGetPathFromIDListW(pidl, wTemp); + icon_idx = 0; + } + else + { + MultiByteToWideChar(CP_ACP, 0, sTemp, -1, wTemp, MAX_PATH); + } + + found = TRUE; + } + else if (!lstrcmpiA(sTemp, "lnkfile")) + { + /* extract icon from shell shortcut */ + CComPtr dsf; + CComPtr psl; + + if (SUCCEEDED(SHGetDesktopFolder(&dsf))) + { + HRESULT hr = dsf->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*)&pidl, IID_IShellLinkW, NULL, (LPVOID *)&psl); + + if (SUCCEEDED(hr)) + { + hr = psl->GetIconLocation(wTemp, MAX_PATH, &icon_idx); + + if (SUCCEEDED(hr) && *sTemp) + found = TRUE; + + } + } + } + } + + if (!found) + /* default icon */ + initIcon->SetNormalIcon(swShell32Name, 0); + else + initIcon->SetNormalIcon(wTemp, icon_idx); + } + + return extractIcon; +} + +/************************************************************************** +* IExtractIconA_Constructor +*/ +IExtractIconA* IExtractIconA_Constructor(LPCITEMIDLIST pidl) +{ + IExtractIconW *extractIconW; + IExtractIconA *extractIconA; + HRESULT hr; + + extractIconW = IExtractIconW_Constructor(pidl); + if (!extractIconW) + return NULL; + + hr = extractIconW->QueryInterface(IID_IExtractIconA, (void **)&extractIconA); + extractIconW->Release(); + if (FAILED(hr)) + return NULL; + return extractIconA; +} diff --git a/reactos/dll/win32/shell32/fprop.cpp b/reactos/dll/win32/shell32/fprop.cpp new file mode 100644 index 00000000000..7eee167172a --- /dev/null +++ b/reactos/dll/win32/shell32/fprop.cpp @@ -0,0 +1,943 @@ +/* + * Shell Library Functions + * + * Copyright 2005 Johannes Anderwald + * + * 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +#define MAX_PROPERTY_SHEET_PAGE 32 + +typedef struct _LANGANDCODEPAGE_ +{ + WORD lang; + WORD code; +} LANGANDCODEPAGE, *LPLANGANDCODEPAGE; + +EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj); + +static LONG SH_GetAssociatedApplication(WCHAR *fileext, WCHAR *wAssocApp) +{ + WCHAR wDataType[MAX_PATH] = {0}; + HKEY hkey; + LONG result; + DWORD dwLen = MAX_PATH * sizeof(WCHAR); + + wAssocApp[0] = '\0'; + RegCreateKeyExW(HKEY_CLASSES_ROOT, fileext, 0, NULL, 0, KEY_READ, NULL, &hkey, NULL); + result = RegQueryValueExW(hkey, L"", NULL, NULL, (LPBYTE)wDataType, &dwLen); + RegCloseKey(hkey); + + if (result == ERROR_SUCCESS) + { + wcscat(wDataType, L"\\shell\\open\\command"); + dwLen = MAX_PATH * sizeof(WCHAR); + RegCreateKeyExW(HKEY_CLASSES_ROOT, wDataType, 0, NULL, 0, KEY_READ, NULL, &hkey, NULL); + result = (RegQueryValueExW(hkey, NULL, NULL, NULL, (LPBYTE)wAssocApp, &dwLen)); + RegCloseKey(hkey); + + if (result != ERROR_SUCCESS) + { + /* FIXME: Make it return full path instead of + notepad.exe "%1" + %systemroot%\notepad.exe "%1" + etc + Maybe there is code to do that somewhere? + dll\win32\shell32\shlexec.c for example? + */ + wAssocApp[0] = '\0'; + } + } + + return result; +} + +static LONG SH_FileGeneralOpensWith(HWND hwndDlg, WCHAR *fileext) +{ + HWND hDlgCtrl; + LONG result; + WCHAR wAppName[MAX_PATH] = {0}; + WCHAR wAssocApp[MAX_PATH] = {0}; + + hDlgCtrl = GetDlgItem(hwndDlg, 14007); + result = SH_GetAssociatedApplication(fileext, wAssocApp); + + if (result == ERROR_SUCCESS) + { + _wsplitpath(wAssocApp, NULL, NULL, wAppName, NULL); + + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wAppName); + } + + return result; +} + +/************************************************************************* + * + * SH_CreatePropertySheetPage [Internal] + * + * creates a property sheet page from an resource name + * + */ + +HPROPSHEETPAGE +SH_CreatePropertySheetPage(LPCSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle) +{ + HRSRC hRes; + LPVOID lpsztemplate; + PROPSHEETPAGEW ppage; + + if (resname == NULL) + return (HPROPSHEETPAGE)0; + + hRes = FindResourceA(shell32_hInstance, resname, (LPSTR)RT_DIALOG); + + if (hRes == NULL) + { + ERR("failed to find resource name\n"); + return (HPROPSHEETPAGE)0; + } + + lpsztemplate = LoadResource(shell32_hInstance, hRes); + + if (lpsztemplate == NULL) + return (HPROPSHEETPAGE)0; + + memset(&ppage, 0x0, sizeof(PROPSHEETPAGEW)); + ppage.dwSize = sizeof(PROPSHEETPAGEW); + ppage.dwFlags = PSP_DLGINDIRECT; + ppage.pResource = (DLGTEMPLATE *)lpsztemplate; + ppage.pfnDlgProc = dlgproc; + ppage.lParam = lParam; + ppage.pszTitle = szTitle; + + if (szTitle) + { + ppage.dwFlags |= PSP_USETITLE; + } + + return CreatePropertySheetPageW(&ppage); +} + +/************************************************************************* + * + * SH_FileGeneralFileType [Internal] + * + * retrieves file extension description from registry and sets it in dialog + * + * TODO: retrieve file extension default icon and load it + * find executable name from registry, retrieve description from executable + */ + +BOOL +SH_FileGeneralSetFileType(HWND hwndDlg, WCHAR *filext) +{ + WCHAR name[MAX_PATH]; + WCHAR value[MAX_PATH]; + DWORD lname = MAX_PATH; + DWORD lvalue = MAX_PATH; + HKEY hKey; + LONG result; + HWND hDlgCtrl; + + TRACE("fileext %s\n", debugstr_w(filext)); + + if (filext == NULL) + return FALSE; + + hDlgCtrl = GetDlgItem(hwndDlg, 14005); + + if (hDlgCtrl == NULL) + return FALSE; + + if (RegOpenKeyW(HKEY_CLASSES_ROOT, filext, &hKey) != ERROR_SUCCESS) + { + /* the file extension is unknown, so default to string "FileExtension File" */ + SendMessageW(hDlgCtrl, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)value); + swprintf(name, L"%s %s", &filext[1], value); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)name); + return TRUE; + } + + result = RegEnumValueW(hKey, 0, name, &lname, NULL, NULL, (LPBYTE)value, &lvalue); + RegCloseKey(hKey); + + if (result != ERROR_SUCCESS) + return FALSE; + + if (RegOpenKeyW(HKEY_CLASSES_ROOT, value, &hKey) == ERROR_SUCCESS) + { + if (RegLoadMUIStringW(hKey, L"FriendlyTypeName", value, MAX_PATH, NULL, 0, NULL) != ERROR_SUCCESS) + { + lvalue = lname = MAX_PATH; + result = RegEnumValueW(hKey, 0, name, &lname, NULL, NULL, (LPBYTE)value, &lvalue); + } + + lname = MAX_PATH; + + if (RegGetValueW(hKey, L"DefaultIcon", NULL, RRF_RT_REG_SZ, NULL, name, &lname) == ERROR_SUCCESS) + { + UINT IconIndex; + WCHAR szBuffer[MAX_PATH]; + WCHAR *Offset; + HICON hIcon = 0; + HRSRC hResource; + LPVOID pResource = NULL; + HGLOBAL hGlobal; + HINSTANCE hLibrary; + Offset = wcsrchr(name, L','); + + if (Offset) + { + IconIndex = _wtoi(Offset + 2); + *Offset = L'\0'; + name[MAX_PATH - 1] = L'\0'; + + if (ExpandEnvironmentStringsW(name, szBuffer, MAX_PATH)) + { + szBuffer[MAX_PATH - 1] = L'\0'; + hLibrary = LoadLibraryExW(szBuffer, NULL, LOAD_LIBRARY_AS_DATAFILE); + if (hLibrary) + { + hResource = FindResourceW(hLibrary, MAKEINTRESOURCEW(IconIndex), (LPCWSTR)RT_ICON); + if (hResource) + { + hGlobal = LoadResource(shell32_hInstance, hResource); + if (hGlobal) + { + pResource = LockResource(hGlobal); + if (pResource != NULL) + { + hIcon = CreateIconFromResource((LPBYTE)pResource, SizeofResource(shell32_hInstance, hResource), TRUE, 0x00030000); + TRACE("hIcon %p,- szBuffer %s IconIndex %u error %u icon %p hResource %p pResource %p\n", + hIcon, + debugstr_w(szBuffer), + IconIndex, + MAKEINTRESOURCEW(IconIndex), + hResource, + pResource); + SendDlgItemMessageW(hwndDlg, 14000, STM_SETICON, (WPARAM)hIcon, 0); + } + } + } + FreeLibrary(hLibrary); + } + } + } + } + RegCloseKey(hKey); + } + + /* file extension type */ + value[MAX_PATH - 1] = L'\0'; + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)value); + + return TRUE; +} + +/************************************************************************* + * + * SHFileGeneralGetFileTimeString [Internal] + * + * formats a given LPFILETIME struct into readable user format + */ + +BOOL +SHFileGeneralGetFileTimeString(LPFILETIME lpFileTime, WCHAR *lpResult) +{ + FILETIME ft; + SYSTEMTIME dt; + WORD wYear; + static const WCHAR wFormat[] = { + '%', '0', '2', 'd', '/', '%', '0', '2', 'd', '/', '%', '0', '4', 'd', + ' ', ' ', '%', '0', '2', 'd', ':', '%', '0', '2', 'u', 0 }; + + if (lpFileTime == NULL || lpResult == NULL) + return FALSE; + + if (!FileTimeToLocalFileTime(lpFileTime, &ft)) + return FALSE; + + FileTimeToSystemTime(&ft, &dt); + + wYear = dt.wYear; + + /* ddmmyy */ + swprintf(lpResult, wFormat, dt.wDay, dt.wMonth, wYear, dt.wHour, dt.wMinute); + + TRACE("result %s\n", debugstr_w(lpResult)); + return TRUE; +} + +/************************************************************************* + * + * SH_FileGeneralSetText [Internal] + * + * sets file path string and filename string + * + */ + +BOOL +SH_FileGeneralSetText(HWND hwndDlg, WCHAR *lpstr) +{ + int flength; + int plength; + WCHAR *lpdir; + WCHAR buff[MAX_PATH]; + HWND hDlgCtrl; + + if (lpstr == NULL) + return FALSE; + + lpdir = wcsrchr(lpstr, '\\'); /* find the last occurence of '\\' */ + + plength = wcslen(lpstr); + flength = wcslen(lpdir); + + if (lpdir) + { + /* location text field */ + wcsncpy(buff, lpstr, plength - flength); + buff[plength - flength] = UNICODE_NULL; + + if (wcslen(buff) == 2) + { + wcscat(buff, L"\\"); + } + + hDlgCtrl = GetDlgItem(hwndDlg, 14009); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff); + } + + if (flength > 1) + { + /* text filename field */ + wcsncpy(buff, &lpdir[1], flength); + hDlgCtrl = GetDlgItem(hwndDlg, 14001); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff); + } + + return TRUE; +} + +/************************************************************************* + * + * SH_FileGeneralSetFileSizeTime [Internal] + * + * retrieves file information from file and sets in dialog + * + */ + +BOOL +SH_FileGeneralSetFileSizeTime(HWND hwndDlg, WCHAR *lpfilename, PULARGE_INTEGER lpfilesize) +{ + BOOL result; + HANDLE hFile; + FILETIME create_time; + FILETIME accessed_time; + FILETIME write_time; + WCHAR resultstr[MAX_PATH]; + HWND hDlgCtrl; + LARGE_INTEGER file_size; + + if (lpfilename == NULL) + return FALSE; + + hFile = CreateFileW(lpfilename, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hFile == INVALID_HANDLE_VALUE) + { + WARN("failed to open file %s\n", debugstr_w(lpfilename)); + return FALSE; + } + + result = GetFileTime(hFile, &create_time, &accessed_time, &write_time); + + if (!result) + { + WARN("GetFileTime failed\n"); + return FALSE; + } + + if (SHFileGeneralGetFileTimeString(&create_time, resultstr)) + { + hDlgCtrl = GetDlgItem(hwndDlg, 14015); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr); + } + + if (SHFileGeneralGetFileTimeString(&accessed_time, resultstr)) + { + hDlgCtrl = GetDlgItem(hwndDlg, 14019); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr); + } + + if (SHFileGeneralGetFileTimeString(&write_time, resultstr)) + { + hDlgCtrl = GetDlgItem(hwndDlg, 14017); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr); + } + + if (!GetFileSizeEx(hFile, &file_size)) + { + WARN("GetFileSize failed\n"); + CloseHandle(hFile); + return FALSE; + } + + CloseHandle(hFile); + + if (!StrFormatByteSizeW(file_size.QuadPart, + resultstr, + sizeof(resultstr) / sizeof(WCHAR))) + return FALSE; + + hDlgCtrl = GetDlgItem(hwndDlg, 14011); + + TRACE("result size %u resultstr %s\n", file_size.QuadPart, debugstr_w(resultstr)); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)resultstr); + + if (lpfilesize) + lpfilesize->QuadPart = (ULONGLONG)file_size.QuadPart; + + return TRUE; +} + +/************************************************************************* + * + * SH_SetFileVersionText [Internal] + * + * + */ + +BOOL +SH_FileVersionQuerySetText(HWND hwndDlg, DWORD dlgId, LPVOID pInfo, WCHAR *text, WCHAR **resptr) +{ + UINT reslen; + HWND hDlgCtrl; + + if (hwndDlg == NULL || resptr == NULL || text == NULL) + return FALSE; + + if (VerQueryValueW(pInfo, text, (LPVOID *)resptr, &reslen)) + { + /* file description property */ + hDlgCtrl = GetDlgItem(hwndDlg, dlgId); + TRACE("%s :: %s\n", debugstr_w(text), debugstr_w(*resptr)); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)0, (LPARAM)*resptr); + return TRUE; + } + + return FALSE; +} + +/************************************************************************* + * + * SH_FileVersionQuerySetListText [Internal] + * + * retrieves a version string and adds it to listbox + * + */ + +BOOL +SH_FileVersionQuerySetListText(HWND hwndDlg, LPVOID pInfo, const WCHAR *text, WCHAR **resptr, WORD lang, WORD code) +{ + UINT reslen; + HWND hDlgCtrl; + UINT index; + static const WCHAR wFormat[] = { + '\\', 'S', 't', 'r', 'i', 'n', 'g', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o', + '\\', '%', '0', '4', 'x', '%', '0', '4', 'x', '\\', '%', 's', 0 }; + WCHAR buff[256]; + + TRACE("text %s, resptr %p hwndDlg %p\n", debugstr_w(text), resptr, hwndDlg); + + if (hwndDlg == NULL || resptr == NULL || text == NULL) + return FALSE; + + swprintf(buff, wFormat, lang, code, text); + + if (VerQueryValueW(pInfo, buff, (LPVOID *)resptr, &reslen)) + { + /* listbox name property */ + hDlgCtrl = GetDlgItem(hwndDlg, 14009); + TRACE("%s :: %s\n", debugstr_w(text), debugstr_w(*resptr)); + index = SendMessageW(hDlgCtrl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)text); + SendMessageW(hDlgCtrl, LB_SETITEMDATA, (WPARAM)index, (LPARAM)(WCHAR *)*resptr); + return TRUE; + } + + return FALSE; +} + +/************************************************************************* + * + * SH_FileVersionInitialize [Internal] + * + * sets all file version properties in dialog + */ + +BOOL +SH_FileVersionInitialize(HWND hwndDlg, WCHAR *lpfilename) +{ + LPVOID pBuf; + DWORD versize; + DWORD handle; + LPVOID info = NULL; + UINT infolen; + WCHAR buff[256]; + HWND hDlgCtrl; + WORD lang = 0; + WORD code = 0; + LPLANGANDCODEPAGE lplangcode; + WCHAR *str; + static const WCHAR wVersionFormat[] = { + '%', 'd', '.', '%', 'd', '.', '%', 'd', '.', '%', 'd', 0 }; + static const WCHAR wFileDescriptionFormat[] = { + '\\', 'S', 't', 'r', 'i', 'n', 'g', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o', + '\\', '%', '0', '4', 'x', '%', '0', '4', 'x', + '\\', 'F', 'i', 'l', 'e', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 0 }; + static const WCHAR wLegalCopyrightFormat[] = { + '\\', 'S', 't', 'r', 'i', 'n', 'g', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o', + '\\', '%', '0', '4', 'x', '%', '0', '4', 'x', + '\\', 'L', 'e', 'g', 'a', 'l', 'C', 'o', 'p', 'y', 'r', 'i', 'g', 'h', 't', 0 }; + static const WCHAR wTranslation[] = { + 'V', 'a', 'r', 'F', 'i', 'l', 'e', 'I', 'n', 'f', 'o', + '\\', 'T', 'r', 'a', 'n', 's', 'l', 'a', 't', 'i', 'o', 'n', 0 }; + static const WCHAR wCompanyName[] = { + 'C', 'o', 'm', 'p', 'a', 'n', 'y', 'N', 'a', 'm', 'e', 0 }; + static const WCHAR wFileVersion[] = { + 'F', 'i', 'l', 'e', 'V', 'e', 'r', 's', 'i', 'o', 'n', 0 }; + static const WCHAR wInternalName[] = { + 'I', 'n', 't', 'e', 'r', 'n', 'a', 'l', 'N', 'a', 'm', 'e', 0 }; + static const WCHAR wOriginalFilename[] = { + 'O', 'r', 'i', 'g', 'i', 'n', 'a', 'l', 'F', 'i', 'l', 'e', 'n', 'a', 'm', 'e', 0 }; + static const WCHAR wProductName[] = { + 'P', 'r', 'o', 'd', 'u', 'c', 't', 'N', 'a', 'm', 'e', 0 }; + static const WCHAR wProductVersion[] = { + 'P', 'r', 'o', 'd', 'u', 'c', 't', 'V', 'e', 'r', 's', 'i', 'o', 'n', 0 }; + static const WCHAR wSlash[] = { '\\', 0 }; + + if (lpfilename == 0) + return FALSE; + + if (!(versize = GetFileVersionInfoSizeW(lpfilename, &handle))) + { + WARN("GetFileVersionInfoSize failed\n"); + return FALSE; + } + + if (!(pBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, versize))) + { + WARN("HeapAlloc failed bytes %x\n", versize); + return FALSE; + } + + if (!GetFileVersionInfoW(lpfilename, handle, versize, pBuf)) + { + HeapFree(GetProcessHeap(), 0, pBuf); + return FALSE; + } + + if (VerQueryValueW(pBuf, const_cast(wSlash), &info, &infolen)) + { + VS_FIXEDFILEINFO *inf = (VS_FIXEDFILEINFO *)info; + swprintf(buff, wVersionFormat, HIWORD(inf->dwFileVersionMS), + LOWORD(inf->dwFileVersionMS), + HIWORD(inf->dwFileVersionLS), + LOWORD(inf->dwFileVersionLS)); + hDlgCtrl = GetDlgItem(hwndDlg, 14001); + TRACE("MS %x LS %x res %s \n", inf->dwFileVersionMS, inf->dwFileVersionLS, debugstr_w(buff)); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)buff); + } + + if (VerQueryValueW(pBuf, const_cast(wTranslation), (LPVOID *)&lplangcode, &infolen)) + { + /* FIXME find language from current locale / if not available, + * default to english + * for now default to first available language + */ + lang = lplangcode->lang; + code = lplangcode->code; + } + + swprintf(buff, wFileDescriptionFormat, lang, code); + SH_FileVersionQuerySetText(hwndDlg, 14003, pBuf, buff, &str); + + swprintf(buff, wLegalCopyrightFormat, lang, code); + SH_FileVersionQuerySetText(hwndDlg, 14005, pBuf, buff, &str); + + /* listbox properties */ + SH_FileVersionQuerySetListText(hwndDlg, pBuf, wCompanyName, &str, lang, code); + SH_FileVersionQuerySetListText(hwndDlg, pBuf, wFileVersion, &str, lang, code); + SH_FileVersionQuerySetListText(hwndDlg, pBuf, wInternalName, &str, lang, code); + + /* FIXME insert language identifier */ + + SH_FileVersionQuerySetListText(hwndDlg, pBuf, wOriginalFilename, &str, lang, code); + SH_FileVersionQuerySetListText(hwndDlg, pBuf, wProductName, &str, lang, code); + SH_FileVersionQuerySetListText(hwndDlg, pBuf, wProductVersion, &str, lang, code); + SetWindowLongPtr(hwndDlg, DWL_USER, (LONG_PTR)pBuf); + + /* select first item */ + hDlgCtrl = GetDlgItem(hwndDlg, 14009); + SendMessageW(hDlgCtrl, LB_SETCURSEL, 0, 0); + str = (WCHAR *) SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)0, (LPARAM)NULL); + hDlgCtrl = GetDlgItem(hwndDlg, 14010); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)str); + + return TRUE; +} + +/************************************************************************* + * + * SH_FileVersionDlgProc + * + * wnd proc of 'Version' property sheet page + */ + +INT_PTR +CALLBACK +SH_FileVersionDlgProc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LPPROPSHEETPAGE ppsp; + WCHAR *lpstr; + LPVOID buf; + + switch (uMsg) + { + case WM_INITDIALOG: + ppsp = (LPPROPSHEETPAGE)lParam; + + if (ppsp == NULL) + break; + + TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %x\n", hwndDlg, lParam, ppsp->lParam); + + lpstr = (WCHAR *)ppsp->lParam; + + if (lpstr == NULL) + break; + + return SH_FileVersionInitialize(hwndDlg, lpstr); + + case WM_COMMAND: + if (LOWORD(wParam) == 14009 && HIWORD(wParam) == LBN_DBLCLK) + { + HWND hDlgCtrl; + LRESULT lresult; + WCHAR *str; + + hDlgCtrl = GetDlgItem(hwndDlg, 14009); + lresult = SendMessageW(hDlgCtrl, LB_GETCURSEL, (WPARAM)NULL, (LPARAM)NULL); + + if (lresult == LB_ERR) + break; + + str = (WCHAR *) SendMessageW(hDlgCtrl, LB_GETITEMDATA, (WPARAM)lresult, (LPARAM)NULL); + + if (str == NULL) + break; + + hDlgCtrl = GetDlgItem(hwndDlg, 14010); + TRACE("hDlgCtrl %x string %s \n", hDlgCtrl, debugstr_w(str)); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)str); + + return TRUE; + } + break; + + case WM_DESTROY: + buf = (LPVOID) GetWindowLongPtr(hwndDlg, DWL_USER); + HeapFree(GetProcessHeap(), 0, buf); + break; + + default: + break; + } + + return FALSE; +} + +/************************************************************************* + * + * SH_FileGeneralDlgProc + * + * wnd proc of 'General' property sheet page + * + */ + +INT_PTR +CALLBACK +SH_FileGeneralDlgProc(HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LPPROPSHEETPAGEW ppsp; + WCHAR *lpstr; + + switch (uMsg) + { + case WM_INITDIALOG: + ppsp = (LPPROPSHEETPAGEW)lParam; + + if (ppsp == NULL) + break; + + TRACE("WM_INITDIALOG hwnd %p lParam %p ppsplParam %S\n", hwndDlg, lParam, ppsp->lParam); + + lpstr = (WCHAR *)ppsp->lParam; + + if (lpstr == NULL) + { + ERR("no filename\n"); + break; + } + + /* set general text properties filename filelocation and icon */ + SH_FileGeneralSetText(hwndDlg, lpstr); + + /* enumerate file extension from registry and application which opens it */ + SH_FileGeneralSetFileType(hwndDlg, wcsrchr(lpstr, '.')); + + /* set opens with */ + SH_FileGeneralOpensWith(hwndDlg, wcsrchr(lpstr, '.')); + + /* set file time create/modfied/accessed */ + SH_FileGeneralSetFileSizeTime(hwndDlg, lpstr, NULL); + + return TRUE; + + default: + break; + } + + return FALSE; +} + +BOOL +CALLBACK +AddShellPropSheetExCallback(HPROPSHEETPAGE hPage, + LPARAM lParam) +{ + PROPSHEETHEADERW *pinfo = (PROPSHEETHEADERW *)lParam; + + if (pinfo->nPages < MAX_PROPERTY_SHEET_PAGE) + { + pinfo->phpage[pinfo->nPages++] = hPage; + return TRUE; + } + + return FALSE; +} + +int +EnumPropSheetExt(LPWSTR wFileName, PROPSHEETHEADERW *pinfo, int NumPages, HPSXA *hpsxa, IDataObject *pDataObj) +{ + WCHAR szName[MAX_PATH] = { 0 }; + WCHAR *pOffset; + UINT Length; + DWORD dwName; + int Pages; + CLSID clsid; + + pOffset = wcsrchr(wFileName, L'.'); + + if (!pOffset) + { + Length = wcslen(szName); + + if (Length + 6 > sizeof(szName) / sizeof(szName[0])) + return 0; + + if (CLSIDFromString(wFileName, &clsid) == NOERROR) + { + wcscpy(szName, L"CLSID\\"); + wcscpy(&szName[6], wFileName); + } + else + { + wcscpy(szName, wFileName); + } + } + else + { + Length = wcslen(pOffset); + + if (Length >= sizeof(szName) / sizeof(szName[0])) + return 0; + + wcscpy(szName, pOffset); + } + + TRACE("EnumPropSheetExt szName %s\n", debugstr_w(szName)); + + hpsxa[0] = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, szName, NumPages, pDataObj); + Pages = SHAddFromPropSheetExtArray(hpsxa[0], AddShellPropSheetExCallback, (LPARAM)pinfo); + + hpsxa[1] = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, L"*", NumPages-Pages, pDataObj); + Pages += SHAddFromPropSheetExtArray(hpsxa[1], AddShellPropSheetExCallback, (LPARAM)pinfo); + + hpsxa[2] = NULL; + + if (pOffset) + { + /* try to load property sheet handlers from prog id key */ + dwName = sizeof(szName); + + if (RegGetValueW(HKEY_CLASSES_ROOT, pOffset, NULL, RRF_RT_REG_SZ, NULL, szName, &dwName) == ERROR_SUCCESS) + { + TRACE("EnumPropSheetExt szName %s, pOffset %s\n", debugstr_w(szName), debugstr_w(pOffset)); + szName[(sizeof(szName) / sizeof(WCHAR)) - 1] = L'\0'; + hpsxa[2] = SHCreatePropSheetExtArrayEx(HKEY_CLASSES_ROOT, szName, NumPages - Pages, pDataObj); + Pages += SHAddFromPropSheetExtArray(hpsxa[2], AddShellPropSheetExCallback, (LPARAM)pinfo); + } + } + + return Pages; +} + +/************************************************************************* + * + * SH_ShowPropertiesDialog + * + * called from ShellExecuteExW32 + * + * lpf contains (quoted) path of folder/file + * + * TODO: provide button change application type if file has registered type + * make filename field editable and apply changes to filename on close + */ + +BOOL +SH_ShowPropertiesDialog(WCHAR *lpf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST *apidl) +{ + PROPSHEETHEADERW pinfo; + HPROPSHEETPAGE hppages[MAX_PROPERTY_SHEET_PAGE]; + WCHAR wFileName[MAX_PATH]; + DWORD dwHandle = 0; + WCHAR *pFileName; + HPSXA hpsxa[3]; + INT_PTR res; + CComPtr pDataObj; + HRESULT hResult; + + TRACE("SH_ShowPropertiesDialog entered filename %s\n", debugstr_w(lpf)); + + if (lpf == NULL) + return FALSE; + + if (!wcslen(lpf)) + return FALSE; + + memset(hppages, 0x0, sizeof(HPROPSHEETPAGE) * MAX_PROPERTY_SHEET_PAGE); + + if (lpf[0] == '"') + { + /* remove quotes from lpf */ + LPCWSTR src = lpf + 1; + LPWSTR dst = wFileName; + + while (*src && *src != '"') + *dst++ = *src++; + + *dst = '\0'; + } + else + { + wcscpy(wFileName, lpf); + } + + if (PathIsDirectoryW(wFileName)) + { + return SH_ShowFolderProperties(wFileName, pidlFolder, apidl); + } + + if (wcslen(wFileName) == 3) + { + return SH_ShowDriveProperties(wFileName, pidlFolder, apidl); + } + + pFileName = wcsrchr(wFileName, '\\'); + + if (!pFileName) + pFileName = wFileName; + else + pFileName++; + + memset(&pinfo, 0x0, sizeof(PROPSHEETHEADERW)); + pinfo.dwSize = sizeof(PROPSHEETHEADERW); + pinfo.dwFlags = PSH_NOCONTEXTHELP | PSH_PROPTITLE; + pinfo.phpage = hppages; + pinfo.pszCaption = pFileName; + + hppages[pinfo.nPages] = + SH_CreatePropertySheetPage("SHELL_FILE_GENERAL_DLG", + SH_FileGeneralDlgProc, + (LPARAM)wFileName, + NULL); + + if (hppages[pinfo.nPages]) + pinfo.nPages++; + + hResult = SHCreateDataObject(pidlFolder, 1, apidl, NULL, IID_IDataObject, (LPVOID *)&pDataObj); + + if (hResult == S_OK) + { + if (!EnumPropSheetExt(wFileName, &pinfo, MAX_PROPERTY_SHEET_PAGE - 1, hpsxa, pDataObj)) + { + hpsxa[0] = NULL; + hpsxa[1] = NULL; + hpsxa[2] = NULL; + } + } + + if (GetFileVersionInfoSizeW(lpf, &dwHandle)) + { + hppages[pinfo.nPages] = + SH_CreatePropertySheetPage("SHELL_FILE_VERSION_DLG", + SH_FileVersionDlgProc, + (LPARAM)wFileName, + NULL); + if (hppages[pinfo.nPages]) + pinfo.nPages++; + } + + res = PropertySheetW(&pinfo); + + if (hResult == S_OK) + { + SHDestroyPropSheetExtArray(hpsxa[0]); + SHDestroyPropSheetExtArray(hpsxa[1]); + SHDestroyPropSheetExtArray(hpsxa[2]); + } + + return (res != -1); +} + +/*EOF */ diff --git a/reactos/dll/win32/shell32/icon_res.rc b/reactos/dll/win32/shell32/icon_res.rc index 1f644ae6cf8..4b7b68a7721 100644 --- a/reactos/dll/win32/shell32/icon_res.rc +++ b/reactos/dll/win32/shell32/icon_res.rc @@ -45,7 +45,9 @@ IDI_SHELL_FIND_IN_FILE ICON "res/icons/134.ico" IDI_SHELL_OPEN_WITH ICON "res/icons/135.ico" IDI_SHELL_CONTROL_PANEL3 ICON "res/icons/137.ico" IDI_SHELL_PRINTER2 ICON "res/icons/138.ico" -/* TODO: 139.ico, 140.ico, 141.ico, 142.ico, 143.ico, 144,ico, 145.ico, 146.ico, 147.ico, 148.ico */ +/* TODO: 139.ico, 140.ico, 141.ico */ +IDI_SHELL_TRASH_FILE ICON "res/icons/33.ico" //142 +/* TODO 143.ico, 144,ico, 145.ico, 146.ico, 147.ico, 148.ico */ IDI_SHELL_INF_FILE ICON "res/icons/151.ico" IDI_SHELL_TEXT_FILE ICON "res/icons/152.ico" IDI_SHELL_BAT_FILE ICON "res/icons/153.ico" diff --git a/reactos/dll/win32/shell32/iconcache.cpp b/reactos/dll/win32/shell32/iconcache.cpp new file mode 100644 index 00000000000..b4f0076faee --- /dev/null +++ b/reactos/dll/win32/shell32/iconcache.cpp @@ -0,0 +1,936 @@ +/* + * shell icon cache (SIC) + * + * Copyright 1998, 1999 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/********************** THE ICON CACHE ********************************/ + +#define INVALID_INDEX -1 + +typedef struct +{ + LPWSTR sSourceFile; /* file (not path!) containing the icon */ + DWORD dwSourceIndex; /* index within the file, if it is a resoure ID it will be negated */ + DWORD dwListIndex; /* index within the iconlist */ + DWORD dwFlags; /* GIL_* flags */ + DWORD dwAccessTime; +} SIC_ENTRY, * LPSIC_ENTRY; + +static HDPA sic_hdpa = 0; + +namespace +{ +extern CRITICAL_SECTION SHELL32_SicCS; +CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &SHELL32_SicCS, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_SicCS") } +}; +CRITICAL_SECTION SHELL32_SicCS = { &critsect_debug, -1, 0, 0, 0, 0 }; +} + +/***************************************************************************** + * SIC_CompareEntries + * + * NOTES + * Callback for DPA_Search + */ +static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam) +{ LPSIC_ENTRY e1 = (LPSIC_ENTRY)p1, e2 = (LPSIC_ENTRY)p2; + + TRACE("%p %p %8lx\n", p1, p2, lparam); + + /* Icons in the cache are keyed by the name of the file they are + * loaded from, their resource index and the fact if they have a shortcut + * icon overlay or not. + */ + if (e1->dwSourceIndex != e2->dwSourceIndex || /* first the faster one */ + (e1->dwFlags & GIL_FORSHORTCUT) != (e2->dwFlags & GIL_FORSHORTCUT)) + return 1; + + if (wcsicmp(e1->sSourceFile,e2->sSourceFile)) + return 1; + + return 0; +} + +/* declare SIC_LoadOverlayIcon() */ +static int SIC_LoadOverlayIcon(int icon_idx); + +/***************************************************************************** + * SIC_OverlayShortcutImage [internal] + * + * NOTES + * Creates a new icon as a copy of the passed-in icon, overlayed with a + * shortcut image. + */ +static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large) +{ ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo; + HICON ShortcutIcon, TargetIcon; + BITMAP SourceBitmapInfo, ShortcutBitmapInfo; + HDC SourceDC = NULL, + ShortcutDC = NULL, + TargetDC = NULL, + ScreenDC = NULL; + HBITMAP OldSourceBitmap = NULL, + OldShortcutBitmap = NULL, + OldTargetBitmap = NULL; + + static int s_imgListIdx = -1; + + /* Get information about the source icon and shortcut overlay */ + if (! GetIconInfo(SourceIcon, &SourceIconInfo) + || 0 == GetObjectW(SourceIconInfo.hbmColor, sizeof(BITMAP), &SourceBitmapInfo)) + { + return NULL; + } + + /* search for the shortcut icon only once */ + if (s_imgListIdx == -1) + s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT); + /* FIXME should use icon index 29 instead of the + resource id, but not all icons are present yet + so we can't use icon indices */ + + if (s_imgListIdx != -1) + { + if (large) + ShortcutIcon = ImageList_GetIcon(ShellBigIconList, s_imgListIdx, ILD_TRANSPARENT); + else + ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT); + } else + ShortcutIcon = NULL; + + if (NULL == ShortcutIcon + || ! GetIconInfo(ShortcutIcon, &ShortcutIconInfo) + || 0 == GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo)) + { + return NULL; + } + + TargetIconInfo = SourceIconInfo; + TargetIconInfo.hbmMask = NULL; + TargetIconInfo.hbmColor = NULL; + + /* Setup the source, shortcut and target masks */ + SourceDC = CreateCompatibleDC(NULL); + if (NULL == SourceDC) goto fail; + OldSourceBitmap = (HBITMAP)SelectObject(SourceDC, SourceIconInfo.hbmMask); + if (NULL == OldSourceBitmap) goto fail; + + ShortcutDC = CreateCompatibleDC(NULL); + if (NULL == ShortcutDC) goto fail; + OldShortcutBitmap = (HBITMAP)SelectObject(ShortcutDC, ShortcutIconInfo.hbmMask); + if (NULL == OldShortcutBitmap) goto fail; + + TargetDC = CreateCompatibleDC(NULL); + if (NULL == TargetDC) goto fail; + TargetIconInfo.hbmMask = CreateCompatibleBitmap(TargetDC, SourceBitmapInfo.bmWidth, + SourceBitmapInfo.bmHeight); + if (NULL == TargetIconInfo.hbmMask) goto fail; + ScreenDC = GetDC(NULL); + if (NULL == ScreenDC) goto fail; + TargetIconInfo.hbmColor = CreateCompatibleBitmap(ScreenDC, SourceBitmapInfo.bmWidth, + SourceBitmapInfo.bmHeight); + ReleaseDC(NULL, ScreenDC); + if (NULL == TargetIconInfo.hbmColor) goto fail; + OldTargetBitmap = (HBITMAP)SelectObject(TargetDC, TargetIconInfo.hbmMask); + if (NULL == OldTargetBitmap) goto fail; + + /* Create the target mask by ANDing the source and shortcut masks */ + if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight, + SourceDC, 0, 0, SRCCOPY) || + ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight, + ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight, + ShortcutDC, 0, 0, SRCAND)) + { + goto fail; + } + + /* Setup the source and target xor bitmap */ + if (NULL == SelectObject(SourceDC, SourceIconInfo.hbmColor) || + NULL == SelectObject(TargetDC, TargetIconInfo.hbmColor)) + { + goto fail; + } + + /* Copy the source color bitmap to the target */ + if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight, + SourceDC, 0, 0, SRCCOPY)) goto fail; + + /* Copy the source xor bitmap to the target and clear out part of it by using + the shortcut mask */ + if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor)) goto fail; + if (!MaskBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight, + ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight, + ShortcutDC, 0, 0, ShortcutIconInfo.hbmMask, 0, 0, + MAKEROP4(0xAA0000, SRCCOPY))) + { + goto fail; + } + + /* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set + handles to NULL */ + SelectObject(TargetDC, OldTargetBitmap); + DeleteObject(TargetDC); + SelectObject(ShortcutDC, OldShortcutBitmap); + DeleteObject(ShortcutDC); + SelectObject(SourceDC, OldSourceBitmap); + DeleteObject(SourceDC); + + /* Create the icon using the bitmaps prepared earlier */ + TargetIcon = CreateIconIndirect(&TargetIconInfo); + + /* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */ + DeleteObject(TargetIconInfo.hbmColor); + DeleteObject(TargetIconInfo.hbmMask); + + return TargetIcon; + +fail: + /* Clean up scratch resources we created */ + if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap); + if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor); + if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask); + if (NULL != TargetDC) DeleteObject(TargetDC); + if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap); + if (NULL != ShortcutDC) DeleteObject(ShortcutDC); + if (NULL != OldSourceBitmap) SelectObject(SourceDC, OldSourceBitmap); + if (NULL != SourceDC) DeleteObject(SourceDC); + + return NULL; +} + +/***************************************************************************** + * SIC_IconAppend [internal] + * + * NOTES + * appends an icon pair to the end of the cache + */ +static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon, DWORD dwFlags) +{ LPSIC_ENTRY lpsice; + INT ret, index, index1; + WCHAR path[MAX_PATH]; + TRACE("%s %i %p %p\n", debugstr_w(sSourceFile), dwSourceIndex, hSmallIcon ,hBigIcon); + + lpsice = (LPSIC_ENTRY) SHAlloc (sizeof (SIC_ENTRY)); + + GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL); + lpsice->sSourceFile = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, (wcslen(path)+1)*sizeof(WCHAR) ); + wcscpy( lpsice->sSourceFile, path ); + + lpsice->dwSourceIndex = dwSourceIndex; + lpsice->dwFlags = dwFlags; + + EnterCriticalSection(&SHELL32_SicCS); + + index = DPA_InsertPtr(sic_hdpa, 0x7fff, lpsice); + if ( INVALID_INDEX == index ) + { + HeapFree(GetProcessHeap(), 0, lpsice->sSourceFile); + SHFree(lpsice); + ret = INVALID_INDEX; + } + else + { + index = ImageList_AddIcon (ShellSmallIconList, hSmallIcon); + index1= ImageList_AddIcon (ShellBigIconList, hBigIcon); + + if (index!=index1) + { + FIXME("iconlists out of sync 0x%x 0x%x\n", index, index1); + } + lpsice->dwListIndex = index; + ret = lpsice->dwListIndex; + } + + LeaveCriticalSection(&SHELL32_SicCS); + return ret; +} +/**************************************************************************** + * SIC_LoadIcon [internal] + * + * NOTES + * gets small/big icon by number from a file + */ +static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags) +{ HICON hiconLarge=0; + HICON hiconSmall=0; + HICON hiconLargeShortcut; + HICON hiconSmallShortcut; + +#if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER) + static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL; + + if (!PrivateExtractIconExW) { + HMODULE hUser32 = GetModuleHandleA("user32"); + PrivateExtractIconExW = (UINT(WINAPI*)(LPCWSTR,int,HICON*,HICON*,UINT)) GetProcAddress(hUser32, "PrivateExtractIconExW"); + } + + if (PrivateExtractIconExW) + PrivateExtractIconExW(sSourceFile, dwSourceIndex, &hiconLarge, &hiconSmall, 1); + else +#endif + { + PrivateExtractIconsW(sSourceFile, dwSourceIndex, 32, 32, &hiconLarge, NULL, 1, 0); + PrivateExtractIconsW(sSourceFile, dwSourceIndex, 16, 16, &hiconSmall, NULL, 1, 0); + } + + if ( !hiconLarge || !hiconSmall) + { + WARN("failure loading icon %i from %s (%p %p)\n", dwSourceIndex, debugstr_w(sSourceFile), hiconLarge, hiconSmall); + return -1; + } + + if (0 != (dwFlags & GIL_FORSHORTCUT)) + { + hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge, TRUE); + hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall, FALSE); + if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut) + { + hiconLarge = hiconLargeShortcut; + hiconSmall = hiconSmallShortcut; + } + else + { + WARN("Failed to create shortcut overlayed icons\n"); + if (NULL != hiconLargeShortcut) DestroyIcon(hiconLargeShortcut); + if (NULL != hiconSmallShortcut) DestroyIcon(hiconSmallShortcut); + dwFlags &= ~ GIL_FORSHORTCUT; + } + } + + return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge, dwFlags); +} +/***************************************************************************** + * SIC_GetIconIndex [internal] + * + * Parameters + * sSourceFile [IN] filename of file containing the icon + * index [IN] index/resID (negated) in this file + * + * NOTES + * look in the cache for a proper icon. if not available the icon is taken + * from the file and cached + */ +INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags ) +{ + SIC_ENTRY sice; + INT ret, index = INVALID_INDEX; + WCHAR path[MAX_PATH]; + + TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex); + + GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL); + sice.sSourceFile = path; + sice.dwSourceIndex = dwSourceIndex; + sice.dwFlags = dwFlags; + + EnterCriticalSection(&SHELL32_SicCS); + + if (NULL != DPA_GetPtr (sic_hdpa, 0)) + { + /* search linear from position 0*/ + index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, 0); + } + + if ( INVALID_INDEX == index ) + { + ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags); + } + else + { + TRACE("-- found\n"); + ret = ((LPSIC_ENTRY)DPA_GetPtr(sic_hdpa, index))->dwListIndex; + } + + LeaveCriticalSection(&SHELL32_SicCS); + return ret; +} +/***************************************************************************** + * SIC_Initialize [internal] + */ +BOOL SIC_Initialize(void) +{ + HICON hSm = NULL, hLg = NULL; + INT cx_small, cy_small; + INT cx_large, cy_large; + HDC hDC; + INT bpp; + DWORD ilMask; + + TRACE("Entered SIC_Initialize\n"); + + if (sic_hdpa) + { + TRACE("Icon cache already initialized\n"); + return TRUE; + } + + sic_hdpa = DPA_Create(16); + if (!sic_hdpa) + { + return FALSE; + } + + hDC = CreateICW(L"DISPLAY", NULL, NULL, NULL); + if (!hDC) + { + ERR("Failed to create information context (error %d)\n", GetLastError()); + return FALSE; + } + + bpp = GetDeviceCaps(hDC, BITSPIXEL); + ReleaseDC(NULL, hDC); + + if (bpp <= 4) + ilMask = ILC_COLOR4; + else if (bpp <= 8) + ilMask = ILC_COLOR8; + else if (bpp <= 16) + ilMask = ILC_COLOR16; + else if (bpp <= 24) + ilMask = ILC_COLOR24; + else if (bpp <= 32) + ilMask = ILC_COLOR32; + else + ilMask = ILC_COLOR; + + ilMask |= ILC_MASK; + + cx_small = GetSystemMetrics(SM_CXSMICON); + cy_small = GetSystemMetrics(SM_CYSMICON); + cx_large = GetSystemMetrics(SM_CXICON); + cy_large = GetSystemMetrics(SM_CYICON); + + ShellSmallIconList = ImageList_Create(cx_small, + cy_small, + ilMask, + 100, + 100); + + ShellBigIconList = ImageList_Create(cx_large, + cy_large, + ilMask, + 100, + 100); + if (ShellSmallIconList) + { + /* Load the document icon, which is used as the default if an icon isn't found. */ + hSm = (HICON)LoadImageW(shell32_hInstance, + MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT), + IMAGE_ICON, + cx_small, + cy_small, + LR_SHARED | LR_DEFAULTCOLOR); + if (!hSm) + { + ERR("Failed to load IDI_SHELL_DOCUMENT icon1!\n"); + return FALSE; + } + } + else + { + ERR("Failed to load ShellSmallIconList\n"); + return FALSE; + } + + if (ShellBigIconList) + { + hLg = (HICON)LoadImageW(shell32_hInstance, + MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT), + IMAGE_ICON, + cx_large, + cy_large, + LR_SHARED | LR_DEFAULTCOLOR); + if (!hLg) + { + ERR("Failed to load IDI_SHELL_DOCUMENT icon2!\n"); + DestroyIcon(hSm); + return FALSE; + } + } + else + { + ERR("Failed to load ShellBigIconList\n"); + return FALSE; + } + + SIC_IconAppend(swShell32Name, IDI_SHELL_DOCUMENT-1, hSm, hLg, 0); + SIC_IconAppend(swShell32Name, -IDI_SHELL_DOCUMENT, hSm, hLg, 0); + + TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList); + + return TRUE; +} +/************************************************************************* + * SIC_Destroy + * + * frees the cache + */ +static INT CALLBACK sic_free( LPVOID ptr, LPVOID lparam ) +{ + HeapFree(GetProcessHeap(), 0, ((LPSIC_ENTRY)ptr)->sSourceFile); + SHFree(ptr); + return TRUE; +} + +void SIC_Destroy(void) +{ + TRACE("\n"); + + EnterCriticalSection(&SHELL32_SicCS); + + if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL ); + + sic_hdpa = NULL; + ImageList_Destroy(ShellSmallIconList); + ShellSmallIconList = 0; + ImageList_Destroy(ShellBigIconList); + ShellBigIconList = 0; + + LeaveCriticalSection(&SHELL32_SicCS); + //DeleteCriticalSection(&SHELL32_SicCS); //static +} + +/***************************************************************************** + * SIC_LoadOverlayIcon [internal] + * + * Load a shell overlay icon and return its icon cache index. + */ +static int SIC_LoadOverlayIcon(int icon_idx) +{ + WCHAR buffer[1024], wszIdx[8]; + HKEY hKeyShellIcons; + LPCWSTR iconPath; + int iconIdx; + + static const WCHAR wszShellIcons[] = { + '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','\\','S','h','e','l','l',' ','I','c','o','n','s',0 + }; + static const WCHAR wszNumFmt[] = {'%','d',0}; + + iconPath = swShell32Name; /* default: load icon from shell32.dll */ + iconIdx = icon_idx; + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszShellIcons, 0, KEY_READ, &hKeyShellIcons) == ERROR_SUCCESS) + { + DWORD count = sizeof(buffer); + + swprintf(wszIdx, wszNumFmt, icon_idx); + + /* read icon path and index */ + if (RegQueryValueExW(hKeyShellIcons, wszIdx, NULL, NULL, (LPBYTE)buffer, &count) == ERROR_SUCCESS) + { + LPWSTR p = wcschr(buffer, ','); + + if (p) + *p++ = 0; + + iconPath = buffer; + iconIdx = _wtoi(p); + } + + RegCloseKey(hKeyShellIcons); + } + + return SIC_LoadIcon(iconPath, iconIdx, 0); +} + +/************************************************************************* + * Shell_GetImageLists [SHELL32.71] + * + * PARAMETERS + * imglist[1|2] [OUT] pointer which receives imagelist handles + * + */ +BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList) +{ TRACE("(%p,%p)\n",lpBigList,lpSmallList); + if (lpBigList) + { *lpBigList = ShellBigIconList; + } + if (lpSmallList) + { *lpSmallList = ShellSmallIconList; + } + + return TRUE; +} +/************************************************************************* + * PidlToSicIndex [INTERNAL] + * + * PARAMETERS + * sh [IN] IShellFolder + * pidl [IN] + * bBigIcon [IN] + * uFlags [IN] GIL_* + * pIndex [OUT] index within the SIC + * + */ +BOOL PidlToSicIndex ( + IShellFolder * sh, + LPCITEMIDLIST pidl, + BOOL bBigIcon, + UINT uFlags, + int * pIndex) +{ + CComPtr ei; + WCHAR szIconFile[MAX_PATH]; /* file containing the icon */ + INT iSourceIndex; /* index or resID(negated) in this file */ + BOOL ret = FALSE; + UINT dwFlags = 0; + int iShortcutDefaultIndex = INVALID_INDEX; + + TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small"); + + if (SUCCEEDED (sh->GetUIObjectOf(0, 1, &pidl, IID_IExtractIconW, 0, (void **)&ei))) + { + if (SUCCEEDED(ei->GetIconLocation(uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags))) + { + *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags); + ret = TRUE; + } + } + + if (INVALID_INDEX == *pIndex) /* default icon when failed */ + { + if (0 == (uFlags & GIL_FORSHORTCUT)) + { + *pIndex = 0; + } + else + { + if (INVALID_INDEX == iShortcutDefaultIndex) + { + iShortcutDefaultIndex = SIC_LoadIcon(swShell32Name, 0, GIL_FORSHORTCUT); + } + *pIndex = (INVALID_INDEX != iShortcutDefaultIndex ? iShortcutDefaultIndex : 0); + } + } + + return ret; + +} + +/************************************************************************* + * SHMapPIDLToSystemImageListIndex [SHELL32.77] + * + * PARAMETERS + * sh [IN] pointer to an instance of IShellFolder + * pidl [IN] + * pIndex [OUT][OPTIONAL] SIC index for big icon + * + */ +int WINAPI SHMapPIDLToSystemImageListIndex( + IShellFolder *sh, + LPCITEMIDLIST pidl, + int *pIndex) +{ + int Index; + UINT uGilFlags = 0; + + TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex); + pdump(pidl); + + if (SHELL_IsShortcut(pidl)) + uGilFlags |= GIL_FORSHORTCUT; + + if (pIndex) + if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex)) + *pIndex = -1; + + if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index)) + return -1; + + return Index; +} + +/************************************************************************* + * SHMapIDListToImageListIndexAsync [SHELL32.148] + */ +EXTERN_C HRESULT WINAPI SHMapIDListToImageListIndexAsync(IShellTaskScheduler *pts, IShellFolder *psf, + LPCITEMIDLIST pidl, UINT flags, + PFNASYNCICONTASKBALLBACK pfn, void *pvData, void *pvHint, + int *piIndex, int *piIndexSel) +{ + FIXME("(%p, %p, %p, 0x%08x, %p, %p, %p, %p, %p)\n", + pts, psf, pidl, flags, pfn, pvData, pvHint, piIndex, piIndexSel); + return E_FAIL; +} + +/************************************************************************* + * Shell_GetCachedImageIndex [SHELL32.72] + * + */ +INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, UINT bSimulateDoc) +{ + INT ret, len; + LPWSTR szTemp; + + WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc); + + len = MultiByteToWideChar( CP_ACP, 0, szPath, -1, NULL, 0 ); + szTemp = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len ); + + ret = SIC_GetIconIndex( szTemp, nIndex, 0 ); + + HeapFree( GetProcessHeap(), 0, szTemp ); + + return ret; +} + +INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, UINT bSimulateDoc) +{ + WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc); + + return SIC_GetIconIndex(szPath, nIndex, 0); +} + +EXTERN_C INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc) +{ if( SHELL_OsIsUnicode()) + return Shell_GetCachedImageIndexW((LPCWSTR)szPath, nIndex, bSimulateDoc); + return Shell_GetCachedImageIndexA((LPCSTR)szPath, nIndex, bSimulateDoc); +} + +/************************************************************************* + * ExtractIconExW [SHELL32.@] + * RETURNS + * 0 no icon found + * -1 file is not valid + * or number of icons extracted + */ +UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons) +{ + /* get entry point of undocumented function PrivateExtractIconExW() in user32 */ +#if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER) + static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL; + + if (!PrivateExtractIconExW) { + HMODULE hUser32 = GetModuleHandleA("user32"); + PrivateExtractIconExW = (UINT(WINAPI*)(LPCWSTR,int,HICON*,HICON*,UINT)) GetProcAddress(hUser32, "PrivateExtractIconExW"); + + if (!PrivateExtractIconExW) + return 0; + } +#endif + + TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons); + + return PrivateExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons); +} + +/************************************************************************* + * ExtractIconExA [SHELL32.@] + */ +UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons) +{ + UINT ret = 0; + INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0); + LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons); + + if (lpwstrFile) + { + MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len); + ret = ExtractIconExW(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons); + HeapFree(GetProcessHeap(), 0, lpwstrFile); + } + return ret; +} + +/************************************************************************* + * ExtractAssociatedIconA (SHELL32.@) + * + * Return icon for given file (either from file itself or from associated + * executable) and patch parameters if needed. + */ +HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon) +{ + HICON hIcon = NULL; + INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0); + /* Note that we need to allocate MAX_PATH, since we are supposed to fill + * the correct executable if there is no icon in lpIconPath directly. + * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW + * is large enough too. Yes, I am puking too. + */ + LPWSTR lpIconPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); + + TRACE("%p %s %p\n", hInst, debugstr_a(lpIconPath), lpiIcon); + + if (lpIconPathW) + { + MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, lpIconPathW, len); + hIcon = ExtractAssociatedIconW(hInst, lpIconPathW, lpiIcon); + WideCharToMultiByte(CP_ACP, 0, lpIconPathW, -1, lpIconPath, MAX_PATH , NULL, NULL); + HeapFree(GetProcessHeap(), 0, lpIconPathW); + } + return hIcon; +} + +/************************************************************************* + * ExtractAssociatedIconW (SHELL32.@) + * + * Return icon for given file (either from file itself or from associated + * executable) and patch parameters if needed. + */ +HICON WINAPI ExtractAssociatedIconW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIcon) +{ + HICON hIcon = NULL; + WORD wDummyIcon = 0; + + TRACE("%p %s %p\n", hInst, debugstr_w(lpIconPath), lpiIcon); + + if(lpiIcon == NULL) + lpiIcon = &wDummyIcon; + + hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon); + + if( hIcon < (HICON)2 ) + { if( hIcon == (HICON)1 ) /* no icons found in given file */ + { WCHAR tempPath[MAX_PATH]; + HINSTANCE uRet = FindExecutableW(lpIconPath,NULL,tempPath); + + if( uRet > (HINSTANCE)32 && tempPath[0] ) + { wcscpy(lpIconPath,tempPath); + hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon); + if( hIcon > (HICON)2 ) + return hIcon; + } + } + + if( hIcon == (HICON)1 ) + *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */ + else + *lpiIcon = 6; /* generic icon - found nothing */ + + if (GetModuleFileNameW(hInst, lpIconPath, MAX_PATH)) + hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(*lpiIcon)); + } + return hIcon; +} + +/************************************************************************* + * ExtractAssociatedIconExW (SHELL32.@) + * + * Return icon for given file (either from file itself or from associated + * executable) and patch parameters if needed. + */ +EXTERN_C HICON WINAPI ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId) +{ + FIXME("%p %s %p %p): stub\n", hInst, debugstr_w(lpIconPath), lpiIconIdx, lpiIconId); + return 0; +} + +/************************************************************************* + * ExtractAssociatedIconExA (SHELL32.@) + * + * Return icon for given file (either from file itself or from associated + * executable) and patch parameters if needed. + */ +EXTERN_C HICON WINAPI ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId) +{ + HICON ret; + INT len = MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, NULL, 0 ); + LPWSTR lpwstrFile = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + + TRACE("%p %s %p %p)\n", hInst, lpIconPath, lpiIconIdx, lpiIconId); + + MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, lpwstrFile, len ); + ret = ExtractAssociatedIconExW(hInst, lpwstrFile, lpiIconIdx, lpiIconId); + HeapFree(GetProcessHeap(), 0, lpwstrFile); + return ret; +} + + +/**************************************************************************** + * SHDefExtractIconW [SHELL32.@] + */ +HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, + HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize) +{ + UINT ret; + HICON hIcons[2]; + WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); + + ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR); + /* FIXME: deal with uFlags parameter which contains GIL_ flags */ + if (ret == 0xFFFFFFFF) + return E_FAIL; + if (ret > 0) { + if (phiconLarge) + *phiconLarge = hIcons[0]; + else + DestroyIcon(hIcons[0]); + if (phiconSmall) + *phiconSmall = hIcons[1]; + else + DestroyIcon(hIcons[1]); + return S_OK; + } + return S_FALSE; +} + +/**************************************************************************** + * SHDefExtractIconA [SHELL32.@] + */ +HRESULT WINAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags, + HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize) +{ + HRESULT ret; + INT len = MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, NULL, 0); + LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); + + MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, lpwstrFile, len); + ret = SHDefExtractIconW(lpwstrFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); + HeapFree(GetProcessHeap(), 0, lpwstrFile); + return ret; +} + +/**************************************************************************** + * SHGetIconOverlayIndexA [SHELL32.@] + * + * Returns the index of the overlay icon in the system image list. + */ +EXTERN_C INT WINAPI SHGetIconOverlayIndexA(LPCSTR pszIconPath, INT iIconIndex) +{ + FIXME("%s, %d\n", debugstr_a(pszIconPath), iIconIndex); + + return -1; +} + +/**************************************************************************** + * SHGetIconOverlayIndexW [SHELL32.@] + * + * Returns the index of the overlay icon in the system image list. + */ +EXTERN_C INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex) +{ + FIXME("%s, %d\n", debugstr_w(pszIconPath), iIconIndex); + + return -1; +} diff --git a/reactos/dll/win32/shell32/lang/de-DE.rc b/reactos/dll/win32/shell32/lang/de-DE.rc index cbb3d03c78b..e2136f9552f 100644 --- a/reactos/dll/win32/shell32/lang/de-DE.rc +++ b/reactos/dll/win32/shell32/lang/de-DE.rc @@ -55,7 +55,7 @@ BEGIN MENUITEM "Aktualisieren", FCIDM_SHVIEW_REFRESH MENUITEM SEPARATOR MENUITEM "Einfügen", FCIDM_SHVIEW_INSERT - MENUITEM "Verknüpfung einfügen", FCIDM_SHVIEW_INSERTLINK + MENUITEM "Einfügen als Verweis", FCIDM_SHVIEW_INSERTLINK MENUITEM SEPARATOR MENUITEM "&Eigenschaften", FCIDM_SHVIEW_PROPERTIES END @@ -719,7 +719,7 @@ BEGIN IDS_SHELL_ABOUT_BACK "< &Zurück" FCIDM_SHVIEW_NEW "Neu" FCIDM_SHVIEW_NEWFOLDER "Neues Ver&zeichnis" - FCIDM_SHVIEW_NEWLINK "Neue &Verknüpfung" + FCIDM_SHVIEW_NEWLINK "Neuer Ver&weis" IDS_FOLDER_OPTIONS "Ordneroptionen" IDS_RECYCLEBIN_LOCATION "Papierkorbpfad" IDS_RECYCLEBIN_DISKSPACE "freier Speicher" diff --git a/reactos/dll/win32/shell32/menuband.cpp b/reactos/dll/win32/shell32/menuband.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/menuband.h b/reactos/dll/win32/shell32/menuband.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/menubandsite.cpp b/reactos/dll/win32/shell32/menubandsite.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/menubandsite.h b/reactos/dll/win32/shell32/menubandsite.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/menudeskbar.cpp b/reactos/dll/win32/shell32/menudeskbar.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/menudeskbar.h b/reactos/dll/win32/shell32/menudeskbar.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/pidl.cpp b/reactos/dll/win32/shell32/pidl.cpp new file mode 100644 index 00000000000..d28dbce0424 --- /dev/null +++ b/reactos/dll/win32/shell32/pidl.cpp @@ -0,0 +1,2411 @@ +/* + * pidl Handling + * + * Copyright 1998 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 + * + * NOTES + * a pidl == NULL means desktop and is legal + * + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(pidl); +WINE_DECLARE_DEBUG_CHANNEL(shell); + +/* from comctl32.dll */ +EXTERN_C LPVOID WINAPI Alloc(INT); +EXTERN_C BOOL WINAPI Free(LPVOID); + +static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl); +static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl); + +/************************************************************************* + * ILGetDisplayNameExA [SHELL32.186] + * + * Retrieves the display name of an ItemIDList + * + * PARAMS + * psf [I] Shell Folder to start with, if NULL the desktop is used + * pidl [I] ItemIDList relative to the psf to get the display name for + * path [O] Filled in with the display name, assumed to be at least MAX_PATH long + * type [I] Type of display name to retrieve + * 0 = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR uses always the desktop as root + * 1 = SHGDN_NORMAL relative to the root folder + * 2 = SHGDN_INFOLDER relative to the root folder, only the last name + * + * RETURNS + * True if the display name could be retrieved successfully, False otherwise + */ +static BOOL ILGetDisplayNameExA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPSTR path, DWORD type) +{ + BOOL ret = FALSE; + WCHAR wPath[MAX_PATH]; + + TRACE("%p %p %p %d\n", psf, pidl, path, type); + + if (!pidl || !path) + return FALSE; + + ret = ILGetDisplayNameExW(psf, pidl, wPath, type); + WideCharToMultiByte(CP_ACP, 0, wPath, -1, path, MAX_PATH, NULL, NULL); + TRACE("%p %p %s\n", psf, pidl, debugstr_a(path)); + + return ret; +} + +BOOL WINAPI ILGetDisplayNameExW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPWSTR path, DWORD type) +{ + CComPtr psfParent; + LPSHELLFOLDER lsf = psf; + HRESULT ret = NO_ERROR; + LPCITEMIDLIST pidllast; + STRRET strret; + DWORD flag; + + TRACE("%p %p %p %d\n", psf, pidl, path, type); + + if (!pidl || !path) + return FALSE; + + if (!lsf) + { + ret = SHGetDesktopFolder(&lsf); + if (FAILED(ret)) + return FALSE; + } + + if (type <= 2) + { + switch (type) + { + case ILGDN_FORPARSING: + flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR; + break; + case ILGDN_NORMAL: + flag = SHGDN_NORMAL; + break; + case ILGDN_INFOLDER: + flag = SHGDN_INFOLDER; + break; + default: + FIXME("Unknown type parameter = %x\n", type); + flag = SHGDN_FORPARSING | SHGDN_FORADDRESSBAR; + break; + } + if (!*(const WORD*)pidl || type == ILGDN_FORPARSING) + { + ret = lsf->GetDisplayNameOf(pidl, flag, &strret); + if (SUCCEEDED(ret)) + { + if(!StrRetToStrNW(path, MAX_PATH, &strret, pidl)) + ret = E_FAIL; + } + } + else + { + ret = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*)&psfParent, &pidllast); + if (SUCCEEDED(ret)) + { + ret = psfParent->GetDisplayNameOf(pidllast, flag, &strret); + if (SUCCEEDED(ret)) + { + if(!StrRetToStrNW(path, MAX_PATH, &strret, pidllast)) + ret = E_FAIL; + } + } + } + } + + TRACE("%p %p %s\n", psf, pidl, debugstr_w(path)); + + if (!psf) + lsf->Release(); + return SUCCEEDED(ret); +} + +/************************************************************************* + * ILGetDisplayNameEx [SHELL32.186] + */ +BOOL WINAPI ILGetDisplayNameEx(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, LPVOID path, DWORD type) +{ + TRACE_(shell)("%p %p %p %d\n", psf, pidl, path, type); + + if (SHELL_OsIsUnicode()) + return ILGetDisplayNameExW(psf, pidl, (LPWSTR)path, type); + return ILGetDisplayNameExA(psf, pidl, (LPSTR)path, type); +} + +/************************************************************************* + * ILGetDisplayName [SHELL32.15] + */ +BOOL WINAPI ILGetDisplayName(LPCITEMIDLIST pidl, LPVOID path) +{ + TRACE_(shell)("%p %p\n", pidl, path); + + if (SHELL_OsIsUnicode()) + return ILGetDisplayNameExW(NULL, pidl, (LPWSTR)path, ILGDN_FORPARSING); + return ILGetDisplayNameExA(NULL, pidl, (LPSTR)path, ILGDN_FORPARSING); +} + +/************************************************************************* + * ILFindLastID [SHELL32.16] + * + * NOTES + * observed: pidl=Desktop return=pidl + */ +LPITEMIDLIST WINAPI ILFindLastID(LPCITEMIDLIST pidl) +{ + LPCITEMIDLIST pidlLast = pidl; + + TRACE("(pidl=%p)\n",pidl); + + if (!pidl) + return NULL; + + while (pidl->mkid.cb) + { + pidlLast = pidl; + pidl = ILGetNext(pidl); + } + return (LPITEMIDLIST)pidlLast; +} + +/************************************************************************* + * ILRemoveLastID [SHELL32.17] + * + * NOTES + * when pidl=Desktop return=FALSE + */ +BOOL WINAPI ILRemoveLastID(LPITEMIDLIST pidl) +{ + TRACE_(shell)("pidl=%p\n",pidl); + + if (!pidl || !pidl->mkid.cb) + return 0; + ILFindLastID(pidl)->mkid.cb = 0; + return 1; +} + +/************************************************************************* + * ILClone [SHELL32.18] + * + * NOTES + * duplicate an idlist + */ +LPITEMIDLIST WINAPI ILClone (LPCITEMIDLIST pidl) +{ + DWORD len; + LPITEMIDLIST newpidl; + + if (!pidl) + return NULL; + + len = ILGetSize(pidl); + newpidl = (LPITEMIDLIST)SHAlloc(len); + if (newpidl) + memcpy(newpidl,pidl,len); + + TRACE("pidl=%p newpidl=%p\n",pidl, newpidl); + pdump(pidl); + + return newpidl; +} + +/************************************************************************* + * ILCloneFirst [SHELL32.19] + * + * NOTES + * duplicates the first idlist of a complex pidl + */ +LPITEMIDLIST WINAPI ILCloneFirst(LPCITEMIDLIST pidl) +{ + DWORD len; + LPITEMIDLIST pidlNew = NULL; + + TRACE("pidl=%p\n", pidl); + pdump(pidl); + + if (pidl) + { + len = pidl->mkid.cb; + pidlNew = (LPITEMIDLIST)SHAlloc(len+2); + if (pidlNew) + { + memcpy(pidlNew,pidl,len+2); /* 2 -> mind a desktop pidl */ + + if (len) + ILGetNext(pidlNew)->mkid.cb = 0x00; + } + } + TRACE("-- newpidl=%p\n",pidlNew); + + return pidlNew; +} + +/************************************************************************* + * ILLoadFromStream (SHELL32.26) + * + * NOTES + * the first two bytes are the len, the pidl is following then + */ +HRESULT WINAPI ILLoadFromStream (IStream * pStream, LPITEMIDLIST * ppPidl) +{ + WORD wLen = 0; + DWORD dwBytesRead; + HRESULT ret = E_FAIL; + + + TRACE_(shell)("%p %p\n", pStream , ppPidl); + + SHFree(*ppPidl); + *ppPidl = NULL; + + pStream->AddRef (); + + if (SUCCEEDED(pStream->Read(&wLen, 2, &dwBytesRead))) + { + TRACE("PIDL length is %d\n", wLen); + if (wLen != 0) + { + *ppPidl = (LPITEMIDLIST)SHAlloc(wLen); + if (SUCCEEDED(pStream->Read(*ppPidl , wLen, &dwBytesRead))) + { + TRACE("Stream read OK\n"); + ret = S_OK; + } + else + { + WARN("reading pidl failed\n"); + SHFree(*ppPidl); + *ppPidl = NULL; + } + } + else + { + *ppPidl = NULL; + ret = S_OK; + } + } + + /* we are not yet fully compatible */ + if (*ppPidl && !pcheck(*ppPidl)) + { + WARN("Check failed\n"); + SHFree(*ppPidl); + *ppPidl = NULL; + } + + pStream->Release (); + TRACE("done\n"); + return ret; +} + +/************************************************************************* + * ILSaveToStream (SHELL32.27) + * + * NOTES + * the first two bytes are the len, the pidl is following then + */ +HRESULT WINAPI ILSaveToStream (IStream * pStream, LPCITEMIDLIST pPidl) +{ + WORD wLen = 0; + HRESULT ret = E_FAIL; + + TRACE_(shell)("%p %p\n", pStream, pPidl); + + pStream->AddRef (); + + wLen = ILGetSize(pPidl); + + if (SUCCEEDED(pStream->Write(&wLen, 2, NULL))) + { + if (SUCCEEDED(pStream->Write(pPidl, wLen, NULL))) + ret = S_OK; + } + pStream->Release (); + + return ret; +} + +/************************************************************************* + * SHILCreateFromPath [SHELL32.28] + * + * Create an ItemIDList from a path + * + * PARAMS + * path [I] + * ppidl [O] + * attributes [I/O] requested attributes on call and actual attributes when + * the function returns + * + * RETURNS + * NO_ERROR if successful, or an OLE errer code otherwise + * + * NOTES + * Wrapper for IShellFolder_ParseDisplayName(). + */ +HRESULT WINAPI SHILCreateFromPathA(LPCSTR path, LPITEMIDLIST * ppidl, DWORD * attributes) +{ + WCHAR lpszDisplayName[MAX_PATH]; + + TRACE_(shell)("%s %p 0x%08x\n", path, ppidl, attributes ? *attributes : 0); + + if (!MultiByteToWideChar(CP_ACP, 0, path, -1, lpszDisplayName, MAX_PATH)) + lpszDisplayName[MAX_PATH-1] = 0; + + return SHILCreateFromPathW(lpszDisplayName, ppidl, attributes); +} + +HRESULT WINAPI SHILCreateFromPathW(LPCWSTR path, LPITEMIDLIST * ppidl, DWORD * attributes) +{ + CComPtr sf; + DWORD pchEaten; + HRESULT ret = E_FAIL; + + TRACE_(shell)("%s %p 0x%08x\n", debugstr_w(path), ppidl, attributes ? *attributes : 0); + + if (SUCCEEDED (SHGetDesktopFolder(&sf))) + ret = sf->ParseDisplayName(0, NULL, (LPWSTR)path, &pchEaten, ppidl, attributes); + return ret; +} + +EXTERN_C HRESULT WINAPI SHILCreateFromPathAW (LPCVOID path, LPITEMIDLIST * ppidl, DWORD * attributes) +{ + if ( SHELL_OsIsUnicode()) + return SHILCreateFromPathW ((LPCWSTR)path, ppidl, attributes); + return SHILCreateFromPathA ((LPCSTR)path, ppidl, attributes); +} + +/************************************************************************* + * SHCloneSpecialIDList [SHELL32.89] + * + * Create an ItemIDList to one of the special folders. + + * PARAMS + * hwndOwner [in] + * nFolder [in] CSIDL_xxxxx + * fCreate [in] Create folder if it does not exist + * + * RETURNS + * Success: The newly created pidl + * Failure: NULL, if inputs are invalid. + * + * NOTES + * exported by ordinal. + * Caller is responsible for deallocating the returned ItemIDList with the + * shells IMalloc interface, aka ILFree. + */ +LPITEMIDLIST WINAPI SHCloneSpecialIDList(HWND hwndOwner, int nFolder, BOOL fCreate) +{ + LPITEMIDLIST ppidl; + TRACE_(shell)("(hwnd=%p,csidl=0x%x,%s).\n", hwndOwner, nFolder, fCreate ? "T" : "F"); + + if (fCreate) + nFolder |= CSIDL_FLAG_CREATE; + + SHGetSpecialFolderLocation(hwndOwner, nFolder, &ppidl); + return ppidl; +} + +/************************************************************************* + * ILGlobalClone [SHELL32.20] + * + * Clones an ItemIDList using Alloc. + * + * PARAMS + * pidl [I] ItemIDList to clone + * + * RETURNS + * Newly allocated ItemIDList. + * + * NOTES + * exported by ordinal. + */ +LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl) +{ + DWORD len; + LPITEMIDLIST newpidl; + + if (!pidl) + return NULL; + + len = ILGetSize(pidl); + newpidl = (LPITEMIDLIST)Alloc(len); + if (newpidl) + memcpy(newpidl,pidl,len); + + TRACE("pidl=%p newpidl=%p\n",pidl, newpidl); + pdump(pidl); + + return newpidl; +} + +/************************************************************************* + * ILIsEqual [SHELL32.21] + * + */ +BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + char szData1[MAX_PATH]; + char szData2[MAX_PATH]; + + LPCITEMIDLIST pidltemp1 = pidl1; + LPCITEMIDLIST pidltemp2 = pidl2; + + TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2); + + /* + * Explorer reads from registry directly (StreamMRU), + * so we can only check here + */ + if (!pcheck(pidl1) || !pcheck (pidl2)) + return FALSE; + + pdump (pidl1); + pdump (pidl2); + + if (!pidl1 || !pidl2) + return FALSE; + + while (pidltemp1->mkid.cb && pidltemp2->mkid.cb) + { + _ILSimpleGetText(pidltemp1, szData1, MAX_PATH); + _ILSimpleGetText(pidltemp2, szData2, MAX_PATH); + + if (strcmp( szData1, szData2 )) + return FALSE; + + pidltemp1 = ILGetNext(pidltemp1); + pidltemp2 = ILGetNext(pidltemp2); + } + + if (!pidltemp1->mkid.cb && !pidltemp2->mkid.cb) + return TRUE; + + return FALSE; +} + +/************************************************************************* + * ILIsParent [SHELL32.23] + * + * Verifies that pidlParent is indeed the (immediate) parent of pidlChild. + * + * PARAMS + * pidlParent [I] + * pidlChild [I] + * bImmediate [I] only return true if the parent is the direct parent + * of the child + * + * RETURNS + * True if the parent ItemIDlist is a complete part of the child ItemIdList, + * False otherwise. + * + * NOTES + * parent = a/b, child = a/b/c -> true, c is in folder a/b + * child = a/b/c/d -> false if bImmediate is true, d is not in folder a/b + * child = a/b/c/d -> true if bImmediate is false, d is in a subfolder of a/b + */ +BOOL WINAPI ILIsParent(LPCITEMIDLIST pidlParent, LPCITEMIDLIST pidlChild, BOOL bImmediate) +{ + char szData1[MAX_PATH]; + char szData2[MAX_PATH]; + LPCITEMIDLIST pParent = pidlParent; + LPCITEMIDLIST pChild = pidlChild; + + TRACE("%p %p %x\n", pidlParent, pidlChild, bImmediate); + + if (!pParent || !pChild) + return FALSE; + + while (pParent->mkid.cb && pChild->mkid.cb) + { + _ILSimpleGetText(pParent, szData1, MAX_PATH); + _ILSimpleGetText(pChild, szData2, MAX_PATH); + + if (strcmp( szData1, szData2 )) + return FALSE; + + pParent = ILGetNext(pParent); + pChild = ILGetNext(pChild); + } + + /* child shorter or has equal length to parent */ + if (pParent->mkid.cb || !pChild->mkid.cb) + return FALSE; + + /* not immediate descent */ + if ( ILGetNext(pChild)->mkid.cb && bImmediate) + return FALSE; + + return TRUE; +} + +/************************************************************************* + * ILFindChild [SHELL32.24] + * + * Compares elements from pidl1 and pidl2. + * + * PARAMS + * pidl1 [I] + * pidl2 [I] + * + * RETURNS + * pidl1 is desktop pidl2 + * pidl1 shorter pidl2 pointer to first different element of pidl2 + * if there was at least one equal element + * pidl2 shorter pidl1 0 + * pidl2 equal pidl1 pointer to last 0x00-element of pidl2 + * + * NOTES + * exported by ordinal. + */ +LPITEMIDLIST WINAPI ILFindChild(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + char szData1[MAX_PATH]; + char szData2[MAX_PATH]; + + LPCITEMIDLIST pidltemp1 = pidl1; + LPCITEMIDLIST pidltemp2 = pidl2; + LPCITEMIDLIST ret=NULL; + + TRACE("pidl1=%p pidl2=%p\n",pidl1, pidl2); + + /* explorer reads from registry directly (StreamMRU), + so we can only check here */ + if ((!pcheck (pidl1)) || (!pcheck (pidl2))) + return FALSE; + + pdump (pidl1); + pdump (pidl2); + + if (_ILIsDesktop(pidl1)) + { + ret = pidl2; + } + else + { + while (pidltemp1->mkid.cb && pidltemp2->mkid.cb) + { + _ILSimpleGetText(pidltemp1, szData1, MAX_PATH); + _ILSimpleGetText(pidltemp2, szData2, MAX_PATH); + + if (strcmp(szData1,szData2)) + break; + + pidltemp1 = ILGetNext(pidltemp1); + pidltemp2 = ILGetNext(pidltemp2); + ret = pidltemp2; + } + + if (pidltemp1->mkid.cb) + ret = NULL; /* elements of pidl1 left*/ + } + TRACE_(shell)("--- %p\n", ret); + return (LPITEMIDLIST)ret; /* pidl 1 is shorter */ +} + +/************************************************************************* + * ILCombine [SHELL32.25] + * + * Concatenates two complex ItemIDLists. + * + * PARAMS + * pidl1 [I] first complex ItemIDLists + * pidl2 [I] complex ItemIDLists to append + * + * RETURNS + * if both pidl's == NULL NULL + * if pidl1 == NULL cloned pidl2 + * if pidl2 == NULL cloned pidl1 + * otherwise new pidl with pidl2 appended to pidl1 + * + * NOTES + * exported by ordinal. + * Does not destroy the passed in ItemIDLists! + */ +LPITEMIDLIST WINAPI ILCombine(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + DWORD len1,len2; + LPITEMIDLIST pidlNew; + + TRACE("pidl=%p pidl=%p\n",pidl1,pidl2); + + if (!pidl1 && !pidl2) return NULL; + + pdump (pidl1); + pdump (pidl2); + + if (!pidl1) + { + pidlNew = ILClone(pidl2); + return pidlNew; + } + + if (!pidl2) + { + pidlNew = ILClone(pidl1); + return pidlNew; + } + + len1 = ILGetSize(pidl1)-2; + len2 = ILGetSize(pidl2); + pidlNew = (LPITEMIDLIST)SHAlloc(len1+len2); + + if (pidlNew) + { + memcpy(pidlNew,pidl1,len1); + memcpy(((BYTE *)pidlNew)+len1,pidl2,len2); + } + + /* TRACE(pidl,"--new pidl=%p\n",pidlNew);*/ + return pidlNew; +} + +/************************************************************************* + * SHGetRealIDL [SHELL32.98] + * + * NOTES + */ +HRESULT WINAPI SHGetRealIDL(LPSHELLFOLDER lpsf, LPCITEMIDLIST pidlSimple, LPITEMIDLIST *pidlReal) +{ + CComPtr pDataObj; + HRESULT hr; + + hr = lpsf->GetUIObjectOf(0, 1, &pidlSimple, + IID_IDataObject, 0, (LPVOID*)&pDataObj); + if (SUCCEEDED(hr)) + { + STGMEDIUM medium; + FORMATETC fmt; + + fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLIST); + fmt.ptd = NULL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.tymed = TYMED_HGLOBAL; + + hr = pDataObj->GetData(&fmt, &medium); + + if (SUCCEEDED(hr)) + { + /*assert(pida->cidl==1);*/ + LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal); + + LPCITEMIDLIST pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]); + LPCITEMIDLIST pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]); + + *pidlReal = ILCombine(pidl_folder, pidl_child); + + if (!*pidlReal) + hr = E_OUTOFMEMORY; + + GlobalUnlock(medium.hGlobal); + GlobalFree(medium.hGlobal); + } + } + + return hr; +} + +/************************************************************************* + * SHLogILFromFSIL [SHELL32.95] + * + * NOTES + * pild = CSIDL_DESKTOP ret = 0 + * pild = CSIDL_DRIVES ret = 0 + */ +EXTERN_C LPITEMIDLIST WINAPI SHLogILFromFSIL(LPITEMIDLIST pidl) +{ + FIXME("(pidl=%p)\n",pidl); + + pdump(pidl); + + return 0; +} + +/************************************************************************* + * ILGetSize [SHELL32.152] + * + * Gets the byte size of an ItemIDList including zero terminator + * + * PARAMS + * pidl [I] ItemIDList + * + * RETURNS + * size of pidl in bytes + * + * NOTES + * exported by ordinal + */ +UINT WINAPI ILGetSize(LPCITEMIDLIST pidl) +{ + LPCSHITEMID si = &(pidl->mkid); + UINT len=0; + + if (pidl) + { + while (si->cb) + { + len += si->cb; + si = (LPCSHITEMID)(((const BYTE*)si)+si->cb); + } + len += 2; + } + TRACE("pidl=%p size=%u\n",pidl, len); + return len; +} + +/************************************************************************* + * ILGetNext [SHELL32.153] + * + * Gets the next ItemID of an ItemIDList + * + * PARAMS + * pidl [I] ItemIDList + * + * RETURNS + * null -> null + * desktop -> null + * simple pidl -> pointer to 0x0000 element + * + * NOTES + * exported by ordinal. + */ +LPITEMIDLIST WINAPI ILGetNext(LPCITEMIDLIST pidl) +{ + WORD len; + + TRACE("%p\n", pidl); + + if (pidl) + { + len = pidl->mkid.cb; + if (len) + { + pidl = (LPCITEMIDLIST) (((const BYTE*)pidl)+len); + TRACE("-- %p\n", pidl); + return (LPITEMIDLIST)pidl; + } + } + return NULL; +} + +/************************************************************************* + * ILAppend [SHELL32.154] + * + * Adds the single ItemID item to the ItemIDList indicated by pidl. + * If bEnd is FALSE, inserts the item in the front of the list, + * otherwise it adds the item to the end. (???) + * + * PARAMS + * pidl [I] ItemIDList to extend + * item [I] ItemID to prepend/append + * bEnd [I] Indicates if the item should be appended + * + * NOTES + * Destroys the passed in idlist! (???) + */ +EXTERN_C LPITEMIDLIST WINAPI ILAppend(LPITEMIDLIST pidl, LPCITEMIDLIST item, BOOL bEnd) +{ + LPITEMIDLIST idlRet; + + WARN("(pidl=%p,pidl=%p,%08u)semi-stub\n",pidl,item,bEnd); + + pdump (pidl); + pdump (item); + + if (_ILIsDesktop(pidl)) + { + idlRet = ILClone(item); + SHFree (pidl); + return idlRet; + } + + if (bEnd) + idlRet = ILCombine(pidl, item); + else + idlRet = ILCombine(item, pidl); + + SHFree(pidl); + return idlRet; +} + +/************************************************************************* + * ILFree [SHELL32.155] + * + * Frees memory (if not NULL) allocated by SHMalloc allocator + * + * PARAMS + * pidl [I] + * + * RETURNS + * Nothing + * + * NOTES + * exported by ordinal + */ +void WINAPI ILFree(LPITEMIDLIST pidl) +{ + TRACE("(pidl=%p)\n",pidl); + SHFree(pidl); +} + +/************************************************************************* + * ILGlobalFree [SHELL32.156] + * + * Frees memory (if not NULL) allocated by Alloc allocator + * + * PARAMS + * pidl [I] + * + * RETURNS + * Nothing + * + * NOTES + * exported by ordinal. + */ +void WINAPI ILGlobalFree( LPITEMIDLIST pidl) +{ + TRACE("%p\n", pidl); + + Free(pidl); +} + +/************************************************************************* + * ILCreateFromPathA [SHELL32.189] + * + * Creates a complex ItemIDList from a path and returns it. + * + * PARAMS + * path [I] + * + * RETURNS + * the newly created complex ItemIDList or NULL if failed + * + * NOTES + * exported by ordinal. + */ +LPITEMIDLIST WINAPI ILCreateFromPathA (LPCSTR path) +{ + LPITEMIDLIST pidlnew = NULL; + + TRACE_(shell)("%s\n", debugstr_a(path)); + + if (SUCCEEDED(SHILCreateFromPathA(path, &pidlnew, NULL))) + return pidlnew; + return NULL; +} + +/************************************************************************* + * ILCreateFromPathW [SHELL32.190] + * + * See ILCreateFromPathA. + */ +LPITEMIDLIST WINAPI ILCreateFromPathW (LPCWSTR path) +{ + LPITEMIDLIST pidlnew = NULL; + + TRACE_(shell)("%s\n", debugstr_w(path)); + + if (SUCCEEDED(SHILCreateFromPathW(path, &pidlnew, NULL))) + return pidlnew; + return NULL; +} + +/************************************************************************* + * ILCreateFromPath [SHELL32.157] + */ +EXTERN_C LPITEMIDLIST WINAPI ILCreateFromPathAW (LPCVOID path) +{ + if ( SHELL_OsIsUnicode()) + return ILCreateFromPathW ((LPCWSTR)path); + return ILCreateFromPathA ((LPCSTR)path); +} + +/************************************************************************* + * _ILParsePathW [internal] + * + * Creates an ItemIDList from a path and returns it. + * + * PARAMS + * path [I] path to parse and convert into an ItemIDList + * lpFindFile [I] pointer to buffer to initialize the FileSystem + * Bind Data object with + * bBindCtx [I] indicates to create a BindContext and assign a + * FileSystem Bind Data object + * ppidl [O] the newly create ItemIDList + * prgfInOut [I/O] requested attributes on input and actual + * attributes on return + * + * RETURNS + * NO_ERROR on success or an OLE error code + * + * NOTES + * If either lpFindFile is non-NULL or bBindCtx is TRUE, this function + * creates a BindContext object and assigns a FileSystem Bind Data object + * to it, passing the BindContext to IShellFolder_ParseDisplayName. Each + * IShellFolder uses that FileSystem Bind Data object of the BindContext + * to pass data about the current path element to the next object. This + * is used to avoid having to verify the current path element on disk, so + * that creating an ItemIDList from a nonexistent path still can work. + */ +static HRESULT _ILParsePathW(LPCWSTR path, LPWIN32_FIND_DATAW lpFindFile, + BOOL bBindCtx, LPITEMIDLIST *ppidl, LPDWORD prgfInOut) +{ + CComPtr pSF; + CComPtr pBC; + HRESULT ret; + + TRACE("%s %p %d (%p)->%p (%p)->0x%x\n", debugstr_w(path), lpFindFile, bBindCtx, + ppidl, ppidl ? *ppidl : NULL, + prgfInOut, prgfInOut ? *prgfInOut : 0); + + ret = SHGetDesktopFolder(&pSF); + if (FAILED(ret)) + return ret; + + if (lpFindFile || bBindCtx) + ret = IFileSystemBindData_Constructor(lpFindFile, &pBC); + + if (SUCCEEDED(ret)) + { + ret = pSF->ParseDisplayName(0, pBC, (LPOLESTR)path, NULL, ppidl, prgfInOut); + } + + if (FAILED(ret) && ppidl) + *ppidl = NULL; + + TRACE("%s %p 0x%x\n", debugstr_w(path), ppidl ? *ppidl : NULL, prgfInOut ? *prgfInOut : 0); + + return ret; +} + +/************************************************************************* + * SHSimpleIDListFromPath [SHELL32.162] + * + * Creates a simple ItemIDList from a path and returns it. This function + * does not fail on nonexistent paths. + * + * PARAMS + * path [I] path to parse and convert into an ItemIDList + * + * RETURNS + * the newly created simple ItemIDList + * + * NOTES + * Simple in the name does not mean a relative ItemIDList but rather a + * fully qualified list, where only the file name is filled in and the + * directory flag for those ItemID elements this is known about, eg. + * it is not the last element in the ItemIDList or the actual directory + * exists on disk. + * exported by ordinal. + */ +LPITEMIDLIST WINAPI SHSimpleIDListFromPathA(LPCSTR lpszPath) +{ + LPITEMIDLIST pidl = NULL; + LPWSTR wPath = NULL; + int len; + + TRACE("%s\n", debugstr_a(lpszPath)); + + if (lpszPath) + { + len = MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, NULL, 0); + wPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, lpszPath, -1, wPath, len); + } + + _ILParsePathW(wPath, NULL, TRUE, &pidl, NULL); + + HeapFree(GetProcessHeap(), 0, wPath); + TRACE("%s %p\n", debugstr_a(lpszPath), pidl); + return pidl; +} + +LPITEMIDLIST WINAPI SHSimpleIDListFromPathW(LPCWSTR lpszPath) +{ + LPITEMIDLIST pidl = NULL; + + TRACE("%s\n", debugstr_w(lpszPath)); + + _ILParsePathW(lpszPath, NULL, TRUE, &pidl, NULL); + TRACE("%s %p\n", debugstr_w(lpszPath), pidl); + return pidl; +} + +EXTERN_C LPITEMIDLIST WINAPI SHSimpleIDListFromPathAW(LPCVOID lpszPath) +{ + if ( SHELL_OsIsUnicode()) + return SHSimpleIDListFromPathW ((LPCWSTR)lpszPath); + return SHSimpleIDListFromPathA ((LPCSTR)lpszPath); +} + +/************************************************************************* + * SHGetDataFromIDListA [SHELL32.247] + * + * NOTES + * the pidl can be a simple one. since we can't get the path out of the pidl + * we have to take all data from the pidl + */ +HRESULT WINAPI SHGetDataFromIDListA(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, + int nFormat, LPVOID dest, int len) +{ + LPSTR filename, shortname; + WIN32_FIND_DATAA * pfd; + + TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); + + pdump(pidl); + if (!psf || !dest) + return E_INVALIDARG; + + switch (nFormat) + { + case SHGDFIL_FINDDATA: + pfd = (WIN32_FIND_DATAA *)dest; + + if (_ILIsDrive(pidl) || _ILIsSpecialFolder(pidl)) + return E_INVALIDARG; + + if (len < (int)sizeof(WIN32_FIND_DATAA)) + return E_INVALIDARG; + + ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA)); + _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); + pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); + pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); + + filename = _ILGetTextPointer(pidl); + shortname = _ILGetSTextPointer(pidl); + + if (filename) + lstrcpynA(pfd->cFileName, filename, sizeof(pfd->cFileName)); + else + pfd->cFileName[0] = '\0'; + + if (shortname) + lstrcpynA(pfd->cAlternateFileName, shortname, sizeof(pfd->cAlternateFileName)); + else + pfd->cAlternateFileName[0] = '\0'; + return NOERROR; + + case SHGDFIL_NETRESOURCE: + case SHGDFIL_DESCRIPTIONID: + FIXME_(shell)("SHGDFIL %i stub\n", nFormat); + break; + + default: + ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); + } + + return E_INVALIDARG; +} + +/************************************************************************* + * SHGetDataFromIDListW [SHELL32.248] + * + */ +HRESULT WINAPI SHGetDataFromIDListW(LPSHELLFOLDER psf, LPCITEMIDLIST pidl, + int nFormat, LPVOID dest, int len) +{ + LPSTR filename, shortname; + WIN32_FIND_DATAW * pfd = (WIN32_FIND_DATAW *)dest; + + TRACE_(shell)("sf=%p pidl=%p 0x%04x %p 0x%04x stub\n",psf,pidl,nFormat,dest,len); + + pdump(pidl); + + if (!psf || !dest) + return E_INVALIDARG; + + switch (nFormat) + { + case SHGDFIL_FINDDATA: + pfd = (WIN32_FIND_DATAW *)dest; + + if (_ILIsDrive(pidl)) + return E_INVALIDARG; + + if (len < (int)sizeof(WIN32_FIND_DATAW)) + return E_INVALIDARG; + + ZeroMemory(pfd, sizeof (WIN32_FIND_DATAA)); + _ILGetFileDateTime( pidl, &(pfd->ftLastWriteTime)); + pfd->dwFileAttributes = _ILGetFileAttributes(pidl, NULL, 0); + pfd->nFileSizeLow = _ILGetFileSize ( pidl, NULL, 0); + + filename = _ILGetTextPointer(pidl); + shortname = _ILGetSTextPointer(pidl); + + if (!filename) + pfd->cFileName[0] = '\0'; + else if (!MultiByteToWideChar(CP_ACP, 0, filename, -1, pfd->cFileName, MAX_PATH)) + pfd->cFileName[MAX_PATH-1] = 0; + + if (!shortname) + pfd->cAlternateFileName[0] = '\0'; + else if (!MultiByteToWideChar(CP_ACP, 0, shortname, -1, pfd->cAlternateFileName, 14)) + pfd->cAlternateFileName[13] = 0; + return NOERROR; + + case SHGDFIL_NETRESOURCE: + case SHGDFIL_DESCRIPTIONID: + FIXME_(shell)("SHGDFIL %i stub\n", nFormat); + break; + + default: + ERR_(shell)("Unknown SHGDFIL %i, please report\n", nFormat); + } + + return E_INVALIDARG; +} + +/************************************************************************* + * SHGetPathFromIDListA [SHELL32.@][NT 4.0: SHELL32.220] + * + * PARAMETERS + * pidl, [IN] pidl + * pszPath [OUT] path + * + * RETURNS + * path from a passed PIDL. + * + * NOTES + * NULL returns FALSE + * desktop pidl gives path to desktop directory back + * special pidls returning FALSE + */ +BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath) +{ + WCHAR wszPath[MAX_PATH]; + BOOL bSuccess; + + bSuccess = SHGetPathFromIDListW(pidl, wszPath); + WideCharToMultiByte(CP_ACP, 0, wszPath, -1, pszPath, MAX_PATH, NULL, NULL); + + return bSuccess; +} + +/************************************************************************* + * SHGetPathFromIDListW [SHELL32.@] + * + * See SHGetPathFromIDListA. + */ +BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath) +{ + HRESULT hr; + LPCITEMIDLIST pidlLast; + CComPtr psfFolder; + DWORD dwAttributes; + STRRET strret; + + TRACE_(shell)("(pidl=%p,%p)\n", pidl, pszPath); + pdump(pidl); + + *pszPath = '\0'; + if (!pidl) + return FALSE; + + hr = SHBindToParent(pidl, IID_IShellFolder, (VOID**)&psfFolder, &pidlLast); + if (FAILED(hr)) return FALSE; + + dwAttributes = SFGAO_FILESYSTEM; + hr = psfFolder->GetAttributesOf(1, &pidlLast, &dwAttributes); + if (FAILED(hr) || !(dwAttributes & SFGAO_FILESYSTEM)) { + return FALSE; + } + + hr = psfFolder->GetDisplayNameOf(pidlLast, SHGDN_FORPARSING, &strret); + if (FAILED(hr)) return FALSE; + + hr = StrRetToBufW(&strret, pidlLast, pszPath, MAX_PATH); + + TRACE_(shell)("-- %s, 0x%08x\n",debugstr_w(pszPath), hr); + return SUCCEEDED(hr); +} + +/************************************************************************* + * SHBindToParent [shell version 5.0] + */ +HRESULT WINAPI SHBindToParent(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppv, LPCITEMIDLIST *ppidlLast) +{ + CComPtr psfDesktop; + HRESULT hr=E_FAIL; + + TRACE_(shell)("pidl=%p\n", pidl); + pdump(pidl); + + if (!pidl || !ppv) + return E_INVALIDARG; + + *ppv = NULL; + if (ppidlLast) + *ppidlLast = NULL; + + hr = SHGetDesktopFolder(&psfDesktop); + if (FAILED(hr)) + return hr; + + if (_ILIsPidlSimple(pidl)) + { + /* we are on desktop level */ + hr = psfDesktop->QueryInterface(riid, ppv); + } + else + { + LPITEMIDLIST pidlParent = ILClone(pidl); + ILRemoveLastID(pidlParent); + hr = psfDesktop->BindToObject(pidlParent, NULL, riid, ppv); + SHFree (pidlParent); + } + + if (SUCCEEDED(hr) && ppidlLast) + *ppidlLast = ILFindLastID(pidl); + + TRACE_(shell)("-- psf=%p pidl=%p ret=0x%08x\n", *ppv, (ppidlLast)?*ppidlLast:NULL, hr); + return hr; +} + +/************************************************************************** + * + * internal functions + * + * ### 1. section creating pidls ### + * + ************************************************************************* + */ + +/* Basic PIDL constructor. Allocates size + 5 bytes, where: + * - two bytes are SHITEMID.cb + * - one byte is PIDLDATA.type + * - two bytes are the NULL PIDL terminator + * Sets type of the returned PIDL to type. + */ +static LPITEMIDLIST _ILAlloc(PIDLTYPE type, unsigned int size) +{ + LPITEMIDLIST pidlOut = NULL; + + pidlOut = (LPITEMIDLIST)SHAlloc(size + 5); + if(pidlOut) + { + LPPIDLDATA pData; + LPITEMIDLIST pidlNext; + + ZeroMemory(pidlOut, size + 5); + pidlOut->mkid.cb = size + 3; + + pData = _ILGetDataPointer(pidlOut); + if (pData) + pData->type = type; + + pidlNext = ILGetNext(pidlOut); + if (pidlNext) + pidlNext->mkid.cb = 0x00; + TRACE("-- (pidl=%p, size=%u)\n", pidlOut, size); + } + + return pidlOut; +} + +LPITEMIDLIST _ILCreateDesktop(void) +{ + LPITEMIDLIST ret; + + TRACE("()\n"); + ret = (LPITEMIDLIST)SHAlloc(2); + if (ret) + ret->mkid.cb = 0; + return ret; +} + +LPITEMIDLIST _ILCreateMyComputer(void) +{ + TRACE("()\n"); + return _ILCreateGuid(PT_GUID, CLSID_MyComputer); +} + +LPITEMIDLIST _ILCreateMyDocuments(void) +{ + TRACE("()\n"); + return _ILCreateGuid(PT_GUID, CLSID_MyDocuments); +} + +LPITEMIDLIST _ILCreateIExplore(void) +{ + TRACE("()\n"); + return _ILCreateGuid(PT_GUID, CLSID_Internet); +} + +LPITEMIDLIST _ILCreateControlPanel(void) +{ + LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, CLSID_MyComputer), ret = NULL; + + TRACE("()\n"); + if (parent) + { + LPITEMIDLIST cpl = _ILCreateGuid(PT_SHELLEXT, CLSID_ControlPanel); + + if (cpl) + { + ret = ILCombine(parent, cpl); + SHFree(cpl); + } + SHFree(parent); + } + return ret; +} + +LPITEMIDLIST _ILCreatePrinters(void) +{ + LPITEMIDLIST parent = _ILCreateGuid(PT_GUID, CLSID_MyComputer), ret = NULL; + + TRACE("()\n"); + if (parent) + { + LPITEMIDLIST printers = _ILCreateGuid(PT_YAGUID, CLSID_Printers); + + if (printers) + { + ret = ILCombine(parent, printers); + SHFree(printers); + } + SHFree(parent); + } + return ret; +} + +LPITEMIDLIST _ILCreateNetwork(void) +{ + TRACE("()\n"); + return _ILCreateGuid(PT_GUID, CLSID_NetworkPlaces); +} + +LPITEMIDLIST _ILCreateBitBucket(void) +{ + TRACE("()\n"); + return _ILCreateGuid(PT_GUID, CLSID_RecycleBin); +} + +LPITEMIDLIST _ILCreateAdminTools(void) +{ + TRACE("()\n"); + return _ILCreateGuid(PT_GUID, CLSID_AdminFolderShortcut); //FIXME +} + +LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid) +{ + LPITEMIDLIST pidlOut; + + if (type == PT_SHELLEXT || type == PT_GUID || type == PT_YAGUID) + { + pidlOut = _ILAlloc(type, sizeof(GUIDStruct)); + if (pidlOut) + { + LPPIDLDATA pData = _ILGetDataPointer(pidlOut); + + pData->u.guid.guid = guid; + TRACE("-- create GUID-pidl %s\n", + debugstr_guid(&(pData->u.guid.guid))); + } + } + else + { + WARN("%d: invalid type for GUID\n", type); + pidlOut = NULL; + } + return pidlOut; +} + +LPITEMIDLIST _ILCreateGuidFromStrA(LPCSTR szGUID) +{ + IID iid; + + if (FAILED(SHCLSIDFromStringA(szGUID, &iid))) + { + ERR("%s is not a GUID\n", szGUID); + return NULL; + } + return _ILCreateGuid(PT_GUID, iid); +} + +LPITEMIDLIST _ILCreateGuidFromStrW(LPCWSTR szGUID) +{ + IID iid; + + if (FAILED(CLSIDFromString((LPOLESTR)szGUID, &iid))) + { + ERR("%s is not a GUID\n", debugstr_w(szGUID)); + return NULL; + } + return _ILCreateGuid(PT_GUID, iid); +} + +LPITEMIDLIST _ILCreateFromFindDataW( const WIN32_FIND_DATAW *wfd ) +{ + char buff[MAX_PATH + 14 +1]; /* see WIN32_FIND_DATA */ + DWORD len, len1, wlen, alen; + LPITEMIDLIST pidl; + PIDLTYPE type; + + if (!wfd) + return NULL; + + TRACE("(%s, %s)\n",debugstr_w(wfd->cAlternateFileName), debugstr_w(wfd->cFileName)); + + /* prepare buffer with both names */ + len = WideCharToMultiByte(CP_ACP,0,wfd->cFileName,-1,buff,MAX_PATH,NULL,NULL); + len1 = WideCharToMultiByte(CP_ACP,0,wfd->cAlternateFileName,-1, buff+len, sizeof(buff)-len, NULL, NULL); + alen = len + len1; + + type = (wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? PT_FOLDER : PT_VALUE; + + wlen = wcslen(wfd->cFileName) + 1; + pidl = _ILAlloc(type, sizeof(FileStruct) + (alen + (alen & 1)) + + sizeof(FileStructW) + wlen * sizeof(WCHAR) + sizeof(WORD)); + if (pidl) + { + LPPIDLDATA pData = _ILGetDataPointer(pidl); + FileStruct *fs = &pData->u.file; + FileStructW *fsw; + WORD *pOffsetW; + + FileTimeToDosDateTime( &wfd->ftLastWriteTime, &fs->uFileDate, &fs->uFileTime); + fs->dwFileSize = wfd->nFileSizeLow; + fs->uFileAttribs = wfd->dwFileAttributes; + memcpy(fs->szNames, buff, alen); + + fsw = (FileStructW*)(pData->u.file.szNames + alen + (alen & 0x1)); + fsw->cbLen = sizeof(FileStructW) + wlen * sizeof(WCHAR) + sizeof(WORD); + FileTimeToDosDateTime( &wfd->ftCreationTime, &fsw->uCreationDate, &fsw->uCreationTime); + FileTimeToDosDateTime( &wfd->ftLastAccessTime, &fsw->uLastAccessDate, &fsw->uLastAccessTime); + memcpy(fsw->wszName, wfd->cFileName, wlen * sizeof(WCHAR)); + + pOffsetW = (WORD*)((LPBYTE)pidl + pidl->mkid.cb - sizeof(WORD)); + *pOffsetW = (LPBYTE)fsw - (LPBYTE)pidl; + TRACE("-- Set Value: %s\n",debugstr_w(fsw->wszName)); + } + return pidl; + +} + +HRESULT _ILCreateFromPathW(LPCWSTR szPath, LPITEMIDLIST* ppidl) +{ + HANDLE hFile; + WIN32_FIND_DATAW stffile; + + if (!ppidl) + return E_INVALIDARG; + + hFile = FindFirstFileW(szPath, &stffile); + if (hFile == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + + FindClose(hFile); + + *ppidl = _ILCreateFromFindDataW(&stffile); + + return *ppidl ? S_OK : E_OUTOFMEMORY; +} + +LPITEMIDLIST _ILCreateDrive(LPCWSTR lpszNew) +{ + LPITEMIDLIST pidlOut; + + TRACE("(%s)\n",debugstr_w(lpszNew)); + + pidlOut = _ILAlloc(PT_DRIVE, sizeof(DriveStruct)); + if (pidlOut) + { + LPSTR pszDest; + + pszDest = _ILGetTextPointer(pidlOut); + if (pszDest) + { + strcpy(pszDest, "x:\\"); + pszDest[0]=towupper(lpszNew[0]); + TRACE("-- create Drive: %s\n", debugstr_a(pszDest)); + } + } + return pidlOut; +} + +/************************************************************************** + * _ILGetDrive() + * + * Gets the text for the drive eg. 'c:\' + * + * RETURNS + * strlen (lpszText) + */ +DWORD _ILGetDrive(LPCITEMIDLIST pidl,LPSTR pOut, UINT uSize) +{ + TRACE("(%p,%p,%u)\n",pidl,pOut,uSize); + + if(_ILIsMyComputer(pidl)) + pidl = ILGetNext(pidl); + + if (pidl && _ILIsDrive(pidl)) + return _ILSimpleGetText(pidl, pOut, uSize); + + return 0; +} + +/************************************************************************** + * + * ### 2. section testing pidls ### + * + ************************************************************************** + * _ILIsUnicode() + * _ILIsDesktop() + * _ILIsMyComputer() + * _ILIsSpecialFolder() + * _ILIsDrive() + * _ILIsFolder() + * _ILIsValue() + * _ILIsPidlSimple() + */ +BOOL _ILIsUnicode(LPCITEMIDLIST pidl) +{ + LPPIDLDATA lpPData = _ILGetDataPointer(pidl); + + TRACE("(%p)\n",pidl); + + return (pidl && lpPData && PT_VALUEW == lpPData->type); +} + +BOOL _ILIsDesktop(LPCITEMIDLIST pidl) +{ + TRACE("(%p)\n",pidl); + + return pidl && pidl->mkid.cb ? 0 : 1; +} + +BOOL _ILIsMyDocuments(LPCITEMIDLIST pidl) +{ + IID *iid = _ILGetGUIDPointer(pidl); + + TRACE("(%p)\n",pidl); + + if (iid) + return IsEqualIID(*iid, CLSID_MyDocuments); + return FALSE; +} + +BOOL _ILIsControlPanel(LPCITEMIDLIST pidl) +{ + IID *iid = _ILGetGUIDPointer(pidl); + + TRACE("(%p)\n",pidl); + + if (iid) + return IsEqualIID(*iid, CLSID_ControlPanel); + return FALSE; +} + +BOOL _ILIsNetHood(LPCITEMIDLIST pidl) +{ + IID *iid = _ILGetGUIDPointer(pidl); + + TRACE("(%p)\n",pidl); + + if (iid) + return IsEqualIID(*iid, CLSID_NetworkPlaces); + return FALSE; +} + + +LPITEMIDLIST _ILCreateNetHood(void) +{ + return _ILCreateGuid(PT_GUID, CLSID_NetworkPlaces); +} + +LPITEMIDLIST _ILCreateFont(void) +{ + return _ILCreateGuid(PT_GUID, CLSID_FontsFolderShortcut); +} + +BOOL _ILIsMyComputer(LPCITEMIDLIST pidl) +{ + IID *iid = _ILGetGUIDPointer(pidl); + + TRACE("(%p)\n",pidl); + + if (iid) + return IsEqualIID(*iid, CLSID_MyComputer); + return FALSE; +} + +BOOL _ILIsPrinter(LPCITEMIDLIST pidl) +{ + IID *iid = _ILGetGUIDPointer(pidl); + + TRACE("(%p)\n",pidl); + + if (iid) + return IsEqualIID(*iid, CLSID_Printers); + return FALSE; +} + +BOOL _ILIsBitBucket(LPCITEMIDLIST pidl) +{ + IID *iid = _ILGetGUIDPointer(pidl); + + TRACE("(%p)\n",pidl); + + if (iid) + return IsEqualIID(*iid, CLSID_RecycleBin); + return FALSE; +} + +BOOL _ILIsAdminTools(LPCITEMIDLIST pidl) +{ + IID *iid = _ILGetGUIDPointer(pidl); + + TRACE("(%p)\n",pidl); + + if (iid) + return IsEqualIID(*iid, CLSID_AdminFolderShortcut); + else + return FALSE; +} + +BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl) +{ + LPPIDLDATA lpPData = _ILGetDataPointer(pidl); + + TRACE("(%p)\n",pidl); + + return (pidl && ( (lpPData && (PT_GUID== lpPData->type || PT_SHELLEXT== lpPData->type || PT_YAGUID == lpPData->type)) || + (pidl && pidl->mkid.cb == 0x00) + )); +} + +BOOL _ILIsDrive(LPCITEMIDLIST pidl) +{ + LPPIDLDATA lpPData = _ILGetDataPointer(pidl); + + TRACE("(%p)\n",pidl); + + return (pidl && lpPData && (PT_DRIVE == lpPData->type || + PT_DRIVE1 == lpPData->type || + PT_DRIVE2 == lpPData->type || + PT_DRIVE3 == lpPData->type)); +} + +BOOL _ILIsFolder(LPCITEMIDLIST pidl) +{ + LPPIDLDATA lpPData = _ILGetDataPointer(pidl); + + TRACE("(%p)\n",pidl); + + return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type)); +} + +BOOL _ILIsValue(LPCITEMIDLIST pidl) +{ + LPPIDLDATA lpPData = _ILGetDataPointer(pidl); + + TRACE("(%p)\n",pidl); + + return (pidl && lpPData && PT_VALUE == lpPData->type); +} + +BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl) +{ + LPPIDLDATA lpPData = _ILGetDataPointer(pidl); + + TRACE("(%p)\n",pidl); + + return (pidl && lpPData && (lpPData->type == 0)); +} + +/************************************************************************** + * _ILIsPidlSimple + */ +BOOL _ILIsPidlSimple(LPCITEMIDLIST pidl) +{ + BOOL ret = TRUE; + + if(! _ILIsDesktop(pidl)) /* pidl=NULL or mkid.cb=0 */ + { + WORD len = pidl->mkid.cb; + LPCITEMIDLIST pidlnext = (LPCITEMIDLIST) (((const BYTE*)pidl) + len ); + + if (pidlnext->mkid.cb) + ret = FALSE; + } + + TRACE("%s\n", ret ? "Yes" : "No"); + return ret; +} + +/************************************************************************** + * + * ### 3. section getting values from pidls ### + */ + + /************************************************************************** + * _ILSimpleGetText + * + * gets the text for the first item in the pidl (eg. simple pidl) + * + * returns the length of the string + */ +DWORD _ILSimpleGetText (LPCITEMIDLIST pidl, LPSTR szOut, UINT uOutSize) +{ + DWORD dwReturn=0; + LPSTR szSrc; + LPWSTR szSrcW; + GUID const * riid; + char szTemp[MAX_PATH]; + + TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); + + if (!pidl) + return 0; + + if (szOut) + *szOut = 0; + + if (_ILIsDesktop(pidl)) + { + /* desktop */ + if (HCR_GetClassNameA(CLSID_ShellDesktop, szTemp, MAX_PATH)) + { + if (szOut) + lstrcpynA(szOut, szTemp, uOutSize); + + dwReturn = strlen (szTemp); + } + } + else if (( szSrc = _ILGetTextPointer(pidl) )) + { + /* filesystem */ + if (szOut) + lstrcpynA(szOut, szSrc, uOutSize); + + dwReturn = strlen(szSrc); + } + else if (( szSrcW = _ILGetTextPointerW(pidl) )) + { + /* unicode filesystem */ + WideCharToMultiByte(CP_ACP,0,szSrcW, -1, szTemp, MAX_PATH, NULL, NULL); + + if (szOut) + lstrcpynA(szOut, szTemp, uOutSize); + + dwReturn = strlen (szTemp); + } + else if (( riid = _ILGetGUIDPointer(pidl) )) + { + /* special folder */ + if (HCR_GetClassNameA(*riid, szTemp, MAX_PATH) ) + { + if (szOut) + lstrcpynA(szOut, szTemp, uOutSize); + + dwReturn = strlen (szTemp); + } + } + else + { + ERR("-- no text\n"); + } + + TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_a(szOut),dwReturn); + return dwReturn; +} + + /************************************************************************** + * _ILSimpleGetTextW + * + * gets the text for the first item in the pidl (eg. simple pidl) + * + * returns the length of the string + */ +DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR szOut, UINT uOutSize) +{ + DWORD dwReturn; + FileStructW *pFileStructW = _ILGetFileStructW(pidl); + + TRACE("(%p %p %x)\n",pidl,szOut,uOutSize); + + if (pFileStructW) { + lstrcpynW(szOut, pFileStructW->wszName, uOutSize); + dwReturn = wcslen(pFileStructW->wszName); + } else { + GUID const * riid; + WCHAR szTemp[MAX_PATH]; + LPSTR szSrc; + LPWSTR szSrcW; + dwReturn=0; + + if (!pidl) + return 0; + + if (szOut) + *szOut = 0; + + if (_ILIsDesktop(pidl)) + { + /* desktop */ + if (HCR_GetClassNameW(CLSID_ShellDesktop, szTemp, MAX_PATH)) + { + if (szOut) + lstrcpynW(szOut, szTemp, uOutSize); + + dwReturn = wcslen (szTemp); + } + } + else if (( szSrcW = _ILGetTextPointerW(pidl) )) + { + /* unicode filesystem */ + if (szOut) + lstrcpynW(szOut, szSrcW, uOutSize); + + dwReturn = wcslen(szSrcW); + } + else if (( szSrc = _ILGetTextPointer(pidl) )) + { + /* filesystem */ + MultiByteToWideChar(CP_ACP, 0, szSrc, -1, szTemp, MAX_PATH); + + if (szOut) + lstrcpynW(szOut, szTemp, uOutSize); + + dwReturn = wcslen (szTemp); + } + else if (( riid = _ILGetGUIDPointer(pidl) )) + { + /* special folder */ + if ( HCR_GetClassNameW(*riid, szTemp, MAX_PATH) ) + { + if (szOut) + lstrcpynW(szOut, szTemp, uOutSize); + + dwReturn = wcslen (szTemp); + } + } + else + { + ERR("-- no text\n"); + } + } + + TRACE("-- (%p=%s 0x%08x)\n",szOut,debugstr_w(szOut),dwReturn); + return dwReturn; +} + +/************************************************************************** + * + * ### 4. getting pointers to parts of pidls ### + * + ************************************************************************** + * _ILGetDataPointer() + */ +LPPIDLDATA _ILGetDataPointer(LPCITEMIDLIST pidl) +{ + if(pidl && pidl->mkid.cb != 0x00) + return (LPPIDLDATA)pidl->mkid.abID; + return NULL; +} + +/************************************************************************** + * _ILGetTextPointerW() + * gets a pointer to the unicode long filename string stored in the pidl + */ +static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) +{ + /* TRACE(pidl,"(pidl%p)\n", pidl);*/ + + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + + if (!pdata) + return NULL; + + switch (pdata->type) + { + case PT_GUID: + case PT_SHELLEXT: + case PT_YAGUID: + return NULL; + + case PT_DRIVE: + case PT_DRIVE1: + case PT_DRIVE2: + case PT_DRIVE3: + /*return (LPSTR)&(pdata->u.drive.szDriveName);*/ + return NULL; + + case PT_FOLDER: + case PT_FOLDER1: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + /*return (LPSTR)&(pdata->u.file.szNames);*/ + return NULL; + + case PT_WORKGRP: + case PT_COMP: + case PT_NETWORK: + case PT_NETPROVIDER: + case PT_SHARE: + /*return (LPSTR)&(pdata->u.network.szNames);*/ + return NULL; + + case PT_VALUEW: + return (LPWSTR)pdata->u.file.szNames; + } + return NULL; +} + + +/************************************************************************** + * _ILGetTextPointer() + * gets a pointer to the long filename string stored in the pidl + */ +LPSTR _ILGetTextPointer(LPCITEMIDLIST pidl) +{ + /* TRACE(pidl,"(pidl%p)\n", pidl);*/ + + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + + if (!pdata) + return NULL; + + switch (pdata->type) + { + case PT_GUID: + case PT_SHELLEXT: + case PT_YAGUID: + return NULL; + + case PT_DRIVE: + case PT_DRIVE1: + case PT_DRIVE2: + case PT_DRIVE3: + return pdata->u.drive.szDriveName; + + case PT_FOLDER: + case PT_FOLDER1: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + return pdata->u.file.szNames; + + case PT_WORKGRP: + case PT_COMP: + case PT_NETWORK: + case PT_NETPROVIDER: + case PT_SHARE: + return pdata->u.network.szNames; + } + return NULL; +} + +/************************************************************************** + * _ILGetSTextPointer() + * gets a pointer to the short filename string stored in the pidl + */ +static LPSTR _ILGetSTextPointer(LPCITEMIDLIST pidl) +{ + /* TRACE(pidl,"(pidl%p)\n", pidl); */ + + LPPIDLDATA pdata =_ILGetDataPointer(pidl); + + if (!pdata) + return NULL; + + switch (pdata->type) + { + case PT_FOLDER: + case PT_VALUE: + case PT_IESPECIAL1: + case PT_IESPECIAL2: + return pdata->u.file.szNames + strlen (pdata->u.file.szNames) + 1; + + case PT_WORKGRP: + return pdata->u.network.szNames + strlen (pdata->u.network.szNames) + 1; + } + return NULL; +} + +/************************************************************************** + * _ILGetGUIDPointer() + * + * returns reference to guid stored in some pidls + */ +IID* _ILGetGUIDPointer(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata =_ILGetDataPointer(pidl); + + TRACE("%p\n", pidl); + + if (!pdata) + return NULL; + + TRACE("pdata->type 0x%04x\n", pdata->type); + switch (pdata->type) + { + case PT_SHELLEXT: + case PT_GUID: + case PT_YAGUID: + return &(pdata->u.guid.guid); + + default: + TRACE("Unknown pidl type 0x%04x\n", pdata->type); + break; + } + return NULL; +} + +/****************************************************************************** + * _ILGetFileStructW [Internal] + * + * Get pointer the a SHITEMID's FileStructW field if present + * + * PARAMS + * pidl [I] The SHITEMID + * + * RETURNS + * Success: Pointer to pidl's FileStructW field. + * Failure: NULL + */ +FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) { + FileStructW *pFileStructW; + WORD cbOffset; + + if (!(_ILIsValue(pidl) || _ILIsFolder(pidl))) + return NULL; + + cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD)); + pFileStructW = (FileStructW*)((LPBYTE)pidl + cbOffset); + + /* Currently I don't see a fool prove way to figure out if a pidl is for sure of WinXP + * style with a FileStructW member. If we switch all our shellfolder-implementations to + * the new format, this won't be a problem. For now, we do as many sanity checks as possible. */ + if (cbOffset & 0x1 || /* FileStructW member is word aligned in the pidl */ + /* FileStructW is positioned after FileStruct */ + cbOffset < sizeof(pidl->mkid.cb) + sizeof(PIDLTYPE) + sizeof(FileStruct) || + /* There has to be enough space at cbOffset in the pidl to hold FileStructW and cbOffset */ + cbOffset > pidl->mkid.cb - sizeof(cbOffset) - sizeof(FileStructW) || + pidl->mkid.cb != cbOffset + pFileStructW->cbLen) + { + WARN("Invalid pidl format (cbOffset = %d)!\n", cbOffset); + return NULL; + } + + return pFileStructW; +} + +/************************************************************************* + * _ILGetFileDateTime + * + * Given the ItemIdList, get the FileTime + * + * PARAMS + * pidl [I] The ItemIDList + * pFt [I] the resulted FILETIME of the file + * + * RETURNS + * True if Successful + * + * NOTES + * + */ +BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt) +{ + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + + if (!pdata) + return FALSE; + + switch (pdata->type) + { + case PT_FOLDER: + case PT_VALUE: + DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt); + break; + default: + return FALSE; + } + return TRUE; +} + +BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) +{ + FILETIME ft,lft; + SYSTEMTIME time; + BOOL ret; + + if (_ILGetFileDateTime( pidl, &ft )) + { + FileTimeToLocalFileTime(&ft, &lft); + FileTimeToSystemTime (&lft, &time); + + ret = GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&time, NULL, pOut, uOutSize); + if (ret) + { + /* Append space + time without seconds */ + pOut[ret-1] = ' '; + GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret); + } + } + else + { + pOut[0] = '\0'; + ret = FALSE; + } + return ret; +} + +/************************************************************************* + * _ILGetFileSize + * + * Given the ItemIdList, get the FileSize + * + * PARAMS + * pidl [I] The ItemIDList + * pOut [I] The buffer to save the result + * uOutsize [I] The size of the buffer + * + * RETURNS + * The FileSize + * + * NOTES + * pOut can be null when no string is needed + * + */ +DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) +{ + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + DWORD dwSize; + + if (!pdata) + return 0; + + switch (pdata->type) + { + case PT_VALUE: + dwSize = pdata->u.file.dwFileSize; + if (pOut) + StrFormatKBSizeA(dwSize, pOut, uOutSize); + return dwSize; + } + if (pOut) + *pOut = 0x00; + return 0; +} + +BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) +{ + char szTemp[MAX_PATH]; + const char * pPoint; + LPCITEMIDLIST pidlTemp=pidl; + + TRACE("pidl=%p\n",pidl); + + if (!pidl) + return FALSE; + + pidlTemp = ILFindLastID(pidl); + + if (!_ILIsValue(pidlTemp)) + return FALSE; + if (!_ILSimpleGetText(pidlTemp, szTemp, MAX_PATH)) + return FALSE; + + pPoint = PathFindExtensionA(szTemp); + + if (!*pPoint) + return FALSE; + + pPoint++; + lstrcpynA(pOut, pPoint, uOutSize); + TRACE("%s\n",pOut); + + return TRUE; +} + +/************************************************************************* + * _ILGetFileType + * + * Given the ItemIdList, get the file type description + * + * PARAMS + * pidl [I] The ItemIDList (simple) + * pOut [I] The buffer to save the result + * uOutsize [I] The size of the buffer + * + * RETURNS + * nothing + * + * NOTES + * This function copies as much as possible into the buffer. + */ +void _ILGetFileType(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) +{ + char sType[64]; + + if(_ILIsValue(pidl)) + { + char sTemp[64]; + + if(uOutSize > 0) + pOut[0] = 0; + if (_ILGetExtension (pidl, sType, 64)) + { + if (HCR_MapTypeToValueA(sType, sTemp, 64, TRUE)) + { + /* retrieve description */ + if(HCR_MapTypeToValueA(sTemp, pOut, uOutSize, FALSE )) + return; + } + /* display Ext-file as description */ + strcpy(pOut, sType); + _strupr(pOut); + /* load localized file string */ + sTemp[0] = '\0'; + if(LoadStringA(shell32_hInstance, IDS_SHV_COLUMN1, sTemp, 64)) + { + sTemp[63] = '\0'; + strcat(pOut, "-"); + strcat(pOut, sTemp); + } + } + } + else + { + pOut[0] = '\0'; + LoadStringA(shell32_hInstance, IDS_DIRECTORY, pOut, uOutSize); + /* make sure its null terminated */ + pOut[uOutSize-1] = '\0'; + } +} + +/************************************************************************* + * _ILGetFileAttributes + * + * Given the ItemIdList, get the Attrib string format + * + * PARAMS + * pidl [I] The ItemIDList + * pOut [I] The buffer to save the result + * uOutsize [I] The size of the Buffer + * + * RETURNS + * Attributes + * + * FIXME + * return value 0 in case of error is a valid return value + * + */ +DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPSTR pOut, UINT uOutSize) +{ + LPPIDLDATA pData = _ILGetDataPointer(pidl); + WORD wAttrib = 0; + int i; + + if (!pData) + return 0; + + switch(pData->type) + { + case PT_FOLDER: + case PT_VALUE: + wAttrib = pData->u.file.uFileAttribs; + break; + } + + if(uOutSize >= 6) + { + i=0; + if(wAttrib & FILE_ATTRIBUTE_READONLY) + pOut[i++] = 'R'; + if(wAttrib & FILE_ATTRIBUTE_HIDDEN) + pOut[i++] = 'H'; + if(wAttrib & FILE_ATTRIBUTE_SYSTEM) + pOut[i++] = 'S'; + if(wAttrib & FILE_ATTRIBUTE_ARCHIVE) + pOut[i++] = 'A'; + if(wAttrib & FILE_ATTRIBUTE_COMPRESSED) + pOut[i++] = 'C'; + pOut[i] = 0x00; + } + return wAttrib; +} + +/************************************************************************* + * ILFreeaPidl + * + * free a aPidl struct + */ +void _ILFreeaPidl(LPITEMIDLIST * apidl, UINT cidl) +{ + UINT i; + + if (apidl) + { + for (i = 0; i < cidl; i++) + SHFree(apidl[i]); + SHFree(apidl); + } +} + +/************************************************************************* + * ILCopyaPidl + * + * copies an aPidl struct + */ +LPITEMIDLIST* _ILCopyaPidl(const LPCITEMIDLIST * apidlsrc, UINT cidl) +{ + UINT i; + LPITEMIDLIST *apidldest; + + apidldest = (LPITEMIDLIST *)SHAlloc(cidl * sizeof(LPITEMIDLIST)); + if (!apidlsrc) + return NULL; + + for (i = 0; i < cidl; i++) + apidldest[i] = ILClone(apidlsrc[i]); + + return apidldest; +} + +/************************************************************************* + * _ILCopyCidaToaPidl + * + * creates aPidl from CIDA + */ +LPITEMIDLIST* _ILCopyCidaToaPidl(LPITEMIDLIST* pidl, const CIDA * cida) +{ + UINT i; + LPITEMIDLIST *dst; + + dst = (LPITEMIDLIST *)SHAlloc(cida->cidl * sizeof(LPITEMIDLIST)); + if (!dst) + return NULL; + + if (pidl) + *pidl = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[0]])); + + for (i = 0; i < cida->cidl; i++) + dst[i] = ILClone((LPCITEMIDLIST)(&((const BYTE*)cida)[cida->aoffset[i + 1]])); + + return dst; +} diff --git a/reactos/dll/win32/shell32/pidl.h b/reactos/dll/win32/shell32/pidl.h index 692f56f0a83..2ba343c5da6 100644 --- a/reactos/dll/win32/shell32/pidl.h +++ b/reactos/dll/win32/shell32/pidl.h @@ -163,7 +163,7 @@ typedef struct tagFileStruct WORD uFileDate; /*06*/ WORD uFileTime; /*08*/ WORD uFileAttribs; /*10*/ - CHAR szNames[1]; /*12*/ + CHAR szNames[0]; /*12*/ /* Here are coming two strings. The first is the long name. The second the dos name when needed or just 0x00 */ } FileStruct; @@ -179,7 +179,7 @@ typedef struct tagFileStructW { WORD uLastAccessDate; WORD uLastAccessTime; BYTE dummy2[4]; - WCHAR wszName[1]; + WCHAR wszName[0]; } FileStructW; typedef struct tagValueW diff --git a/reactos/dll/win32/shell32/precomp.h b/reactos/dll/win32/shell32/precomp.h index a4fca384777..1d2b4950f46 100644 --- a/reactos/dll/win32/shell32/precomp.h +++ b/reactos/dll/win32/shell32/precomp.h @@ -12,12 +12,8 @@ #include #define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT #define WIN32_NO_STATUS #define NTOS_MODE_USER -#define UNICODE -#define _UNICODE #include @@ -44,11 +40,16 @@ #include #include #include -#include +#include #include #include #include +#include +#include +#include +#include + #include "base/shell/explorer-new/todo.h" #include "dlgs.h" #include "pidl.h" @@ -64,6 +65,24 @@ #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" diff --git a/reactos/dll/win32/shell32/regsvr.cpp b/reactos/dll/win32/shell32/regsvr.cpp new file mode 100644 index 00000000000..4567aff5d2f --- /dev/null +++ b/reactos/dll/win32/shell32/regsvr.cpp @@ -0,0 +1,798 @@ +/* + * self-registerable dll functions for shell32.dll +* + * Copyright (C) 2003 John K. Hohm + * + * 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 + + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* + * Near the bottom of this file are the exported DllRegisterServer and + * DllUnregisterServer, which make all this worthwhile. + */ + +/*********************************************************************** + * interface for self-registering + */ +struct regsvr_interface +{ + IID const *iid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + IID const *base_iid; /* can be NULL to omit */ + int num_methods; /* can be <0 to omit */ + CLSID const *ps_clsid; /* can be NULL to omit */ + CLSID const *ps_clsid32; /* can be NULL to omit */ +}; + +static HRESULT register_interfaces(struct regsvr_interface const *list); +static HRESULT unregister_interfaces(struct regsvr_interface const *list); + +struct regsvr_coclass +{ + CLSID const *clsid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + UINT idName; /* can be 0 to omit */ + LPCSTR ips; /* can be NULL to omit */ + LPCSTR ips32; /* can be NULL to omit */ + LPCSTR ips32_tmodel; /* can be NULL to omit */ + DWORD flags; + DWORD dwAttributes; + DWORD dwCallForAttributes; + LPCSTR clsid_str; /* can be NULL to omit */ + LPCSTR progid; /* can be NULL to omit */ + UINT idDefaultIcon; /* can be 0 to omit */ +// CLSID const *clsid_menu; /* can be NULL to omit */ +}; + +/* flags for regsvr_coclass.flags */ +#define SHELLEX_MAYCHANGEDEFAULTMENU 0x00000001 +#define SHELLFOLDER_WANTSFORPARSING 0x00000002 +#define SHELLFOLDER_ATTRIBUTES 0x00000004 +#define SHELLFOLDER_CALLFORATTRIBUTES 0x00000008 +#define SHELLFOLDER_WANTSFORDISPLAY 0x00000010 +#define SHELLFOLDER_HIDEASDELETEPERUSER 0x00000020 + +static HRESULT register_coclasses(struct regsvr_coclass const *list); +static HRESULT unregister_coclasses(struct regsvr_coclass const *list); + +struct regsvr_namespace +{ + CLSID const *clsid; /* CLSID of the namespace extension. NULL for end of list */ + LPCWSTR parent; /* Mount point (MyComputer, Desktop, ..). */ + LPCWSTR value; /* Display name of the extension. */ +}; + +static HRESULT register_namespace_extensions(struct regsvr_namespace const *list); +static HRESULT unregister_namespace_extensions(struct regsvr_namespace const *list); + +/*********************************************************************** + * static helper functions + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); +static LONG register_key_defvalueW(HKEY base, WCHAR const *name, + WCHAR const *value); +static LONG register_key_defvalueA(HKEY base, WCHAR const *name, + char const *value); + +/*********************************************************************** + * register_interfaces + */ +static HRESULT register_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, L"Interface", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(*list->iid, buf, 39); + res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + + if (list->name) { + res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->base_iid) { + res = register_key_guid(iid_key, L"BaseInterface", list->base_iid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (0 <= list->num_methods) { + static WCHAR const fmt[3] = { '%', 'd', 0 }; + HKEY key; + + res = RegCreateKeyExW(iid_key, L"NumMethods", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + + swprintf(buf, fmt, list->num_methods); + res = RegSetValueExW(key, NULL, 0, REG_SZ, + (CONST BYTE*)buf, + (wcslen(buf) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid) { + res = register_key_guid(iid_key, L"ProxyStubClsid", list->ps_clsid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid32) { + res = register_key_guid(iid_key, L"ProxyStubClsid32", list->ps_clsid32); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + error_close_iid_key: + RegCloseKey(iid_key); + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_interfaces + */ +static HRESULT unregister_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Interface", 0, + KEY_READ | KEY_WRITE, &interface_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(*list->iid, buf, 39); + res = RegDeleteTreeW(interface_key, buf); + if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS; + } + + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * register_coclasses + */ +static HRESULT register_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, L"CLSID", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(*list->clsid, buf, 39); + res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->name) { + res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->idName) { + char buffer[64]; + sprintf(buffer, "@shell32.dll,-%u", list->idName); + res = RegSetValueExA(clsid_key, "LocalizedString", 0, REG_SZ, + (CONST BYTE*)(buffer), strlen(buffer)+1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->idDefaultIcon) { + HKEY icon_key; + char buffer[64]; + + res = RegCreateKeyExW(clsid_key, L"DefaultIcon", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &icon_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + sprintf(buffer, "shell32.dll,-%u", list->idDefaultIcon); + res = RegSetValueExA(icon_key, NULL, 0, REG_SZ, + (CONST BYTE*)(buffer), strlen(buffer)+1); + RegCloseKey(icon_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips) { + res = register_key_defvalueA(clsid_key, L"InProcServer", list->ips); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips32) { + HKEY ips32_key; + + res = RegCreateKeyExW(clsid_key, L"InProcServer32", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &ips32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->ips32, + lstrlenA(list->ips32) + 1); + if (res == ERROR_SUCCESS && list->ips32_tmodel) + res = RegSetValueExA(ips32_key, "ThreadingModel", 0, REG_SZ, + (CONST BYTE*)list->ips32_tmodel, + strlen(list->ips32_tmodel) + 1); + RegCloseKey(ips32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->flags & SHELLEX_MAYCHANGEDEFAULTMENU) { + HKEY shellex_key, mcdm_key; + + res = RegCreateKeyExW(clsid_key, L"shellex", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &shellex_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + res = RegCreateKeyExW(shellex_key, L"MayChangeDefaultMenu", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &mcdm_key, NULL); + RegCloseKey(shellex_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + RegCloseKey(mcdm_key); + } + + if (list->flags & + (SHELLFOLDER_WANTSFORPARSING|SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES|SHELLFOLDER_WANTSFORDISPLAY|SHELLFOLDER_HIDEASDELETEPERUSER)) + { + HKEY shellfolder_key; + + res = RegCreateKeyExW(clsid_key, L"ShellFolder", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &shellfolder_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + if (list->flags & SHELLFOLDER_WANTSFORPARSING) + res = RegSetValueExA(shellfolder_key, "WantsFORPARSING", 0, REG_SZ, (const BYTE *)"", 1); + if (list->flags & SHELLFOLDER_ATTRIBUTES) + res = RegSetValueExA(shellfolder_key, "Attributes", 0, REG_DWORD, + (const BYTE *)&list->dwAttributes, sizeof(DWORD)); + if (list->flags & SHELLFOLDER_CALLFORATTRIBUTES) + res = RegSetValueExA(shellfolder_key, "CallForAttributes", 0, REG_DWORD, + (const BYTE *)&list->dwCallForAttributes, sizeof(DWORD)); + if (list->flags & SHELLFOLDER_WANTSFORDISPLAY) + res = RegSetValueExA(shellfolder_key, "WantsFORDISPLAY", 0, REG_SZ, (const BYTE *)"", 1); + if (list->flags & SHELLFOLDER_HIDEASDELETEPERUSER) + res = RegSetValueExA(shellfolder_key, "HideAsDeletePerUser", 0, REG_SZ, (const BYTE *)"", 1); + RegCloseKey(shellfolder_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->clsid_str) { + res = register_key_defvalueA(clsid_key, L"CLSID", + list->clsid_str); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->progid) { + HKEY progid_key; + + res = register_key_defvalueA(clsid_key, L"ProgID", + list->progid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegCreateKeyExA(HKEY_CLASSES_ROOT, list->progid, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &progid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_key_defvalueW(progid_key, L"CLSID", buf); + RegCloseKey(progid_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + if (IsEqualIID(list->clsid, CLSID_RecycleBin)) {//if (list->clsid_menu) { + HKEY shellex_key, cmenu_key, menuhandler_key; + res = RegCreateKeyExW(clsid_key, L"shellex", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &shellex_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + res = RegCreateKeyExW(shellex_key, L"ContextMenuHandlers", 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &cmenu_key, NULL); + if (res != ERROR_SUCCESS) { + RegCloseKey(shellex_key); + goto error_close_clsid_key; + } + + StringFromGUID2(*list->clsid, buf, 39); //clsid_menu + res = RegCreateKeyExW(cmenu_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &menuhandler_key, NULL); + RegCloseKey(menuhandler_key); + RegCloseKey(cmenu_key); + RegCloseKey(shellex_key); + } + + error_close_clsid_key: + RegCloseKey(clsid_key); + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_coclasses + */ +static HRESULT unregister_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"CLSID", 0, + KEY_READ | KEY_WRITE, &coclass_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(*list->clsid, buf, 39); + res = RegDeleteTreeW(coclass_key, buf); + if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS; + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->progid) { + res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid); + if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS; + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/********************************************************************** + * register_namespace_extensions + */ +static WCHAR *get_namespace_key(struct regsvr_namespace const *list) { + static const WCHAR wszExplorerKey[] = { + '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','\\',0 }; + static const WCHAR wszNamespace[] = { '\\','N','a','m','e','s','p','a','c','e','\\',0 }; + WCHAR *pwszKey, *pwszCLSID; + + pwszKey = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, sizeof(wszExplorerKey)+sizeof(wszNamespace)+ + sizeof(WCHAR)*(wcslen(list->parent)+CHARS_IN_GUID)); + if (!pwszKey) + return NULL; + + wcscpy(pwszKey, wszExplorerKey); + wcscat(pwszKey, list->parent); + wcscat(pwszKey, wszNamespace); + if (FAILED(StringFromCLSID(*list->clsid, &pwszCLSID))) { + HeapFree(GetProcessHeap(), 0, pwszKey); + return NULL; + } + wcscat(pwszKey, pwszCLSID); + CoTaskMemFree(pwszCLSID); + + return pwszKey; +} + +static HRESULT register_namespace_extensions(struct regsvr_namespace const *list) { + WCHAR *pwszKey; + HKEY hKey; + + for (; list->clsid; list++) { + pwszKey = get_namespace_key(list); + + /* Create the key and set the value. */ + if (pwszKey && ERROR_SUCCESS == + RegCreateKeyExW(HKEY_LOCAL_MACHINE, pwszKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL)) + { + RegSetValueExW(hKey, NULL, 0, REG_SZ, (const BYTE *)list->value, sizeof(WCHAR)*(wcslen(list->value)+1)); + RegCloseKey(hKey); + } + + HeapFree(GetProcessHeap(), 0, pwszKey); + } + return S_OK; +} + +static HRESULT unregister_namespace_extensions(struct regsvr_namespace const *list) { + WCHAR *pwszKey; + + for (; list->clsid; list++) { + pwszKey = get_namespace_key(list); + RegDeleteKeyW(HKEY_LOCAL_MACHINE, pwszKey); + HeapFree(GetProcessHeap(), 0, pwszKey); + } + return S_OK; +} + +/*********************************************************************** + * regsvr_key_guid + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) +{ + WCHAR buf[39]; + + StringFromGUID2(*guid, buf, 39); + return register_key_defvalueW(base, name, buf); +} + +/*********************************************************************** + * regsvr_key_defvalueW + */ +static LONG register_key_defvalueW( + HKEY base, + WCHAR const *name, + WCHAR const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + (wcslen(value) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_key_defvalueA + */ +static LONG register_key_defvalueA( + HKEY base, + WCHAR const *name, + char const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + lstrlenA(value) + 1); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * coclass list + */ +static GUID const CLSID_Desktop = { + 0x00021400, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +static GUID const CLSID_Shortcut = { + 0x00021401, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +static struct regsvr_coclass const coclass_list[] = { + { + &CLSID_Desktop, + "Desktop", + IDS_DESKTOP, + NULL, + "shell32.dll", + "Apartment" + }, + { + &CLSID_ControlPanel, + "Shell Control Panel Folder", + IDS_CONTROLPANEL, + NULL, + "shell32.dll", + "Apartment", + SHELLFOLDER_WANTSFORDISPLAY|SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_HIDEASDELETEPERUSER, + SFGAO_FOLDER|SFGAO_HASSUBFOLDER, + 0, + NULL, + NULL, + IDI_SHELL_CONTROL_PANEL1 + }, + { + &CLSID_DragDropHelper, + "Shell Drag and Drop Helper", + 0, + NULL, + "shell32.dll", + "Apartment" + }, + { + &CLSID_Printers, + "Printers & Fax", + IDS_PRINTERS, + NULL, + "shell32.dll", + "Apartment", + SHELLFOLDER_ATTRIBUTES, + SFGAO_FOLDER, + 0, + NULL, + NULL, + IDI_SHELL_PRINTERS_FOLDER + }, + { + &CLSID_MyComputer, + "My Computer", + IDS_MYCOMPUTER, + NULL, + "shell32.dll", + "Apartment" + }, + { + &CLSID_NetworkPlaces, + "My Network Places", + IDS_NETWORKPLACE, + NULL, + "shell32.dll", + "Apartment", + SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES, + SFGAO_FOLDER|SFGAO_HASPROPSHEET, + 0, + NULL, + NULL, + IDI_SHELL_MY_NETWORK_PLACES + }, + { + &CLSID_FontsFolderShortcut, + "Fonts", + IDS_FONTS, + NULL, + "shell32.dll", + "Apartment", + SHELLFOLDER_ATTRIBUTES, + SFGAO_FOLDER, + 0, + NULL, + NULL, + IDI_SHELL_FONTS_FOLDER + }, + { + &CLSID_AdminFolderShortcut, + "Administrative Tools", + IDS_ADMINISTRATIVETOOLS, + NULL, + "shell32.dll", + "Apartment", + SHELLFOLDER_ATTRIBUTES, + SFGAO_FOLDER, + 0, + NULL, + NULL, + IDI_SHELL_ADMINTOOLS //FIXME + }, + { + &CLSID_Shortcut, + "Shortcut", + 0, + NULL, + "shell32.dll", + "Apartment", + SHELLEX_MAYCHANGEDEFAULTMENU + }, + { + &CLSID_AutoComplete, + "AutoComplete", + 0, + NULL, + "shell32.dll", + "Apartment", + }, + { + &CLSID_FolderShortcut, + "Foldershortcut", + 0, + NULL, + "shell32.dll", + "Apartment", + SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES, + SFGAO_FILESYSTEM|SFGAO_FOLDER|SFGAO_LINK, + SFGAO_HASSUBFOLDER|SFGAO_FILESYSTEM|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR + }, + { + &CLSID_MyDocuments, + "My Documents", + IDS_PERSONAL, + NULL, + "shell32.dll", + "Apartment", + SHELLFOLDER_WANTSFORPARSING|SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES, + SFGAO_FILESYSANCESTOR|SFGAO_FOLDER|SFGAO_HASSUBFOLDER, + SFGAO_FILESYSTEM + }, + { + &CLSID_RecycleBin, + "Trash", + IDS_RECYCLEBIN_FOLDER_NAME, + NULL, + "shell32.dll", + "Apartment", + SHELLFOLDER_ATTRIBUTES|SHELLFOLDER_CALLFORATTRIBUTES, + SFGAO_FOLDER|SFGAO_DROPTARGET|SFGAO_HASPROPSHEET, + 0, + NULL, + NULL, + IDI_SHELL_FULL_RECYCLE_BIN +// &CLSID_RecycleBin + }, + { + &CLSID_ShellFSFolder, + "Shell File System Folder", + 0, + NULL, + "shell32.dll", + "Apartment" + }, + { + &CLSID_ShellFolderViewOC, + "Microsoft Shell Folder View Router", + 0, + NULL, + "shell32.dll", + "Apartment" + }, + { + &CLSID_StartMenu, + "Start Menu", + 0, + NULL, + "shell32.dll", + "Apartment" + }, + { + &CLSID_MenuBandSite, + "Menu Site", + 0, + NULL, + "shell32.dll", + "Apartment" + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * interface list + */ + +static struct regsvr_interface const interface_list[] = { + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * namespace extensions list + */ +static const WCHAR wszDesktop[] = { 'D','e','s','k','t','o','p',0 }; +static const WCHAR wszSlash[] = { '/', 0 }; +static const WCHAR wszMyDocuments[] = { 'M','y',' ','D','o','c','u','m','e','n','t','s', 0 }; +static const WCHAR wszRecycleBin[] = { 'T','r','a','s','h', 0 }; +static const WCHAR wszMyComputer[] = { 'M','y','C','o','m','p','u','t','e','r',0 }; +static const WCHAR wszControlPanel[] = { 'C','o','n','t','r','o','l','P','a','n','e','l',0 }; +static const WCHAR wszFolderOptions[] = { 'F','o','l','d','e','r',' ','O','p','t','i','o','n','s',0 }; +static const WCHAR wszNethoodFolder[] = { 'N','e','t','h','o','o','d',' ','f','o','l','d','e','r',0}; +static const WCHAR wszPrinters[] = { 'P','r','i','n','t','e','r','s',0 }; +static const WCHAR wszFonts[] = { 'F','o','n','t','s',0 }; +static const WCHAR wszAdminTools[] = { 'A','d','m','i','n','T','o','o','l','s',0 }; + +static struct regsvr_namespace const namespace_extensions_list[] = { + { + &CLSID_MyDocuments, + L"Desktop", + L"My Documents" + }, + { + &CLSID_NetworkPlaces, + L"Desktop", + L"Nethood folder" + }, + { + &CLSID_RecycleBin, + L"Desktop", + L"Trash" + }, + { + &CLSID_ControlPanel, + L"MyComputer", + L"ControlPanel" + }, + { + &CLSID_FolderOptions, + L"ControlPanel" + L"Folder Options" + }, + { + &CLSID_FontsFolderShortcut, + L"ControlPanel" + L"Fonts" + }, + { + &CLSID_Printers, + L"ControlPanel" + L"Printers" + }, + { + &CLSID_AdminFolderShortcut, + L"ControlPanel" + L"AdminTools" + }, + { NULL } +}; + +/*********************************************************************** + * DllRegisterServer (SHELL32.@) + */ +EXTERN_C HRESULT WINAPI DllRegisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = register_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = register_interfaces(interface_list); + if (SUCCEEDED(hr)) + hr = SHELL_RegisterShellFolders(); + if (SUCCEEDED(hr)) + hr = register_namespace_extensions(namespace_extensions_list); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer (SHELL32.@) + */ +EXTERN_C HRESULT WINAPI DllUnregisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = unregister_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = unregister_interfaces(interface_list); + if (SUCCEEDED(hr)) + hr = unregister_namespace_extensions(namespace_extensions_list); + return hr; +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/adminfoldershortcut.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/adminfoldershortcut.rgs new file mode 100644 index 00000000000..5b031a8692b --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/adminfoldershortcut.rgs @@ -0,0 +1,56 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {D20EA4E1-3957-11d2-A40B-0C5020524153} = s 'Administrative Tools' + { + val '{305CA226-D286-468e-B848-2B2E8E697B74} 2' = d '5' + val InfoTip = s '@%SystemRoot%\system32\SHELL32.dll,-22921' + val LocalizedString = s '@%SystemRoot%\system32\SHELL32.dll,-22982' + DefaultIcon = s '%SystemRoot%\system32\main.cpl,10' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + Instance + { + val CLSID = s '{0AFACED1-E828-11D1-9187-B532F1E9575D}' + InitPropertyBag + { + val Attributes = s '0x00000011' + val TargetSpecialFolder = s '0x002f' + } + } + 'ShellFolder' + { + val Attributes = d '&H60000100' + val WantsFORPARSING = s '' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + ControlPanel + { + NameSpace + { + '{D20EA4E1-3957-11d2-A40B-0C5020524153}' = s 'Administrative Tools' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/autocomplete.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/autocomplete.rgs new file mode 100644 index 00000000000..9afd9d5cb86 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/autocomplete.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {00BB2763-6A77-11D0-A535-00C04FD7D062} = s 'Shell ReactOS AutoComplete' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/controlpanel.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/controlpanel.rgs new file mode 100644 index 00000000000..5164a1e3dea --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/controlpanel.rgs @@ -0,0 +1,52 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {21EC2020-3AEA-1069-A2DD-08002B30309D} + { + val InfoTip = s '@%SystemRoot%\system32\SHELL32.dll,-31361' + DefaultIcon = s '%SystemRoot%\System32\shell32.dll,-137' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + ShellFolder + { + val Attributes = d '0' + val HideAsDeletePerUser = s '' + val WantsFORDISPLAY = s '' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + ControlPanel + { + NameSpace + { + } + } + MyComputer + { + NameSpace + { + Controls = s '{21EC2020-3AEA-1069-A2DD-08002B30309D}' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/dragdrophelper.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/dragdrophelper.rgs new file mode 100644 index 00000000000..25d710d188c --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/dragdrophelper.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {4657278A-411B-11d2-839A-00C04FD918D0} = s 'Shell Drag and Drop helper' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/folderoptions.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/folderoptions.rgs new file mode 100644 index 00000000000..51010436450 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/folderoptions.rgs @@ -0,0 +1,56 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {6DFD7C5C-2451-11d3-A299-00C04F8EF6AF} = s 'Folder Options' + { + val '{305CA226-D286-468e-B848-2B2E8E697B74} 2' = d '1' + val InfoTip = s '@%SystemRoot%\system32\SHELL32.dll,-22924' + val LocalizedString = s '@%SystemRoot%\system32\SHELL32.dll,-22985' + DefaultIcon = s '%SystemRoot%\system32\SHELL32.dll,-210' + Shell + { + Open + { + Command = s 'rundll32.exe shell32.dll,Options_RunDLL 0' + } + RunAs + { + Command = s 'rundll32.exe shell32.dll,Options_RunDLL 0' + { + val Extended = s '' + } + } + } + ShellFolder + { + val Attributes = d '0' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + Desktop + { + NameSpace + { + '{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}' = s 'Folder Options' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/foldershortcut.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/foldershortcut.rgs new file mode 100644 index 00000000000..9df72086aed --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/foldershortcut.rgs @@ -0,0 +1,23 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {0AFACED1-E828-11D1-9187-B532F1E9575D} = s 'Folder Shortcut' + { + val Details = s 'prop:Name;LinkTarget' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'shellex' + { + IconHandler = s '{0AFACED1-E828-11D1-9187-B532F1E9575D}' + } + 'ShellFolder' + { + val Attributes = d '&H60410137' + val CallForAttributes = d '&Hf0000000' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/fontsfoldershortcut.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/fontsfoldershortcut.rgs new file mode 100644 index 00000000000..bc13f13c548 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/fontsfoldershortcut.rgs @@ -0,0 +1,56 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {D20EA4E1-3957-11d2-A40B-0C5020524152} = s 'Fonts' + { + val '{305CA226-D286-468e-B848-2B2E8E697B74} 2' = d '&Hffffffff' + val InfoTip = s '@%SystemRoot%\system32\SHELL32.dll,-22920' + val LocalizedString = s '@%SystemRoot%\system32\SHELL32.dll,-22981' + DefaultIcon = s '%SystemRoot%\system32\main.cpl,9' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + Instance + { + val CLSID = s '{0AFACED1-E828-11D1-9187-B532F1E9575D}' + InitPropertyBag + { + val Attributes = s '0x00000015' + val TargetSpecialFolder = s '0x0014' + } + } + 'ShellFolder' + { + val Attributes = d '&H60000100' + val WantsFORPARSING = s '' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + ControlPanel + { + NameSpace + { + '{D20EA4E1-3957-11d2-A40B-0C5020524152}' = s 'Fonts' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/menubandsite.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/menubandsite.rgs new file mode 100644 index 00000000000..c597e873135 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/menubandsite.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {E13EF4E4-D2F2-11d0-9816-00C04FD91972} = s 'Menu Site' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/mycomputer.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/mycomputer.rgs new file mode 100644 index 00000000000..6b60091ef8f --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/mycomputer.rgs @@ -0,0 +1,63 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {20D04FE0-3AEA-1069-A2D8-08002B30309D} = s 'My Computer' + { + val 'InfoTip' = s '@%SystemRoot%\system32\SHELL32.dll,-22913' + val 'IntroText' = s '@%SystemRoot%\system32\SHELL32.dll,-31751' + val 'LocalizedString' = s '@%SystemRoot%\system32\SHELL32.dll,-9216' + DefaultIcon = s '%SystemRoot%\Explorer.exe,0' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'ShellFolder' + { + val 'HideOnDesktopPerUser' = s '' + } + 'shell' + { + 'find' = s '@%SystemRoot%\system32\SHELL32.dll,-8503' + { + val 'SuppressionPolicy' = d '&H00000080' + 'command' = s '%SystemRoot%\Explorer.exe' + 'ddeexec' = s '[FindFolder("%l", %I)]' + { + 'application' = s 'Folders' + 'topic' = s 'AppProperties' + } + } + 'Manage' + { + 'command' = s '%windir%\system32\mmc.exe /s %windir%\system32\compmgmt.msc' + val 'SuppressionPolicy' = d '&H4000003c' + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + MyComputer + { + NameSpace + { + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/mydocuments.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/mydocuments.rgs new file mode 100644 index 00000000000..8b57afe0d85 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/mydocuments.rgs @@ -0,0 +1,67 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {450D8FBA-AD25-11D0-98A8-0800361B1103} + { + val 'InfoTip' = s '@%SystemRoot%\system32\SHELL32.dll,-22914' + val 'SortOrderIndex' = d '&H00000048' + val 'LocalizedString' = s '@%SystemRoot%\system32\SHELL32.dll,-9227' + DefaultIcon = s '%SystemRoot%\system32\SHELL32.dll,-235' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + val LoadWithoutCOM = s '' + } + 'ShellFolder' + { + val 'Attributes' = d '&Hf080013d' + val 'CallForAttributes' = d '&H00020040' + val 'HideOnDesktopPerUser' = s '' + val 'QueryForOverlay' = s '' + val 'WantsFORPARSING' = s '' + } + 'shell' + { + 'find' = s '@%SystemRoot%\system32\SHELL32.dll,-29188' + { + val 'SuppressionPolicy' = d '&H00000080' + 'command' = s '%SystemRoot%\Explorer.exe' + 'ddeexec' = s '[FindFolder("%l", %I)]' + { + 'application' = s 'Folders' + 'topic' = s 'AppProperties' + } + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + Desktop + { + NameSpace + { + '{450D8FBA-AD25-11D0-98A8-0800361B1103}' + { + val 'Removal Message' = s '@mydocs.dll,-900' + } + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/networkplaces.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/networkplaces.rgs new file mode 100644 index 00000000000..8ca1c84e583 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/networkplaces.rgs @@ -0,0 +1,58 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {208D2C60-3AEA-1069-A2D7-08002B30309D} = s 'My Network Places' + { + val 'InfoTip' = s '@%SystemRoot%\system32\SHELL32.dll,-22912' + val 'IntroText' = s '@%SystemRoot%\system32\SHELL32.dll,-31749' + val 'LocalizedString' = s '@%SystemRoot%\system32\SHELL32.dll,-9217' + DefaultIcon = s '%SystemRoot%\system32\SHELL32.dll,17' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'ShellFolder' + { + val 'HideOnDesktopPerUser' = s '' + } + 'shell' + { + 'find' = s '@%SystemRoot%\system32\SHELL32.dll,-29188' + { + val 'SuppressionPolicy' = d '&H00000080' + 'command' = s '%SystemRoot%\Explorer.exe' + 'ddeexec' = s '[FindFolder("%l", %I)]' + { + 'application' = s 'Folders' + 'topic' = s 'AppProperties' + } + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + NetworkNeighborhood + { + NameSpace + { + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/newmenu.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/newmenu.rgs new file mode 100644 index 00000000000..b3a6cab8f49 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/newmenu.rgs @@ -0,0 +1,14 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {D969A300-E7FF-11d0-A93B-00A0C90F2719} = s 'ReactOS New Object Service' + { + val flags = d '0' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/printers.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/printers.rgs new file mode 100644 index 00000000000..722170a8c71 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/printers.rgs @@ -0,0 +1,53 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {2227A280-3AEA-1069-A2DE-08002B30309D} = s 'Printers and Faxes' + { + val '{305CA226-D286-468e-B848-2B2E8E697B74} 2' = d '2' + val 'InfoTip' = s '@%SystemRoot%\system32\SHELL32.dll,-12696' + val 'IntroText' = s '@%SystemRoot%\system32\SHELL32.dll,-31757' + val 'LocalizedString' = s '@%SystemRoot%\system32\SHELL32.dll,-9319' + DefaultIcon = s '%SystemRoot%\System32\shell32.dll,-138' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'ShellFolder' + { + val 'Attributes' = d '&H20000004' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + Desktop + { + NameSpace + { + Printers = s '{2227A280-3AEA-1069-A2DE-08002B30309D}' + { + val 'IconIndex' = d '&H0000012C' + val 'Info' = s 'Adds, removes and changes settings for printers.' + val 'Module' = s '%SystemRoot%\system32\main.cpl' + val 'Name' = s 'Printers and Faxes' + } + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/recyclebin.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/recyclebin.rgs new file mode 100644 index 00000000000..dff8257e045 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/recyclebin.rgs @@ -0,0 +1,59 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {645FF040-5081-101B-9F08-00AA002F954E} + { + val 'InfoTip' = s '@%SystemRoot%\system32\SHELL32.dll,-22915' + val 'IntroText' = d '@%SystemRoot%\system32\SHELL32.dll,-31748' + val 'LocalizedString' = s '@%SystemRoot%\system32\SHELL32.dll,-8964' + DefaultIcon = s '%SystemRoot%\System32\shell32.dll,31' + { + val Empty = s '%SystemRoot%\System32\shell32.dll,31' + val Full = s '%SystemRoot%\System32\shell32.dll,32' + } + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'ShellFolder' + { + val 'Attributes' = b '&H40 &H01 &H00 &H20' + val 'CallForAttributes' = d '&H00000040' + } + 'shellex' + { + 'find' = s '@%SystemRoot%\system32\SHELL32.dll,-29188' + { + 'ContextMenuHandlers' + 'PropertySheetHandlers' + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + Desktop + { + NameSpace + { + '{645FF040-5081-101B-9F08-00AA002F954E}' = s 'Recycle Bin' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/shelldesktop.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/shelldesktop.rgs new file mode 100644 index 00000000000..f421c430cc2 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/shelldesktop.rgs @@ -0,0 +1,45 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {00021400-0000-0000-C000-000000000046} = s 'Desktop' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + shellex + { + ExtShellFolderViews + { + {5984FFE0-28D4-11CF-AE66-08002B2E1262} + val PersistMoniker = s 'file://%userappdata%\Microsoft\Internet Explorer\Desktop.htt' + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + Desktop + { + NameSpace + { + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/shellfsfolder.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/shellfsfolder.rgs new file mode 100644 index 00000000000..00d9daee97b --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/shellfsfolder.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {F3364BA0-65B9-11CE-A9BA-00AA004AE837} = s 'Shell File System Folder' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/shelllink.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/shelllink.rgs new file mode 100644 index 00000000000..a5972a70f9f --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/shelllink.rgs @@ -0,0 +1,23 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {00021401-0000-0000-C000-000000000046} = s 'Shortcut' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + PersistentAddinsRegistered + { + {89BCB740-6119-101A-BCB7-00DD010655AF} = s '{00021401-0000-0000-C000-000000000046}' + } + PersistentHandler = s '{00021401-0000-0000-C000-000000000046}' + ProgID = s 'lnkfile' + shellex + { + MayChangeDefaultMenu = s '' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/Copy of rgs/startmenu.rgs b/reactos/dll/win32/shell32/res/Copy of rgs/startmenu.rgs new file mode 100644 index 00000000000..a91a3464ec2 --- /dev/null +++ b/reactos/dll/win32/shell32/res/Copy of rgs/startmenu.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {4622AD11-FF23-11d0-8D34-00A0C90F2719} = s 'Start Menu' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/adminfoldershortcut.rgs b/reactos/dll/win32/shell32/res/rgs/adminfoldershortcut.rgs new file mode 100644 index 00000000000..bc66450a2af --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/adminfoldershortcut.rgs @@ -0,0 +1,56 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {D20EA4E1-3957-11d2-A40B-0C5020524153} = s 'Administrative Tools' + { + val '{305CA226-D286-468e-B848-2B2E8E697B74} 2' = d '5' + val InfoTip = e '@%%SystemRoot%%\system32\SHELL32.dll,-22921' + val LocalizedString = e '@%%SystemRoot%%\system32\SHELL32.dll,-22982' + DefaultIcon = e '%%SystemRoot%%\system32\main.cpl,10' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + Instance + { + val CLSID = s '{0AFACED1-E828-11D1-9187-B532F1E9575D}' + InitPropertyBag + { + val Attributes = s '0x00000011' + val TargetSpecialFolder = s '0x002f' + } + } + 'ShellFolder' + { + val Attributes = d '&H60000100' + val WantsFORPARSING = s '' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + NoRemove ControlPanel + { + NoRemove NameSpace + { + '{D20EA4E1-3957-11d2-A40B-0C5020524153}' = s 'Administrative Tools' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/autocomplete.rgs b/reactos/dll/win32/shell32/res/rgs/autocomplete.rgs new file mode 100644 index 00000000000..9afd9d5cb86 --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/autocomplete.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {00BB2763-6A77-11D0-A535-00C04FD7D062} = s 'Shell ReactOS AutoComplete' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/controlpanel.rgs b/reactos/dll/win32/shell32/res/rgs/controlpanel.rgs new file mode 100644 index 00000000000..298ff87c917 --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/controlpanel.rgs @@ -0,0 +1,52 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {21EC2020-3AEA-1069-A2DD-08002B30309D} + { + val InfoTip = e '@%%SystemRoot%%\system32\SHELL32.dll,-31361' + DefaultIcon = e '%%SystemRoot%%\System32\shell32.dll,-137' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + ShellFolder + { + val Attributes = d '0' + val HideAsDeletePerUser = s '' + val WantsFORDISPLAY = s '' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + ControlPanel + { + NameSpace + { + } + } + NoRemove MyComputer + { + NoRemove NameSpace + { + Controls = s '{21EC2020-3AEA-1069-A2DD-08002B30309D}' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/dragdrophelper.rgs b/reactos/dll/win32/shell32/res/rgs/dragdrophelper.rgs new file mode 100644 index 00000000000..25d710d188c --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/dragdrophelper.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {4657278A-411B-11d2-839A-00C04FD918D0} = s 'Shell Drag and Drop helper' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/folderoptions.rgs b/reactos/dll/win32/shell32/res/rgs/folderoptions.rgs new file mode 100644 index 00000000000..eead3b603a6 --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/folderoptions.rgs @@ -0,0 +1,56 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {6DFD7C5C-2451-11d3-A299-00C04F8EF6AF} = s 'Folder Options' + { + val '{305CA226-D286-468e-B848-2B2E8E697B74} 2' = d '1' + val InfoTip = e '@%%SystemRoot%%\system32\SHELL32.dll,-22924' + val LocalizedString = e '@%%SystemRoot%%\system32\SHELL32.dll,-22985' + DefaultIcon = e '%%SystemRoot%%\system32\SHELL32.dll,-210' + Shell + { + Open + { + Command = s 'rundll32.exe shell32.dll,Options_RunDLL 0' + } + RunAs + { + Command = s 'rundll32.exe shell32.dll,Options_RunDLL 0' + { + val Extended = s '' + } + } + } + ShellFolder + { + val Attributes = d '0' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + NoRemove ControlPanel + { + NoRemove NameSpace + { + '{6DFD7C5C-2451-11d3-A299-00C04F8EF6AF}' = s 'Folder Options' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/foldershortcut.rgs b/reactos/dll/win32/shell32/res/rgs/foldershortcut.rgs new file mode 100644 index 00000000000..9df72086aed --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/foldershortcut.rgs @@ -0,0 +1,23 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {0AFACED1-E828-11D1-9187-B532F1E9575D} = s 'Folder Shortcut' + { + val Details = s 'prop:Name;LinkTarget' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'shellex' + { + IconHandler = s '{0AFACED1-E828-11D1-9187-B532F1E9575D}' + } + 'ShellFolder' + { + val Attributes = d '&H60410137' + val CallForAttributes = d '&Hf0000000' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/fontsfoldershortcut.rgs b/reactos/dll/win32/shell32/res/rgs/fontsfoldershortcut.rgs new file mode 100644 index 00000000000..69591c6644f --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/fontsfoldershortcut.rgs @@ -0,0 +1,56 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {D20EA4E1-3957-11d2-A40B-0C5020524152} = s 'Fonts' + { + val '{305CA226-D286-468e-B848-2B2E8E697B74} 2' = d '&Hffffffff' + val InfoTip = e '@%%SystemRoot%%\system32\SHELL32.dll,-22920' + val LocalizedString = e '@%%SystemRoot%%\system32\SHELL32.dll,-22981' + DefaultIcon = e '%%SystemRoot%%\system32\main.cpl,9' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + Instance + { + val CLSID = s '{0AFACED1-E828-11D1-9187-B532F1E9575D}' + InitPropertyBag + { + val Attributes = s '0x00000015' + val TargetSpecialFolder = s '0x0014' + } + } + 'ShellFolder' + { + val Attributes = d '&H60000100' + val WantsFORPARSING = s '' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + NoRemove ControlPanel + { + NoRemove NameSpace + { + '{D20EA4E1-3957-11d2-A40B-0C5020524152}' = s 'Fonts' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/menubandsite.rgs b/reactos/dll/win32/shell32/res/rgs/menubandsite.rgs new file mode 100644 index 00000000000..c597e873135 --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/menubandsite.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {E13EF4E4-D2F2-11d0-9816-00C04FD91972} = s 'Menu Site' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/mycomputer.rgs b/reactos/dll/win32/shell32/res/rgs/mycomputer.rgs new file mode 100644 index 00000000000..85aa1496c1f --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/mycomputer.rgs @@ -0,0 +1,63 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {20D04FE0-3AEA-1069-A2D8-08002B30309D} = s 'My Computer' + { + val 'InfoTip' = e '@%%SystemRoot%%\system32\SHELL32.dll,-22913' + val 'IntroText' = e '@%%SystemRoot%%\system32\SHELL32.dll,-31751' + val 'LocalizedString' = e '@%%SystemRoot%%\system32\SHELL32.dll,-9216' + DefaultIcon = e '%%SystemRoot%%\Explorer.exe,0' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'ShellFolder' + { + val 'HideOnDesktopPerUser' = s '' + } + 'shell' + { + 'find' = e '@%%SystemRoot%%\system32\SHELL32.dll,-8503' + { + val 'SuppressionPolicy' = d '&H00000080' + 'command' = e '%%SystemRoot%%\Explorer.exe' + 'ddeexec' = s '[FindFolder("%%l", %%I)]' + { + 'application' = s 'Folders' + 'topic' = s 'AppProperties' + } + } + 'Manage' + { + 'command' = e '%%windir%%\system32\mmc.exe /s %%windir%%\system32\compmgmt.msc' + val 'SuppressionPolicy' = d '&H4000003c' + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + MyComputer + { + NameSpace + { + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/mydocuments.rgs b/reactos/dll/win32/shell32/res/rgs/mydocuments.rgs new file mode 100644 index 00000000000..9b65a9ad09e --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/mydocuments.rgs @@ -0,0 +1,67 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {450D8FBA-AD25-11D0-98A8-0800361B1103} + { + val 'InfoTip' = e '@%%SystemRoot%%\system32\SHELL32.dll,-22914' + val 'SortOrderIndex' = d '&H00000048' + val 'LocalizedString' = e '@%%SystemRoot%%\system32\SHELL32.dll,-9227' + DefaultIcon = e '%%SystemRoot%%\system32\SHELL32.dll,-235' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + val LoadWithoutCOM = s '' + } + 'ShellFolder' + { + val 'Attributes' = d '&Hf080013d' + val 'CallForAttributes' = d '&H00020040' + val 'HideOnDesktopPerUser' = s '' + val 'QueryForOverlay' = s '' + val 'WantsFORPARSING' = s '' + } + 'shell' + { + 'find' = e '@%%SystemRoot%%\system32\SHELL32.dll,-29188' + { + val 'SuppressionPolicy' = d '&H00000080' + 'command' = e '%%SystemRoot%%\Explorer.exe' + 'ddeexec' = s '[FindFolder("%%l", %%I)]' + { + 'application' = s 'Folders' + 'topic' = s 'AppProperties' + } + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + NoRemove Desktop + { + NoRemove NameSpace + { + '{450D8FBA-AD25-11D0-98A8-0800361B1103}' + { + val 'Removal Message' = s '@mydocs.dll,-900' + } + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/networkplaces.rgs b/reactos/dll/win32/shell32/res/rgs/networkplaces.rgs new file mode 100644 index 00000000000..da25a52dc2b --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/networkplaces.rgs @@ -0,0 +1,58 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {208D2C60-3AEA-1069-A2D7-08002B30309D} = s 'My Network Places' + { + val 'InfoTip' = e '@%%SystemRoot%%\system32\SHELL32.dll,-22912' + val 'IntroText' = e '@%%SystemRoot%%\system32\SHELL32.dll,-31749' + val 'LocalizedString' = e '@%%SystemRoot%%\system32\SHELL32.dll,-9217' + DefaultIcon = e '%%SystemRoot%%\system32\SHELL32.dll,17' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'ShellFolder' + { + val 'HideOnDesktopPerUser' = s '' + } + 'shell' + { + 'find' = e '@%%SystemRoot%%\system32\SHELL32.dll,-29188' + { + val 'SuppressionPolicy' = d '&H00000080' + 'command' = e '%%SystemRoot%%\Explorer.exe' + 'ddeexec' = s '[FindFolder("%%l", %%I)]' + { + 'application' = s 'Folders' + 'topic' = s 'AppProperties' + } + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + NetworkNeighborhood + { + NameSpace + { + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/newmenu.rgs b/reactos/dll/win32/shell32/res/rgs/newmenu.rgs new file mode 100644 index 00000000000..b3a6cab8f49 --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/newmenu.rgs @@ -0,0 +1,14 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {D969A300-E7FF-11d0-A93B-00A0C90F2719} = s 'ReactOS New Object Service' + { + val flags = d '0' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/printers.rgs b/reactos/dll/win32/shell32/res/rgs/printers.rgs new file mode 100644 index 00000000000..9277ae3b128 --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/printers.rgs @@ -0,0 +1,53 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {2227A280-3AEA-1069-A2DE-08002B30309D} = s 'Printers and Faxes' + { + val '{305CA226-D286-468e-B848-2B2E8E697B74} 2' = d '2' + val 'InfoTip' = e '@%%SystemRoot%%\system32\SHELL32.dll,-12696' + val 'IntroText' = e '@%%SystemRoot%%\system32\SHELL32.dll,-31757' + val 'LocalizedString' = e '@%%SystemRoot%%\system32\SHELL32.dll,-9319' + DefaultIcon = e '%%SystemRoot%%\System32\shell32.dll,-138' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'ShellFolder' + { + val 'Attributes' = d '&H20000004' + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + NoRemove Desktop + { + NoRemove NameSpace + { + Printers = s '{2227A280-3AEA-1069-A2DE-08002B30309D}' + { + val 'IconIndex' = d '&H0000012C' + val 'Info' = s 'Adds, removes and changes settings for printers.' + val 'Module' = e '%%SystemRoot%%\system32\main.cpl' + val 'Name' = s 'Printers and Faxes' + } + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/recyclebin.rgs b/reactos/dll/win32/shell32/res/rgs/recyclebin.rgs new file mode 100644 index 00000000000..b84d0db826c --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/recyclebin.rgs @@ -0,0 +1,59 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {645FF040-5081-101B-9F08-00AA002F954E} + { + val 'InfoTip' = e '@%%SystemRoot%%\system32\SHELL32.dll,-22915' + val 'IntroText' = e '@%%SystemRoot%%\system32\SHELL32.dll,-31748' + val 'LocalizedString' = e '@%%SystemRoot%%\system32\SHELL32.dll,-8964' + DefaultIcon = e '%%SystemRoot%%\System32\shell32.dll,31' + { + val Empty = e '%%SystemRoot%%\System32\shell32.dll,31' + val Full = e '%%SystemRoot%%\System32\shell32.dll,32' + } + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'ShellFolder' + { + val 'Attributes' = b '40010020' + val 'CallForAttributes' = d '&H00000040' + } + 'shellex' + { + 'find' = e '@%%SystemRoot%%\system32\SHELL32.dll,-29188' + { + 'ContextMenuHandlers' + 'PropertySheetHandlers' + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + NoRemove Desktop + { + NoRemove NameSpace + { + '{645FF040-5081-101B-9F08-00AA002F954E}' = s 'Recycle Bin' + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/shelldesktop.rgs b/reactos/dll/win32/shell32/res/rgs/shelldesktop.rgs new file mode 100644 index 00000000000..476fecab80f --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/shelldesktop.rgs @@ -0,0 +1,45 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {00021400-0000-0000-C000-000000000046} = s 'Desktop' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + shellex + { + ExtShellFolderViews + { + {5984FFE0-28D4-11CF-AE66-08002B2E1262} + val PersistMoniker = s 'file://%%userappdata%%\Microsoft\Internet Explorer\Desktop.htt' + } + } + } + } +} +HKLM +{ + NoRemove Software + { + NoRemove Microsoft + { + NoRemove Windows + { + NoRemove CurrentVersion + { + NoRemove Explorer + { + Desktop + { + NameSpace + { + } + } + } + } + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/shellfsfolder.rgs b/reactos/dll/win32/shell32/res/rgs/shellfsfolder.rgs new file mode 100644 index 00000000000..00d9daee97b --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/shellfsfolder.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {F3364BA0-65B9-11CE-A9BA-00AA004AE837} = s 'Shell File System Folder' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/shelllink.rgs b/reactos/dll/win32/shell32/res/rgs/shelllink.rgs new file mode 100644 index 00000000000..a5972a70f9f --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/shelllink.rgs @@ -0,0 +1,23 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {00021401-0000-0000-C000-000000000046} = s 'Shortcut' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + PersistentAddinsRegistered + { + {89BCB740-6119-101A-BCB7-00DD010655AF} = s '{00021401-0000-0000-C000-000000000046}' + } + PersistentHandler = s '{00021401-0000-0000-C000-000000000046}' + ProgID = s 'lnkfile' + shellex + { + MayChangeDefaultMenu = s '' + } + } + } +} diff --git a/reactos/dll/win32/shell32/res/rgs/startmenu.rgs b/reactos/dll/win32/shell32/res/rgs/startmenu.rgs new file mode 100644 index 00000000000..a91a3464ec2 --- /dev/null +++ b/reactos/dll/win32/shell32/res/rgs/startmenu.rgs @@ -0,0 +1,13 @@ +HKCR +{ + NoRemove CLSID + { + ForceRemove {4622AD11-FF23-11d0-8D34-00A0C90F2719} = s 'Start Menu' + { + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + } + } +} diff --git a/reactos/dll/win32/shell32/rgs_res.rc b/reactos/dll/win32/shell32/rgs_res.rc new file mode 100644 index 00000000000..6a37542b463 --- /dev/null +++ b/reactos/dll/win32/shell32/rgs_res.rc @@ -0,0 +1,22 @@ +///////////////////////////////////////////////////////////////////////////// +// +// REGISTRY +// +IDR_ADMINFOLDERSHORTCUT REGISTRY "res\\rgs\\adminfoldershortcut.rgs" +IDR_AUTOCOMPLETE REGISTRY "res\\rgs\\autocomplete.rgs" +IDR_CONTROLPANEL REGISTRY "res\\rgs\\controlpanel.rgs" +IDR_DRAGDROPHELPER REGISTRY "res\\rgs\\dragdrophelper.rgs" +IDR_FOLDEROPTIONS REGISTRY "res\\rgs\\folderoptions.rgs" +IDR_FOLDERSHORTCUT REGISTRY "res\\rgs\\foldershortcut.rgs" +IDR_FONTSFOLDERSHORTCUT REGISTRY "res\\rgs\\fontsfoldershortcut.rgs" +IDR_MENUBANDSITE REGISTRY "res\\rgs\\menubandsite.rgs" +IDR_MYCOMPUTER REGISTRY "res\\rgs\\mycomputer.rgs" +IDR_MYDOCUMENTS REGISTRY "res\\rgs\\mydocuments.rgs" +IDR_NETWORKPLACES REGISTRY "res\\rgs\\networkplaces.rgs" +IDR_NEWMENU REGISTRY "res\\rgs\\newmenu.rgs" +IDR_PRINTERS REGISTRY "res\\rgs\\printers.rgs" +IDR_RECYCLEBIN REGISTRY "res\\rgs\\recyclebin.rgs" +IDR_SHELLDESKTOP REGISTRY "res\\rgs\\shelldesktop.rgs" +IDR_SHELLFSFOLDER REGISTRY "res\\rgs\\shellfsfolder.rgs" +IDR_SHELLLINK REGISTRY "res\\rgs\\shelllink.rgs" +IDR_STARTMENU REGISTRY "res\\rgs\\startmenu.rgs" diff --git a/reactos/dll/win32/shell32/ros-systray.cpp b/reactos/dll/win32/shell32/ros-systray.cpp new file mode 100644 index 00000000000..1400c2ec114 --- /dev/null +++ b/reactos/dll/win32/shell32/ros-systray.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2004 Martin Fuchs + * + * Pass on icon notification messages to the systray implementation + * in the currently running shell. + * + * 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 + */ + +#include + + /* copy data structure for tray notifications */ +typedef struct TrayNotifyCDS_Dummy { + DWORD cookie; + DWORD notify_code; + DWORD nicon_data[1]; // placeholder for NOTIFYICONDATA structure +} TrayNotifyCDS_Dummy; + + /* The only difference between Shell_NotifyIconA and Shell_NotifyIconW is the call to SendMessageA/W. */ +static BOOL SHELL_NotifyIcon(DWORD dwMessage, void* pnid, HWND nid_hwnd, int nid_size, BOOL unicode) +{ + HWND hwnd; + COPYDATASTRUCT data; + + BOOL ret = FALSE; + int len = sizeof(TrayNotifyCDS_Dummy)-sizeof(DWORD)+nid_size; + + TrayNotifyCDS_Dummy* pnotify_data = (TrayNotifyCDS_Dummy*) alloca(len); + + pnotify_data->cookie = 1; + pnotify_data->notify_code = dwMessage; + memcpy(&pnotify_data->nicon_data, pnid, nid_size); + + data.dwData = 1; + data.cbData = len; + data.lpData = pnotify_data; + + for(hwnd=0; (hwnd=FindWindowExW(0, hwnd, L"Shell_TrayWnd", NULL)); ) + if ((unicode?SendMessageW:SendMessageA)(hwnd, WM_COPYDATA, (WPARAM)nid_hwnd, (LPARAM)&data)) + ret = TRUE; + + return ret; +} + + +/************************************************************************* + * Shell_NotifyIcon [SHELL32.296] + * Shell_NotifyIconA [SHELL32.297] + */ +BOOL WINAPI Shell_NotifyIconA(DWORD dwMessage, PNOTIFYICONDATAA pnid) +{ + return SHELL_NotifyIcon(dwMessage, pnid, pnid->hWnd, pnid->cbSize, FALSE); +} + +/************************************************************************* + * Shell_NotifyIconW [SHELL32.298] + */ +BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW pnid) +{ + return SHELL_NotifyIcon(dwMessage, pnid, pnid->hWnd, pnid->cbSize, TRUE); +} diff --git a/reactos/dll/win32/shell32/she_ocmenu.cpp b/reactos/dll/win32/shell32/she_ocmenu.cpp new file mode 100644 index 00000000000..d15bb22d96e --- /dev/null +++ b/reactos/dll/win32/shell32/she_ocmenu.cpp @@ -0,0 +1,1136 @@ +/* + * Open With Context Menu extension + * + * Copyright 2007 Johannes Anderwald + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL (shell); + +/// +/// [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system] +/// "NoInternetOpenWith"=dword:00000001 +/// + +// TODO +// implement duplicate checks in list box +// implement duplicate checks for MRU! +// implement owner drawn menu + +typedef struct +{ + BOOL bMenu; + HMENU hMenu; + HWND hDlgCtrl; + UINT Count; + BOOL NoOpen; + UINT idCmdFirst; +}OPEN_WITH_CONTEXT, *POPEN_WITH_CONTEXT; + +#define MANUFACTURER_NAME_SIZE 100 + +typedef struct +{ + HICON hIcon; + WCHAR szAppName[MAX_PATH]; + WCHAR szManufacturer[MANUFACTURER_NAME_SIZE]; +}OPEN_ITEM_CONTEXT, *POPEN_ITEM_CONTEXT; + + +typedef struct _LANGANDCODEPAGE_ + { + WORD lang; + WORD code; +} LANGANDCODEPAGE, *LPLANGANDCODEPAGE; + +HANDLE OpenMRUList(HKEY hKey); + +void LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext, const WCHAR * szExt); +void LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext, const WCHAR * szExt); +void InsertOpenWithItem(POPEN_WITH_CONTEXT pContext, WCHAR * szAppName); + +COpenWithMenu::COpenWithMenu() +{ + count = 0; + wId = 0; +} + +COpenWithMenu::~COpenWithMenu() +{ + TRACE(" destroying IContextMenu(%p)\n", this); +} + +VOID +AddItem(HMENU hMenu, UINT idCmdFirst) +{ + MENUITEMINFOW mii; + WCHAR szBuffer[MAX_PATH]; + static const WCHAR szChoose[] = { 'C','h','o','o','s','e',' ','P','r','o','g','r','a','m','.','.','.',0 }; + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_TYPE | MIIM_ID; + mii.fType = MFT_SEPARATOR; + mii.wID = -1; + InsertMenuItemW(hMenu, -1, TRUE, &mii); + + if (!LoadStringW(shell32_hInstance, IDS_OPEN_WITH_CHOOSE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) + wcscpy(szBuffer, szChoose); + + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; + mii.fType = MFT_STRING; + mii.fState = MFS_ENABLED; + mii.wID = idCmdFirst; + mii.dwTypeData = (LPWSTR)szBuffer; + mii.cch = wcslen(szBuffer); + + InsertMenuItemW(hMenu, -1, TRUE, &mii); +} + +static +void +LoadOWItems(POPEN_WITH_CONTEXT pContext, LPCWSTR szName) +{ + const WCHAR * szExt; + WCHAR szPath[100]; + DWORD dwPath; + + szExt = wcsrchr(szName, '.'); + if (!szExt) + { + /* FIXME + * show default list of available programs + */ + return; + } + + /* load programs directly associated from HKCU */ + LoadItemFromHKCU(pContext, szExt); + + /* load programs associated from HKCR\Extension */ + LoadItemFromHKCR(pContext, szExt); + + /* load programs referenced from HKCR\ProgId */ + dwPath = sizeof(szPath); + szPath[0] = 0; + if (RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, szPath, &dwPath) == ERROR_SUCCESS) + { + szPath[(sizeof(szPath)/sizeof(WCHAR))-1] = L'\0'; + LoadItemFromHKCR(pContext, szPath); + } +} + + + +HRESULT WINAPI COpenWithMenu::QueryContextMenu( + HMENU hmenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags) +{ + MENUITEMINFOW mii; + WCHAR szBuffer[100] = {0}; + INT pos; + HMENU hSubMenu = NULL; + OPEN_WITH_CONTEXT Context; + + if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)) < 0) + { + TRACE("failed to load string\n"); + return E_FAIL; + } + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + + hSubMenu = CreatePopupMenu(); + + /* set up context */ + ZeroMemory(&Context, sizeof(OPEN_WITH_CONTEXT)); + Context.bMenu = TRUE; + Context.Count = 0; + Context.hMenu = hSubMenu; + Context.idCmdFirst = idCmdFirst; + /* load items */ + LoadOWItems(&Context, szPath); + if (!Context.Count) + { + DestroyMenu(hSubMenu); + hSubMenu = NULL; + wId = 0; + count = 0; + } + else + { + AddItem(hSubMenu, Context.idCmdFirst++); + count = Context.idCmdFirst - idCmdFirst; + /* verb start at index zero */ + wId = count -1; + hSubMenu = hSubMenu; + } + + pos = GetMenuDefaultItem(hmenu, TRUE, 0) + 1; + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; + if (hSubMenu) + { + mii.fMask |= MIIM_SUBMENU; + mii.hSubMenu = hSubMenu; + } + mii.dwTypeData = (LPWSTR) szBuffer; + mii.fState = MFS_ENABLED; + if (!pos) + { + mii.fState |= MFS_DEFAULT; + } + + mii.wID = Context.idCmdFirst; + mii.fType = MFT_STRING; + if (InsertMenuItemW( hmenu, pos, TRUE, &mii)) + Context.Count++; + + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Context.Count); +} + +void +FreeListItems(HWND hwndDlg) +{ + HWND hList; + LRESULT iIndex, iCount; + POPEN_ITEM_CONTEXT pContext; + + hList = GetDlgItem(hwndDlg, 14002); + iCount = SendMessageW(hList, LB_GETCOUNT, 0, 0); + if (iCount == LB_ERR) + return; + + for (iIndex = 0; iIndex < iCount; iIndex++) + { + pContext = (POPEN_ITEM_CONTEXT)SendMessageW(hList, LB_GETITEMDATA, iIndex, 0); + if (pContext) + { + DestroyIcon(pContext->hIcon); + SendMessageW(hList, LB_SETITEMDATA, iIndex, (LPARAM)0); + HeapFree(GetProcessHeap(), 0, pContext); + } + } +} + +BOOL HideApplicationFromList(WCHAR * pFileName) +{ + WCHAR szBuffer[100] = {'A','p','p','l','i','c','a','t','i','o','n','s','\\',0}; + DWORD dwSize = 0; + LONG result; + + if (wcslen(pFileName) > (sizeof(szBuffer)/sizeof(WCHAR)) - 14) + { + ERR("insufficient buffer\n"); + return FALSE; + } + wcscpy(&szBuffer[13], pFileName); + + result = RegGetValueW(HKEY_CLASSES_ROOT, szBuffer, L"NoOpenWith", RRF_RT_REG_SZ, NULL, NULL, &dwSize); + + TRACE("result %d szBuffer %s\n", result, debugstr_w(szBuffer)); + + if (result == ERROR_SUCCESS) + return TRUE; + else + return FALSE; +} + +VOID +WriteStaticShellExtensionKey(HKEY hRootKey, const WCHAR * pVerb, WCHAR *pFullPath) +{ + HKEY hShell; + LONG result; + WCHAR szBuffer[MAX_PATH+10] = {'s','h','e','l','l','\\', 0 }; + + if (wcslen(pVerb) > (sizeof(szBuffer)/sizeof(WCHAR)) - 15 || + wcslen(pFullPath) > (sizeof(szBuffer)/sizeof(WCHAR)) - 4) + { + ERR("insufficient buffer\n"); + return; + } + + /* construct verb reg path */ + wcscpy(&szBuffer[6], pVerb); + wcscat(szBuffer, L"\\command"); + + /* create verb reg key */ + if (RegCreateKeyExW(hRootKey, szBuffer, 0, NULL, 0, KEY_WRITE, NULL, &hShell, NULL) != ERROR_SUCCESS) + return; + + /* build command buffer */ + wcscpy(szBuffer, pFullPath); + wcscat(szBuffer, L" %1"); + + result = RegSetValueExW(hShell, NULL, 0, REG_SZ, (const BYTE*)szBuffer, (wcslen(szBuffer)+1)* sizeof(WCHAR)); + RegCloseKey(hShell); +} + +VOID +StoreNewSettings(LPCWSTR szFileName, WCHAR *szAppName) +{ + WCHAR szBuffer[100] = { L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\"}; + const WCHAR * pFileExt; + HKEY hKey; + LONG result; + HANDLE hList; + + /* get file extension */ + pFileExt = wcsrchr(szFileName, L'.'); + if (wcslen(pFileExt) > (sizeof(szBuffer)/sizeof(WCHAR)) - 60) + { + ERR("insufficient buffer\n"); + return; + } + wcscpy(&szBuffer[60], pFileExt); + /* open base key for this file extension */ + if (RegCreateKeyExW(HKEY_CURRENT_USER, szBuffer, 0, NULL, 0, KEY_WRITE | KEY_READ, NULL, &hKey, NULL) != ERROR_SUCCESS) + return; + + /* open mru list */ + hList = OpenMRUList(hKey); + + if (!hList) + { + RegCloseKey(hKey); + return; + } + + /* insert the entry */ + result = AddMRUStringW(hList, szAppName); + + /* close mru list */ + FreeMRUList(hList); + /* create mru list key */ + RegCloseKey(hKey); +} + +VOID +SetProgrammAsDefaultHandler(LPCWSTR szFileName, WCHAR * szAppName) +{ + HKEY hKey; + HKEY hAppKey; + DWORD dwDisposition; + WCHAR szBuffer[100]; + DWORD dwSize; + BOOL result; + const WCHAR * pFileExt; + WCHAR * pFileName; + + /* extract file extension */ + pFileExt = wcsrchr(szFileName, L'.'); + if (!pFileExt) + return; + + /* create file extension key */ + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, pFileExt, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) + return; + + if (dwDisposition & REG_CREATED_NEW_KEY) + { + /* a new entry was created create the prog key id */ + wcscpy(szBuffer, &pFileExt[1]); + wcscat(szBuffer, L"_auto_file"); + if (RegSetValueExW(hKey, NULL, 0, REG_SZ, (const BYTE*)szBuffer, (wcslen(szBuffer)+1) * sizeof(WCHAR)) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + return; + } + } + else + { + /* entry already exists fetch prog key id */ + dwSize = sizeof(szBuffer); + if (RegGetValueW(hKey, NULL, NULL, RRF_RT_REG_SZ, NULL, szBuffer, &dwSize) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + return; + } + } + /* close file extension key */ + RegCloseKey(hKey); + + /* create prog id key */ + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) + return; + + + /* check if there already verbs existing for that app */ + pFileName = wcsrchr(szAppName, L'\\'); + wcscpy(szBuffer, L"Classes\\Applications\\"); + wcscat(szBuffer, pFileName); + wcscat(szBuffer, L"\\shell"); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ, &hAppKey) == ERROR_SUCCESS) + { + /* copy static verbs from Classes\Applications key */ + HKEY hTemp; + if (RegCreateKeyExW(hKey, L"shell", 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hTemp, &dwDisposition) == ERROR_SUCCESS) + { + result = RegCopyTreeW(hAppKey, NULL, hTemp); + RegCloseKey(hTemp); + if (result == ERROR_SUCCESS) + { + /* copied all subkeys, we are done */ + RegCloseKey(hKey); + RegCloseKey(hAppKey); + return; + } + } + RegCloseKey(hAppKey); + } + /* write standard static shell extension */ + WriteStaticShellExtensionKey(hKey, L"open", szAppName); + RegCloseKey(hKey); +} + +void +BrowseForApplication(HWND hwndDlg) +{ + WCHAR szBuffer[64] = {0}; + WCHAR szFilter[256] = {0}; + WCHAR szPath[MAX_PATH]; + OPENFILENAMEW ofn; + OPEN_WITH_CONTEXT Context; + INT count; + + /* load resource open with */ + if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + ofn.lpstrTitle = szBuffer; + ofn.nMaxFileTitle = wcslen(szBuffer); + } + + ZeroMemory(&ofn, sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hInstance = shell32_hInstance; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + ofn.nMaxFile = (sizeof(szPath) / sizeof(WCHAR)); + ofn.lpstrFile = szPath; + + /* load the filter resource string */ + if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH_FILTER, szFilter, sizeof(szFilter) / sizeof(WCHAR))) + { + szFilter[(sizeof(szFilter)/sizeof(WCHAR))-1] = 0; + ofn.lpstrFilter = szFilter; + } + ZeroMemory(szPath, sizeof(szPath)); + + /* call openfilename */ + if (!GetOpenFileNameW(&ofn)) + return; + + /* setup context for insert proc */ + ZeroMemory(&Context, sizeof(OPEN_WITH_CONTEXT)); + Context.hDlgCtrl = GetDlgItem(hwndDlg, 14002); + count = SendMessage(Context.hDlgCtrl, LB_GETCOUNT, 0, 0); + InsertOpenWithItem(&Context, szPath); + /* select new item */ + SendMessage(Context.hDlgCtrl, LB_SETCURSEL, count, 0); +} + +POPEN_ITEM_CONTEXT +GetCurrentOpenItemContext(HWND hwndDlg) +{ + LRESULT result; + + /* get current item */ + result = SendDlgItemMessage(hwndDlg, 14002, LB_GETCURSEL, 0, 0); + if(result == LB_ERR) + return NULL; + + /* get item context */ + result = SendDlgItemMessage(hwndDlg, 14002, LB_GETITEMDATA, result, 0); + if (result == LB_ERR) + return NULL; + + return (POPEN_ITEM_CONTEXT)result; +} + +void +ExecuteOpenItem(POPEN_ITEM_CONTEXT pItemContext, LPCWSTR FileName) +{ + STARTUPINFOW si; + PROCESS_INFORMATION pi; + WCHAR szPath[(MAX_PATH * 2)]; + + /* setup path with argument */ + ZeroMemory(&si, sizeof(STARTUPINFOW)); + si.cb = sizeof(STARTUPINFOW); + wcscpy(szPath, pItemContext->szAppName); + wcscat(szPath, L" "); + wcscat(szPath, FileName); + + ERR("path %s\n", debugstr_w(szPath)); + + if (CreateProcessW(NULL, szPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + SHAddToRecentDocs(SHARD_PATHW, FileName); + } +} + + +static INT_PTR CALLBACK OpenWithProgrammDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LPMEASUREITEMSTRUCT lpmis; + LPDRAWITEMSTRUCT lpdis; + INT index; + WCHAR szBuffer[MAX_PATH + 30] = { 0 }; + OPENASINFO *poainfo; + TEXTMETRIC mt; + COLORREF preColor, preBkColor; + POPEN_ITEM_CONTEXT pItemContext; + LONG YOffset; + OPEN_WITH_CONTEXT Context; + + poainfo = (OPENASINFO*) GetWindowLongPtr(hwndDlg, DWLP_USER); + + switch(uMsg) + { + case WM_INITDIALOG: + SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG)lParam); + poainfo = (OPENASINFO*)lParam; + if (!(poainfo->oaifInFlags & OAIF_ALLOW_REGISTRATION)) + EnableWindow(GetDlgItem(hwndDlg, 14003), FALSE); + if (poainfo->oaifInFlags & OAIF_FORCE_REGISTRATION) + SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_CHECKED, 0); + if (poainfo->oaifInFlags & OAIF_HIDE_REGISTRATION) + ShowWindow(GetDlgItem(hwndDlg, 14003), SW_HIDE); + if (poainfo->pcszFile) + { + szBuffer[0] = L'\0'; + SendDlgItemMessageW(hwndDlg, 14001, WM_GETTEXT, sizeof(szBuffer), (LPARAM)szBuffer); + index = wcslen(szBuffer); + if (index + wcslen(poainfo->pcszFile) + 1 < sizeof(szBuffer)/sizeof(szBuffer[0])) + wcscat(szBuffer, poainfo->pcszFile); + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + SendDlgItemMessageW(hwndDlg, 14001, WM_SETTEXT, 0, (LPARAM)szBuffer); + ZeroMemory(&Context, sizeof(OPEN_WITH_CONTEXT)); + Context.hDlgCtrl = GetDlgItem(hwndDlg, 14002); + LoadOWItems(&Context, poainfo->pcszFile); + SendMessage(Context.hDlgCtrl, LB_SETCURSEL, 0, 0); + } + return TRUE; + case WM_MEASUREITEM: + lpmis = (LPMEASUREITEMSTRUCT) lParam; + lpmis->itemHeight = 64; + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case 14004: /* browse */ + BrowseForApplication(hwndDlg); + return TRUE; + case 14002: + if (HIWORD(wParam) == LBN_SELCHANGE) + InvalidateRect((HWND)lParam, NULL, TRUE); // FIXME USE UPDATE RECT + break; + case 14005: /* ok */ + pItemContext = GetCurrentOpenItemContext(hwndDlg); + if (pItemContext) + { + /* store settings in HKCU path */ + StoreNewSettings(poainfo->pcszFile, pItemContext->szAppName); + + if (SendDlgItemMessage(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) + { + /* set programm as default handler */ + SetProgrammAsDefaultHandler(poainfo->pcszFile, pItemContext->szAppName); + } + + if (poainfo->oaifInFlags & OAIF_EXEC) + ExecuteOpenItem(pItemContext, poainfo->pcszFile); + } + FreeListItems(hwndDlg); + EndDialog(hwndDlg, 1); + return TRUE; + case 14006: /* cancel */ + FreeListItems(hwndDlg); + EndDialog(hwndDlg, 0); + return TRUE; + default: + break; + } + break; + case WM_DRAWITEM: + lpdis = (LPDRAWITEMSTRUCT) lParam; + if ((int)lpdis->itemID == -1) + break; + + switch (lpdis->itemAction) + { + case ODA_SELECT: + case ODA_DRAWENTIRE: + index = SendMessageW(lpdis->hwndItem, LB_GETCURSEL, 0, 0); + pItemContext =(POPEN_ITEM_CONTEXT)SendMessage(lpdis->hwndItem, LB_GETITEMDATA, lpdis->itemID, (LPARAM) 0); + + if ((int)lpdis->itemID == index) + { + /* paint focused item with standard background colour */ + HBRUSH hBrush; + hBrush = CreateSolidBrush(RGB(46, 104, 160)); + FillRect(lpdis->hDC, &lpdis->rcItem, hBrush); + DeleteObject(hBrush); + preBkColor = SetBkColor(lpdis->hDC, RGB(46, 104, 160)); + } + else + { + /* paint non focused item with white background */ + HBRUSH hBrush; + hBrush = CreateSolidBrush(RGB(255, 255, 255)); + FillRect(lpdis->hDC, &lpdis->rcItem, hBrush); + DeleteObject(hBrush); + preBkColor = SetBkColor(lpdis->hDC, RGB(255, 255, 255)); + } + + SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, (LPARAM) szBuffer); + /* paint the icon */ + DrawIconEx(lpdis->hDC, lpdis->rcItem.left,lpdis->rcItem.top, pItemContext->hIcon, 0, 0, 0, NULL, DI_NORMAL); + /* get text size */ + GetTextMetrics(lpdis->hDC, &mt); + /* paint app name */ + YOffset = lpdis->rcItem.top + mt.tmHeight/2; + TextOutW(lpdis->hDC, 45, YOffset, szBuffer, wcslen(szBuffer)); + /* paint manufacturer description */ + YOffset += mt.tmHeight + 2; + preColor = SetTextColor(lpdis->hDC, RGB(192, 192, 192)); + if (pItemContext->szManufacturer[0]) + TextOutW(lpdis->hDC, 45, YOffset, pItemContext->szManufacturer, wcslen(pItemContext->szManufacturer)); + else + TextOutW(lpdis->hDC, 45, YOffset, pItemContext->szAppName, wcslen(pItemContext->szAppName)); + SetTextColor(lpdis->hDC, preColor); + SetBkColor(lpdis->hDC, preBkColor); + break; + } + break; + case WM_CLOSE: + FreeListItems(hwndDlg); + EndDialog(hwndDlg, 0); + return TRUE; + default: + break; + } + return FALSE; +} + +void +FreeMenuItemContext(HMENU hMenu) +{ + INT Count; + INT Index; + MENUITEMINFOW mii; + + /* get item count */ + Count = GetMenuItemCount(hMenu); + if (Count == -1) + return; + + /* setup menuitem info */ + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_DATA | MIIM_FTYPE; + + for(Index = 0; Index < Count; Index++) + { + if (GetMenuItemInfoW(hMenu, Index, TRUE, &mii)) + { + if ((mii.fType & MFT_SEPARATOR) || mii.dwItemData == 0) + continue; + HeapFree(GetProcessHeap(), 0, (LPVOID)mii.dwItemData); + } + } +} + + +HRESULT WINAPI +COpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici ) +{ + MENUITEMINFOW mii; + + ERR("This %p wId %x count %u verb %x\n", this, wId, count, LOWORD(lpici->lpVerb)); + + if (wId < LOWORD(lpici->lpVerb)) + return E_FAIL; + + if (wId == LOWORD(lpici->lpVerb)) + { + OPENASINFO info; + + info.pcszFile = szPath; + info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC; + info.pcszClass = NULL; + FreeMenuItemContext(hSubMenu); + return SHOpenWithDialog(lpici->hwnd, &info); + } + + /* retrieve menu item info */ + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_DATA | MIIM_FTYPE; + + if (GetMenuItemInfoW(hSubMenu, LOWORD(lpici->lpVerb), TRUE, &mii)) + { + POPEN_ITEM_CONTEXT pItemContext = (POPEN_ITEM_CONTEXT)mii.dwItemData; + if (pItemContext) + { + /* launch item with specified app */ + ExecuteOpenItem(pItemContext, szPath); + } + } + /* free menu item context */ + FreeMenuItemContext(hSubMenu); + return S_OK; +} + +HRESULT WINAPI +COpenWithMenu::GetCommandString(UINT_PTR idCmd, UINT uType, + UINT* pwReserved, LPSTR pszName, UINT cchMax ) +{ + FIXME("%p %lu %u %p %p %u\n", this, + idCmd, uType, pwReserved, pszName, cchMax ); + + return E_NOTIMPL; +} + +HRESULT WINAPI COpenWithMenu::HandleMenuMsg( + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + TRACE("This %p uMsg %x\n",this, uMsg); + + return E_NOTIMPL; +} + +VOID +GetManufacturer(WCHAR * szAppName, POPEN_ITEM_CONTEXT pContext) +{ + UINT VerSize; + DWORD DummyHandle; + LPVOID pBuf; + WORD lang = 0; + WORD code = 0; + LPLANGANDCODEPAGE lplangcode; + WCHAR szBuffer[100]; + WCHAR * pResult; + BOOL bResult; + + static const WCHAR wFormat[] = L"\\StringFileInfo\\%04x%04x\\CompanyName"; + static const WCHAR wTranslation[] = L"VarFileInfo\\Translation"; + + /* query version info size */ + VerSize = GetFileVersionInfoSizeW(szAppName, &DummyHandle); + if (!VerSize) + { + pContext->szManufacturer[0] = 0; + return; + } + + /* allocate buffer */ + pBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, VerSize); + if (!pBuf) + { + pContext->szManufacturer[0] = 0; + return; + } + + /* query version info */ + if(!GetFileVersionInfoW(szAppName, 0, VerSize, pBuf)) + { + pContext->szManufacturer[0] = 0; + HeapFree(GetProcessHeap(), 0, pBuf); + return; + } + + /* query lang code */ + if(VerQueryValueW(pBuf, const_cast(wTranslation), (LPVOID *)&lplangcode, &VerSize)) + { + /* FIXME find language from current locale / if not available, + * default to english + * for now default to first available language + */ + lang = lplangcode->lang; + code = lplangcode->code; + } + /* set up format */ + swprintf(szBuffer, wFormat, lang, code); + /* query manufacturer */ + pResult = NULL; + bResult = VerQueryValueW(pBuf, szBuffer, (LPVOID *)&pResult, &VerSize); + + if (VerSize && bResult && pResult) + wcscpy(pContext->szManufacturer, pResult); + else + pContext->szManufacturer[0] = 0; + HeapFree(GetProcessHeap(), 0, pBuf); +} + + + + +void +InsertOpenWithItem(POPEN_WITH_CONTEXT pContext, WCHAR * szAppName) +{ + MENUITEMINFOW mii; + POPEN_ITEM_CONTEXT pItemContext; + LRESULT index; + WCHAR * Offset; + WCHAR Buffer[_MAX_FNAME]; + + pItemContext = (OPEN_ITEM_CONTEXT *)HeapAlloc(GetProcessHeap(), 0, sizeof(OPEN_ITEM_CONTEXT)); + if (!pItemContext) + return; + + /* store app path */ + wcscpy(pItemContext->szAppName, szAppName); + /* null terminate it */ + pItemContext->szAppName[MAX_PATH-1] = 0; + /* extract path name */ + _wsplitpath(szAppName, NULL, NULL, Buffer, NULL); + Offset = wcsrchr(Buffer, '.'); + if (Offset) + Offset[0] = L'\0'; + Buffer[0] = towupper(Buffer[0]); + + if (pContext->bMenu) + { + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; + mii.fType = MFT_STRING; //MFT_OWNERDRAW; + mii.fState = MFS_ENABLED; + mii.wID = pContext->idCmdFirst; + mii.dwTypeData = Buffer; + mii.cch = wcslen(Buffer); + mii.dwItemData = (ULONG_PTR)pItemContext; + wcscpy(pItemContext->szManufacturer, Buffer); + if (InsertMenuItemW(pContext->hMenu, -1, TRUE, &mii)) + { + pContext->idCmdFirst++; + pContext->Count++; + } + } + else + { + /* get default icon */ + pItemContext->hIcon = ExtractIconW(shell32_hInstance, szAppName, 0); + /* get manufacturer */ + GetManufacturer(pItemContext->szAppName, pItemContext); + index = SendMessageW(pContext->hDlgCtrl, LB_ADDSTRING, 0, (LPARAM)Buffer); + if (index != LB_ERR) + SendMessageW(pContext->hDlgCtrl, LB_SETITEMDATA, index, (LPARAM)pItemContext); + } +} + +void +AddItemFromProgIDList(POPEN_WITH_CONTEXT pContext, HKEY hKey) +{ + FIXME("implement me :)))\n"); +} + +HANDLE +OpenMRUList(HKEY hKey) +{ + CREATEMRULISTW info; + + /* initialize mru list info */ + info.cbSize = sizeof(info); + info.nMaxItems = 32; + info.dwFlags = MRU_STRING; + info.hKey = hKey; + info.lpszSubKey = L"OpenWithList"; + info.lpfnCompare = NULL; + + /* load list */ + return CreateMRUListW(&info); +} + +void +AddItemFromMRUList(POPEN_WITH_CONTEXT pContext, HKEY hKey) +{ + HANDLE hList; + int nItem, nCount, nResult; + WCHAR szBuffer[MAX_PATH]; + + /* open mru list */ + hList = OpenMRUList(hKey); + if (!hList) + return; + + /* get list count */ + nCount = EnumMRUListW(hList, -1, NULL, 0); + + for(nItem = 0; nItem < nCount; nItem++) + { + nResult = EnumMRUListW(hList, nItem, szBuffer, MAX_PATH); + if (nResult <= 0) + continue; + /* make sure its zero terminated */ + szBuffer[min(MAX_PATH-1, nResult)] = '\0'; + /* insert item */ + if (!HideApplicationFromList(szBuffer)) + InsertOpenWithItem(pContext, szBuffer); + } + + /* free the mru list */ + FreeMRUList(hList); +} + + + +void +LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext, const WCHAR * szExt) +{ + HKEY hKey; + HKEY hSubKey; + WCHAR szBuffer[MAX_PATH+10]; + WCHAR szResult[100]; + DWORD dwSize; + + static const WCHAR szOpenWithList[] = L"OpenWithList"; + static const WCHAR szOpenWithProgIds[] = L"OpenWithProgIDs"; + static const WCHAR szPerceivedType[] = L"PerceivedType"; + static const WCHAR szSysFileAssoc[] = L"SystemFileAssociations\\%s"; + + /* check if extension exists */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szExt, 0, KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS) + return; + + if (RegGetValueW(hKey, NULL, L"NoOpen", RRF_RT_REG_SZ, NULL, NULL, &dwSize) == ERROR_SUCCESS) + { + /* display warning dialog */ + pContext->NoOpen = TRUE; + } + + /* check if there is a directly available execute key */ + if (RegOpenKeyExW(hKey, L"shell\\open\\command", 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) + { + DWORD dwBuffer = sizeof(szBuffer); + + if (RegGetValueW(hSubKey, NULL, NULL, RRF_RT_REG_SZ, NULL, (PVOID)szBuffer, &dwBuffer) == ERROR_SUCCESS) + { + WCHAR * Ext = wcsrchr(szBuffer, ' '); + if (Ext) + { + /* erase %1 or extra arguments */ + Ext[0] = 0; + } + if(!HideApplicationFromList(szBuffer)) + InsertOpenWithItem(pContext, szBuffer); + } + RegCloseKey(hSubKey); + } + + /* load items from HKCR\Ext\OpenWithList */ + if (RegOpenKeyExW(hKey, szOpenWithList, 0, KEY_READ | KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) + { + AddItemFromMRUList(pContext, hKey); + RegCloseKey(hSubKey); + } + + /* load items from HKCR\Ext\OpenWithProgIDs */ + if (RegOpenKeyExW(hKey, szOpenWithProgIds, 0, KEY_READ | KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS) + { + AddItemFromProgIDList(pContext, hSubKey); + RegCloseKey(hSubKey); + } + + /* load items from SystemFileAssociations\Ext key */ + swprintf(szResult, szSysFileAssoc, szExt); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szResult, 0, KEY_READ | KEY_WRITE, &hSubKey) == ERROR_SUCCESS) + { + AddItemFromMRUList(pContext, hSubKey); + RegCloseKey(hSubKey); + } + + /* load additional items from referenced PerceivedType*/ + dwSize = sizeof(szBuffer); + if (RegGetValueW(hKey, NULL, szPerceivedType, RRF_RT_REG_SZ, NULL, szBuffer, &dwSize) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + return; + } + RegCloseKey(hKey); + + /* terminate it explictely */ + szBuffer[29] = 0; + swprintf(szResult, szSysFileAssoc, szBuffer); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szResult, 0, KEY_READ | KEY_WRITE, &hSubKey) == ERROR_SUCCESS) + { + AddItemFromMRUList(pContext, hSubKey); + RegCloseKey(hSubKey); + } +} + +void +LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext, const WCHAR * szExt) +{ + WCHAR szBuffer[MAX_PATH]; + HKEY hKey; + + static const WCHAR szOpenWithProgIDs[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s\\OpenWithProgIDs"; + static const WCHAR szOpenWithList[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s"; + + /* handle first progid lists */ + swprintf(szBuffer, szOpenWithProgIDs, szExt); + if (RegOpenKeyExW(HKEY_CURRENT_USER, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS) + { + AddItemFromProgIDList(pContext, hKey); + RegCloseKey(hKey); + } + + /* now handle mru lists */ + swprintf(szBuffer, szOpenWithList, szExt); + if (RegOpenKeyExW(HKEY_CURRENT_USER, szBuffer, 0, KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS) + { + AddItemFromMRUList(pContext, hKey); + RegCloseKey(hKey); + } +} + +HRESULT +COpenWithMenu::SHEOW_LoadOpenWithItems(IDataObject *pdtobj) +{ + STGMEDIUM medium; + FORMATETC fmt; + HRESULT hr; + LPIDA pida; + LPCITEMIDLIST pidl_folder; + LPCITEMIDLIST pidl_child; + LPCITEMIDLIST pidl; + DWORD dwPath; + LPWSTR szPtr; + static const WCHAR szShortCut[] = { '.','l','n','k', 0 }; + + fmt.cfFormat = RegisterClipboardFormatW(CFSTR_SHELLIDLIST); + fmt.ptd = NULL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.tymed = TYMED_HGLOBAL; + + hr = pdtobj->GetData(&fmt, &medium); + + if (FAILED(hr)) + { + ERR("IDataObject_GetData failed with 0x%x\n", hr); + return hr; + } + + /*assert(pida->cidl==1);*/ + pida = (LPIDA)GlobalLock(medium.hGlobal); + + pidl_folder = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]); + pidl_child = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[1]); + + pidl = ILCombine(pidl_folder, pidl_child); + + GlobalUnlock(medium.hGlobal); + GlobalFree(medium.hGlobal); + + if (!pidl) + { + ERR("no mem\n"); + return E_OUTOFMEMORY; + } + if (_ILIsDesktop(pidl) || _ILIsMyDocuments(pidl) || _ILIsControlPanel(pidl) || _ILIsNetHood(pidl) || + _ILIsBitBucket(pidl) || _ILIsDrive(pidl) || _ILIsCPanelStruct(pidl) || _ILIsFolder(pidl) || _ILIsControlPanel(pidl)) + { + TRACE("pidl is a folder\n"); + SHFree((void*)pidl); + return E_FAIL; + } + + if (!SHGetPathFromIDListW(pidl, szPath)) + { + SHFree((void*)pidl); + ERR("SHGetPathFromIDListW failed\n"); + return E_FAIL; + } + + SHFree((void*)pidl); + TRACE("szPath %s\n", debugstr_w(szPath)); + + if (GetBinaryTypeW(szPath, &dwPath)) + { + TRACE("path is a executable %x\n", dwPath); + return E_FAIL; + } + + szPtr = wcsrchr(szPath, '.'); + if (szPtr) + { + if (!_wcsicmp(szPtr, szShortCut)) + { + FIXME("pidl is a shortcut\n"); + return E_FAIL; + } + } + return S_OK; +} + +HRESULT WINAPI +COpenWithMenu::Initialize(LPCITEMIDLIST pidlFolder, + IDataObject *pdtobj, HKEY hkeyProgID ) +{ + TRACE("This %p\n", this); + + if (pdtobj == NULL) + return E_INVALIDARG; + return SHEOW_LoadOpenWithItems(pdtobj); +} + +HRESULT WINAPI SHOpenWithDialog( + HWND hwndParent, + const OPENASINFO *poainfo +) +{ + MSG msg; + BOOL bRet; + HWND hwnd; + + if (poainfo->pcszClass == NULL && poainfo->pcszFile == NULL) + return E_FAIL; + + + hwnd = CreateDialogParam(shell32_hInstance, MAKEINTRESOURCE(OPEN_WITH_PROGRAMM_DLG), hwndParent, OpenWithProgrammDlg, (LPARAM)poainfo); + 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 S_OK; +} diff --git a/reactos/dll/win32/shell32/she_ocmenu.h b/reactos/dll/win32/shell32/she_ocmenu.h new file mode 100644 index 00000000000..f4cf23b3b7a --- /dev/null +++ b/reactos/dll/win32/shell32/she_ocmenu.h @@ -0,0 +1,65 @@ +/* + * Open With Context Menu extension + * + * Copyright 2007 Johannes Anderwald + * 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 + */ + +#ifndef _SHE_OCMENU_H_ +#define _SHE_OCMENU_H_ + +class COpenWithMenu : + public CComCoClass, + public CComObjectRootEx, + public IContextMenu2, + public IShellExtInit +{ +private: + LONG wId; + BOOL NoOpen; + UINT count; + WCHAR szPath[MAX_PATH]; + HMENU hSubMenu; +public: + COpenWithMenu(); + ~COpenWithMenu(); + HRESULT SHEOW_LoadOpenWithItems(IDataObject *pdtobj); + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand,UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen); + + // IContextMenu2 + virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); + + // IShellExtInit + virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID); + +DECLARE_NO_REGISTRY() +DECLARE_NOT_AGGREGATABLE(COpenWithMenu) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(COpenWithMenu) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit) +END_COM_MAP() +}; + +#endif // _SHE_OCMENU_H_ diff --git a/reactos/dll/win32/shell32/shell.cpp b/reactos/dll/win32/shell32/shell.cpp new file mode 100644 index 00000000000..2813943aff7 --- /dev/null +++ b/reactos/dll/win32/shell32/shell.cpp @@ -0,0 +1,21 @@ +/* + * Shell Library Functions + * + * Copyright 1998 Marcus Meissner + * Copyright 2000 Juergen Schmied + * 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 + */ diff --git a/reactos/dll/win32/shell32/shell32.rbuild b/reactos/dll/win32/shell32/shell32.rbuild index 5276af049f5..844a30c5e77 100644 --- a/reactos/dll/win32/shell32/shell32.rbuild +++ b/reactos/dll/win32/shell32/shell32.rbuild @@ -1,13 +1,15 @@ - + - . . include/reactos/wine - + . + + + 0x600 wine uuid @@ -24,60 +26,61 @@ devmgr winspool winmm + msvcrt + atlnew precomp.h - 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 + 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 diff --git a/reactos/dll/win32/shell32/shell32.rbuild.bak b/reactos/dll/win32/shell32/shell32.rbuild.bak new file mode 100644 index 00000000000..d871af6daab --- /dev/null +++ b/reactos/dll/win32/shell32/shell32.rbuild.bak @@ -0,0 +1,90 @@ + + + + + . + . + include/reactos/wine + . + + + + + + 0x600 + wine + uuid + recyclebin + ntdll + advapi32 + gdi32 + user32 + comctl32 + comdlg32 + shlwapi + ole32 + version + devmgr + winspool + winmm + msvcrt + atlnew + precomp.h + 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 + + + shobjidl_local.idl + + diff --git a/reactos/dll/win32/shell32/shell32.rc b/reactos/dll/win32/shell32/shell32.rc index ec4a8c0f6cd..88169ea741b 100644 --- a/reactos/dll/win32/shell32/shell32.rc +++ b/reactos/dll/win32/shell32/shell32.rc @@ -39,6 +39,7 @@ END #include "icon_res.rc" #include "bitmap_res.rc" #include "avi_res.rc" +#include "rgs_res.rc" /* * Everything specific to any language goes diff --git a/reactos/dll/win32/shell32/shell32_main.cpp b/reactos/dll/win32/shell32/shell32_main.cpp new file mode 100644 index 00000000000..671155d2cf3 --- /dev/null +++ b/reactos/dll/win32/shell32/shell32_main.cpp @@ -0,0 +1,1477 @@ +/* + * Shell basics + * + * Copyright 1998 Marcus Meissner + * Copyright 1998 Juergen Schmied (jsch) * + * + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +const char * const SHELL_Authors[] = { "Copyright 1993-2009 WINE team", "Copyright 1998-2009 ReactOS Team", 0 }; + +#define MORE_DEBUG 1 +/************************************************************************* + * CommandLineToArgvW [SHELL32.@] + * + * We must interpret the quotes in the command line to rebuild the argv + * array correctly: + * - arguments are separated by spaces or tabs + * - quotes serve as optional argument delimiters + * '"a b"' -> 'a b' + * - escaped quotes must be converted back to '"' + * '\"' -> '"' + * - an odd number of '\'s followed by '"' correspond to half that number + * of '\' followed by a '"' (extension of the above) + * '\\\"' -> '\"' + * '\\\\\"' -> '\\"' + * - an even number of '\'s followed by a '"' correspond to half that number + * of '\', plus a regular quote serving as an argument delimiter (which + * means it does not appear in the result) + * 'a\\"b c"' -> 'a\b c' + * 'a\\\\"b c"' -> 'a\\b c' + * - '\' that are not followed by a '"' are copied literally + * 'a\b' -> 'a\b' + * 'a\\b' -> 'a\\b' + * + * Note: + * '\t' == 0x0009 + * ' ' == 0x0020 + * '"' == 0x0022 + * '\\' == 0x005c + */ +LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs) +{ + DWORD argc; + LPWSTR *argv; + LPCWSTR cs; + LPWSTR arg,s,d; + LPWSTR cmdline; + int in_quotes,bcount; + + if (*lpCmdline==0) + { + /* Return the path to the executable */ + DWORD len, size=16; + + argv = (LPWSTR *)LocalAlloc(LMEM_FIXED, size); + for (;;) + { + len = GetModuleFileNameW(0, (LPWSTR)(argv+1), (size-sizeof(LPWSTR))/sizeof(WCHAR)); + if (!len) + { + LocalFree(argv); + return NULL; + } + if (len < size) break; + size*=2; + argv = (LPWSTR *)LocalReAlloc(argv, size, 0); + } + argv[0]=(LPWSTR)(argv+1); + if (numargs) + *numargs=1; + + return argv; + } + + /* to get a writable copy */ + argc=0; + bcount=0; + in_quotes=0; + cs=lpCmdline; + while (1) + { + if (*cs==0 || ((*cs==0x0009 || *cs==0x0020) && !in_quotes)) + { + /* space */ + argc++; + /* skip the remaining spaces */ + while (*cs==0x0009 || *cs==0x0020) + { + cs++; + } + if (*cs==0) + break; + bcount=0; + continue; + } + else if (*cs==0x005c) + { + /* '\', count them */ + bcount++; + } + else if ((*cs==0x0022) && ((bcount & 1)==0)) + { + /* unescaped '"' */ + in_quotes=!in_quotes; + bcount=0; + } + else + { + /* a regular character */ + bcount=0; + } + cs++; + } + /* Allocate in a single lump, the string array, and the strings that go with it. + * This way the caller can make a single GlobalFree call to free both, as per MSDN. + */ + argv = (LPWSTR *)LocalAlloc(LMEM_FIXED, argc*sizeof(LPWSTR)+(wcslen(lpCmdline)+1)*sizeof(WCHAR)); + + if (!argv) + return NULL; + + cmdline=(LPWSTR)(argv+argc); + wcscpy(cmdline, lpCmdline); + + argc=0; + bcount=0; + in_quotes=0; + arg=d=s=cmdline; + while (*s) + { + if ((*s==0x0009 || *s==0x0020) && !in_quotes) + { + /* Close the argument and copy it */ + *d=0; + argv[argc++]=arg; + + /* skip the remaining spaces */ + do { + s++; + } while (*s==0x0009 || *s==0x0020); + + /* Start with a new argument */ + arg=d=s; + bcount=0; + } + else if (*s==0x005c) + { + /* '\\' */ + *d++=*s++; + bcount++; + } + else if (*s==0x0022) + { + /* '"' */ + if ((bcount & 1)==0) + { + /* Preceded by an even number of '\', this is half that + * number of '\', plus a quote which we erase. + */ + d-=bcount/2; + in_quotes=!in_quotes; + s++; + } + else + { + /* Preceded by an odd number of '\', this is half that + * number of '\' followed by a '"' + */ + d=d-bcount/2-1; + *d++='"'; + s++; + } + bcount=0; + } + else + { + /* a regular character */ + *d++=*s++; + bcount=0; + } + } + if (*arg) + { + *d='\0'; + argv[argc++]=arg; + } + if (numargs) + *numargs=argc; + + return argv; +} + +static DWORD shgfi_get_exe_type(LPCWSTR szFullPath) +{ + BOOL status = FALSE; + HANDLE hfile; + DWORD BinaryType; + IMAGE_DOS_HEADER mz_header; + IMAGE_NT_HEADERS nt; + DWORD len; + char magic[4]; + + status = GetBinaryTypeW (szFullPath, &BinaryType); + if (!status) + return 0; + if (BinaryType == SCS_DOS_BINARY || BinaryType == SCS_PIF_BINARY) + return 0x4d5a; + + hfile = CreateFileW( szFullPath, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, 0 ); + if ( hfile == INVALID_HANDLE_VALUE ) + return 0; + + /* + * The next section is adapted from MODULE_GetBinaryType, as we need + * to examine the image header to get OS and version information. We + * know from calling GetBinaryTypeA that the image is valid and either + * an NE or PE, so much error handling can be omitted. + * Seek to the start of the file and read the header information. + */ + + SetFilePointer( hfile, 0, NULL, SEEK_SET ); + ReadFile( hfile, &mz_header, sizeof(mz_header), &len, NULL ); + + SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ); + ReadFile( hfile, magic, sizeof(magic), &len, NULL ); + + if ( *(DWORD*)magic == IMAGE_NT_SIGNATURE ) + { + SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ); + ReadFile( hfile, &nt, sizeof(nt), &len, NULL ); + CloseHandle( hfile ); + + /* DLL files are not executable and should return 0 */ + if (nt.FileHeader.Characteristics & IMAGE_FILE_DLL) + return 0; + + if (nt.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) + { + return IMAGE_NT_SIGNATURE | + (nt.OptionalHeader.MajorSubsystemVersion << 24) | + (nt.OptionalHeader.MinorSubsystemVersion << 16); + } + return IMAGE_NT_SIGNATURE; + } + else if ( *(WORD*)magic == IMAGE_OS2_SIGNATURE ) + { + IMAGE_OS2_HEADER ne; + SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ); + ReadFile( hfile, &ne, sizeof(ne), &len, NULL ); + CloseHandle( hfile ); + + if (ne.ne_exetyp == 2) + return IMAGE_OS2_SIGNATURE | (ne.ne_expver << 16); + return 0; + } + CloseHandle( hfile ); + return 0; +} + +/************************************************************************* + * SHELL_IsShortcut [internal] + * + * Decide if an item id list points to a shell shortcut + */ +BOOL SHELL_IsShortcut(LPCITEMIDLIST pidlLast) +{ + char szTemp[MAX_PATH]; + HKEY keyCls; + BOOL ret = FALSE; + + if (_ILGetExtension(pidlLast, szTemp, MAX_PATH) && + HCR_MapTypeToValueA(szTemp, szTemp, MAX_PATH, TRUE)) + { + if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_QUERY_VALUE, &keyCls)) + { + if (ERROR_SUCCESS == RegQueryValueExA(keyCls, "IsShortcut", NULL, NULL, NULL, NULL)) + ret = TRUE; + + RegCloseKey(keyCls); + } + } + + return ret; +} + +#define SHGFI_KNOWN_FLAGS \ + (SHGFI_SMALLICON | SHGFI_OPENICON | SHGFI_SHELLICONSIZE | SHGFI_PIDL | \ + SHGFI_USEFILEATTRIBUTES | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX | \ + SHGFI_ICON | SHGFI_DISPLAYNAME | SHGFI_TYPENAME | SHGFI_ATTRIBUTES | \ + SHGFI_ICONLOCATION | SHGFI_EXETYPE | SHGFI_SYSICONINDEX | \ + SHGFI_LINKOVERLAY | SHGFI_SELECTED | SHGFI_ATTR_SPECIFIED) + +/************************************************************************* + * SHGetFileInfoW [SHELL32.@] + * + */ +DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes, + SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags ) +{ + WCHAR szLocation[MAX_PATH], szFullPath[MAX_PATH]; + int iIndex; + DWORD_PTR ret = TRUE; + DWORD dwAttributes = 0; + CComPtr psfParent; + CComPtr pei; + LPITEMIDLIST pidlLast = NULL, pidl = NULL; + HRESULT hr = S_OK; + BOOL IconNotYetLoaded=TRUE; + UINT uGilFlags = 0; + + TRACE("%s fattr=0x%x sfi=%p(attr=0x%08x) size=0x%x flags=0x%x\n", + (flags & SHGFI_PIDL)? "pidl" : debugstr_w(path), dwFileAttributes, + psfi, psfi->dwAttributes, sizeofpsfi, flags); + + if (!path) + return FALSE; + + /* windows initializes these values regardless of the flags */ + if (psfi != NULL) + { + psfi->szDisplayName[0] = '\0'; + psfi->szTypeName[0] = '\0'; + psfi->iIcon = 0; + } + + if (!(flags & SHGFI_PIDL)) + { + /* SHGetFileInfo should work with absolute and relative paths */ + if (PathIsRelativeW(path)) + { + GetCurrentDirectoryW(MAX_PATH, szLocation); + PathCombineW(szFullPath, szLocation, path); + } + else + { + lstrcpynW(szFullPath, path, MAX_PATH); + } + } + + if (flags & SHGFI_EXETYPE) + { + if (flags != SHGFI_EXETYPE) + return 0; + return shgfi_get_exe_type(szFullPath); + } + + /* + * psfi is NULL normally to query EXE type. If it is NULL, none of the + * below makes sense anyway. Windows allows this and just returns FALSE + */ + if (psfi == NULL) + return FALSE; + + /* + * translate the path into a pidl only when SHGFI_USEFILEATTRIBUTES + * is not specified. + * The pidl functions fail on not existing file names + */ + + if (flags & SHGFI_PIDL) + { + pidl = ILClone((LPCITEMIDLIST)path); + } + else if (!(flags & SHGFI_USEFILEATTRIBUTES)) + { + hr = SHILCreateFromPathW(szFullPath, &pidl, &dwAttributes); + } + + if ((flags & SHGFI_PIDL) || !(flags & SHGFI_USEFILEATTRIBUTES)) + { + /* get the parent shellfolder */ + if (pidl) + { + hr = SHBindToParent( pidl, IID_IShellFolder, (LPVOID*)&psfParent, + (LPCITEMIDLIST*)&pidlLast ); + if (SUCCEEDED(hr)) + pidlLast = ILClone(pidlLast); + ILFree(pidl); + } + else + { + ERR("pidl is null!\n"); + return FALSE; + } + } + + /* get the attributes of the child */ + if (SUCCEEDED(hr) && (flags & SHGFI_ATTRIBUTES)) + { + if (!(flags & SHGFI_ATTR_SPECIFIED)) + { + psfi->dwAttributes = 0xffffffff; + } + if (psfParent != NULL) + psfParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlLast, + &(psfi->dwAttributes) ); + } + + /* get the displayname */ + if (SUCCEEDED(hr) && (flags & SHGFI_DISPLAYNAME)) + { + if (flags & SHGFI_USEFILEATTRIBUTES) + { + wcscpy (psfi->szDisplayName, PathFindFileNameW(szFullPath)); + } + else + { + STRRET str; + hr = psfParent->GetDisplayNameOf(pidlLast, + SHGDN_INFOLDER, &str); + StrRetToStrNW (psfi->szDisplayName, MAX_PATH, &str, pidlLast); + } + } + + /* get the type name */ + if (SUCCEEDED(hr) && (flags & SHGFI_TYPENAME)) + { + static const WCHAR szFile[] = { 'F','i','l','e',0 }; + static const WCHAR szDashFile[] = { '-','f','i','l','e',0 }; + + if (!(flags & SHGFI_USEFILEATTRIBUTES)) + { + char ftype[80]; + + _ILGetFileType(pidlLast, ftype, 80); + MultiByteToWideChar(CP_ACP, 0, ftype, -1, psfi->szTypeName, 80 ); + } + else + { + if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + wcscat (psfi->szTypeName, szFile); + else + { + WCHAR sTemp[64]; + + wcscpy(sTemp,PathFindExtensionW(szFullPath)); + if (!( HCR_MapTypeToValueW(sTemp, sTemp, 64, TRUE) && + HCR_MapTypeToValueW(sTemp, psfi->szTypeName, 80, FALSE ))) + { + lstrcpynW (psfi->szTypeName, sTemp, 64); + wcscat (psfi->szTypeName, szDashFile); + } + } + } + } + + /* ### icons ###*/ + if (flags & SHGFI_OPENICON) + uGilFlags |= GIL_OPENICON; + + if (flags & SHGFI_LINKOVERLAY) + uGilFlags |= GIL_FORSHORTCUT; + else if ((flags&SHGFI_ADDOVERLAYS) || + (flags&(SHGFI_ICON|SHGFI_SMALLICON))==SHGFI_ICON) + { + if (SHELL_IsShortcut(pidlLast)) + uGilFlags |= GIL_FORSHORTCUT; + } + + if (flags & SHGFI_OVERLAYINDEX) + FIXME("SHGFI_OVERLAYINDEX unhandled\n"); + + if (flags & SHGFI_SELECTED) + FIXME("set icon to selected, stub\n"); + + if (flags & SHGFI_SHELLICONSIZE) + FIXME("set icon to shell size, stub\n"); + + /* get the iconlocation */ + if (SUCCEEDED(hr) && (flags & SHGFI_ICONLOCATION )) + { + UINT uDummy,uFlags; + + if (flags & SHGFI_USEFILEATTRIBUTES) + { + if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + wcscpy(psfi->szDisplayName, swShell32Name); + psfi->iIcon = -IDI_SHELL_FOLDER; + } + else + { + WCHAR* szExt; + static const WCHAR p1W[] = {'%','1',0}; + WCHAR sTemp [MAX_PATH]; + + szExt = PathFindExtensionW(szFullPath); + TRACE("szExt=%s\n", debugstr_w(szExt)); + if ( szExt && + HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) && + HCR_GetDefaultIconW(sTemp, sTemp, MAX_PATH, &psfi->iIcon)) + { + if (lstrcmpW(p1W, sTemp)) + wcscpy(psfi->szDisplayName, sTemp); + else + { + /* the icon is in the file */ + wcscpy(psfi->szDisplayName, szFullPath); + } + } + else + ret = FALSE; + } + } + else + { + hr = psfParent->GetUIObjectOf(0, 1, + (LPCITEMIDLIST*)&pidlLast, IID_IExtractIconW, + &uDummy, (LPVOID*)&pei); + if (SUCCEEDED(hr)) + { + hr = pei->GetIconLocation(uGilFlags, + szLocation, MAX_PATH, &iIndex, &uFlags); + + if (uFlags & GIL_NOTFILENAME) + ret = FALSE; + else + { + wcscpy (psfi->szDisplayName, szLocation); + psfi->iIcon = iIndex; + } + } + } + } + + /* get icon index (or load icon)*/ + if (SUCCEEDED(hr) && (flags & (SHGFI_ICON | SHGFI_SYSICONINDEX))) + { + if (flags & SHGFI_USEFILEATTRIBUTES && !(flags & SHGFI_PIDL)) + { + WCHAR sTemp [MAX_PATH]; + WCHAR * szExt; + int icon_idx=0; + + lstrcpynW(sTemp, szFullPath, MAX_PATH); + + if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + psfi->iIcon = SIC_GetIconIndex(swShell32Name, -IDI_SHELL_FOLDER, 0); + else + { + static const WCHAR p1W[] = {'%','1',0}; + + psfi->iIcon = 0; + szExt = PathFindExtensionW(sTemp); + if ( szExt && + HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) && + HCR_GetDefaultIconW(sTemp, sTemp, MAX_PATH, &icon_idx)) + { + if (!lstrcmpW(p1W,sTemp)) /* icon is in the file */ + wcscpy(sTemp, szFullPath); + + if (flags & SHGFI_SYSICONINDEX) + { + psfi->iIcon = SIC_GetIconIndex(sTemp,icon_idx,0); + if (psfi->iIcon == -1) + psfi->iIcon = 0; + } + else + { + UINT ret; + if (flags & SHGFI_SMALLICON) + ret = PrivateExtractIconsW( sTemp,icon_idx, + GetSystemMetrics( SM_CXSMICON ), + GetSystemMetrics( SM_CYSMICON ), + &psfi->hIcon, 0, 1, 0); + else + ret = PrivateExtractIconsW( sTemp, icon_idx, + GetSystemMetrics( SM_CXICON), + GetSystemMetrics( SM_CYICON), + &psfi->hIcon, 0, 1, 0); + + if (ret != 0 && ret != 0xFFFFFFFF) + { + IconNotYetLoaded=FALSE; + psfi->iIcon = icon_idx; + } + } + } + } + } + else + { + if (!(PidlToSicIndex(psfParent, pidlLast, !(flags & SHGFI_SMALLICON), + uGilFlags, &(psfi->iIcon)))) + { + ret = FALSE; + } + } + if (ret && (flags & SHGFI_SYSICONINDEX)) + { + if (flags & SHGFI_SMALLICON) + ret = (DWORD_PTR) ShellSmallIconList; + else + ret = (DWORD_PTR) ShellBigIconList; + } + } + + /* icon handle */ + if (SUCCEEDED(hr) && (flags & SHGFI_ICON) && IconNotYetLoaded) + { + if (flags & SHGFI_SMALLICON) + psfi->hIcon = ImageList_GetIcon( ShellSmallIconList, psfi->iIcon, ILD_NORMAL); + else + psfi->hIcon = ImageList_GetIcon( ShellBigIconList, psfi->iIcon, ILD_NORMAL); + } + + if (flags & ~SHGFI_KNOWN_FLAGS) + FIXME("unknown flags %08x\n", flags & ~SHGFI_KNOWN_FLAGS); + + if (hr != S_OK) + ret = FALSE; + + SHFree(pidlLast); + +#ifdef MORE_DEBUG + TRACE ("icon=%p index=0x%08x attr=0x%08x name=%s type=%s ret=0x%08lx\n", + psfi->hIcon, psfi->iIcon, psfi->dwAttributes, + debugstr_w(psfi->szDisplayName), debugstr_w(psfi->szTypeName), ret); +#endif + + return ret; +} + +/************************************************************************* + * SHGetFileInfoA [SHELL32.@] + * + * Note: + * MSVBVM60.__vbaNew2 expects this function to return a value in range + * 1 .. 0x7fff when the function succeeds and flags does not contain + * SHGFI_EXETYPE or SHGFI_SYSICONINDEX (see bug 7701) + */ +DWORD_PTR WINAPI SHGetFileInfoA(LPCSTR path,DWORD dwFileAttributes, + SHFILEINFOA *psfi, UINT sizeofpsfi, + UINT flags ) +{ + INT len; + LPWSTR temppath = NULL; + LPCWSTR pathW; + DWORD ret; + SHFILEINFOW temppsfi; + + if (flags & SHGFI_PIDL) + { + /* path contains a pidl */ + pathW = (LPCWSTR)path; + } + else + { + len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0); + temppath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, path, -1, temppath, len); + pathW = temppath; + } + + if (psfi && (flags & SHGFI_ATTR_SPECIFIED)) + temppsfi.dwAttributes=psfi->dwAttributes; + + if (psfi == NULL) + ret = SHGetFileInfoW(pathW, dwFileAttributes, NULL, sizeof(temppsfi), flags); + else + ret = SHGetFileInfoW(pathW, dwFileAttributes, &temppsfi, sizeof(temppsfi), flags); + + if (psfi) + { + if(flags & SHGFI_ICON) + psfi->hIcon=temppsfi.hIcon; + if(flags & (SHGFI_SYSICONINDEX|SHGFI_ICON|SHGFI_ICONLOCATION)) + psfi->iIcon=temppsfi.iIcon; + if(flags & SHGFI_ATTRIBUTES) + psfi->dwAttributes=temppsfi.dwAttributes; + if(flags & (SHGFI_DISPLAYNAME|SHGFI_ICONLOCATION)) + { + WideCharToMultiByte(CP_ACP, 0, temppsfi.szDisplayName, -1, + psfi->szDisplayName, sizeof(psfi->szDisplayName), NULL, NULL); + } + if(flags & SHGFI_TYPENAME) + { + WideCharToMultiByte(CP_ACP, 0, temppsfi.szTypeName, -1, + psfi->szTypeName, sizeof(psfi->szTypeName), NULL, NULL); + } + } + + HeapFree(GetProcessHeap(), 0, temppath); + + return ret; +} + +/************************************************************************* + * DuplicateIcon [SHELL32.@] + */ +EXTERN_C HICON WINAPI DuplicateIcon( HINSTANCE hInstance, HICON hIcon) +{ + ICONINFO IconInfo; + HICON hDupIcon = 0; + + TRACE("%p %p\n", hInstance, hIcon); + + if (GetIconInfo(hIcon, &IconInfo)) + { + hDupIcon = CreateIconIndirect(&IconInfo); + + /* clean up hbmMask and hbmColor */ + DeleteObject(IconInfo.hbmMask); + DeleteObject(IconInfo.hbmColor); + } + + return hDupIcon; +} + +/************************************************************************* + * ExtractIconA [SHELL32.@] + */ +HICON WINAPI ExtractIconA(HINSTANCE hInstance, LPCSTR lpszFile, UINT nIconIndex) +{ + HICON ret; + INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0); + LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + TRACE("%p %s %d\n", hInstance, lpszFile, nIconIndex); + + MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len); + ret = ExtractIconW(hInstance, lpwstrFile, nIconIndex); + HeapFree(GetProcessHeap(), 0, lpwstrFile); + + return ret; +} + +/************************************************************************* + * ExtractIconW [SHELL32.@] + */ +HICON WINAPI ExtractIconW(HINSTANCE hInstance, LPCWSTR lpszFile, UINT nIconIndex) +{ + HICON hIcon = NULL; + UINT ret; + UINT cx = GetSystemMetrics(SM_CXICON), cy = GetSystemMetrics(SM_CYICON); + + TRACE("%p %s %d\n", hInstance, debugstr_w(lpszFile), nIconIndex); + + if (nIconIndex == 0xFFFFFFFF) + { + ret = PrivateExtractIconsW(lpszFile, 0, cx, cy, NULL, NULL, 0, LR_DEFAULTCOLOR); + if (ret != 0xFFFFFFFF && ret) + return (HICON)(UINT_PTR)ret; + return NULL; + } + else + ret = PrivateExtractIconsW(lpszFile, nIconIndex, cx, cy, &hIcon, NULL, 1, LR_DEFAULTCOLOR); + + if (ret == 0xFFFFFFFF) + return (HICON)1; + else if (ret > 0 && hIcon) + return hIcon; + + return NULL; +} + +/************************************************************************* + * Printer_LoadIconsW [SHELL32.205] + */ +EXTERN_C VOID WINAPI Printer_LoadIconsW(LPCWSTR wsPrinterName, HICON * pLargeIcon, HICON * pSmallIcon) +{ + INT iconindex=IDI_SHELL_PRINTERS_FOLDER; + + TRACE("(%s, %p, %p)\n", debugstr_w(wsPrinterName), pLargeIcon, pSmallIcon); + + /* We should check if wsPrinterName is + 1. the Default Printer or not + 2. connected or not + 3. a Local Printer or a Network-Printer + and use different Icons + */ + if((wsPrinterName != NULL) && (wsPrinterName[0] != 0)) + { + FIXME("(select Icon by PrinterName %s not implemented)\n", debugstr_w(wsPrinterName)); + } + + if(pLargeIcon != NULL) + *pLargeIcon = (HICON)LoadImageW(shell32_hInstance, + (LPCWSTR) MAKEINTRESOURCE(iconindex), IMAGE_ICON, + 0, 0, LR_DEFAULTCOLOR|LR_DEFAULTSIZE); + + if(pSmallIcon != NULL) + *pSmallIcon = (HICON)LoadImageW(shell32_hInstance, + (LPCWSTR) MAKEINTRESOURCE(iconindex), IMAGE_ICON, + 16, 16, LR_DEFAULTCOLOR); +} + +/************************************************************************* + * Printers_RegisterWindowW [SHELL32.213] + * used by "printui.dll": + * find the Window of the given Type for the specific Printer and + * return the already existent hwnd or open a new window + */ +EXTERN_C BOOL WINAPI Printers_RegisterWindowW(LPCWSTR wsPrinter, DWORD dwType, + HANDLE * phClassPidl, HWND * phwnd) +{ + FIXME("(%s, %x, %p (%p), %p (%p)) stub!\n", debugstr_w(wsPrinter), dwType, + phClassPidl, (phClassPidl != NULL) ? *(phClassPidl) : NULL, + phwnd, (phwnd != NULL) ? *(phwnd) : NULL); + + return FALSE; +} + +/************************************************************************* + * Printers_UnregisterWindow [SHELL32.214] + */ +EXTERN_C VOID WINAPI Printers_UnregisterWindow(HANDLE hClassPidl, HWND hwnd) +{ + FIXME("(%p, %p) stub!\n", hClassPidl, hwnd); +} + +/*************************************************************************/ + +typedef struct +{ + LPCWSTR szApp; + LPCWSTR szOtherStuff; + HICON hIcon; +} ABOUT_INFO; + +#define DROP_FIELD_TOP (-15) +#define DROP_FIELD_HEIGHT 15 + +/************************************************************************* + * SHAppBarMessage [SHELL32.@] + */ +UINT_PTR WINAPI SHAppBarMessage(DWORD msg, PAPPBARDATA data) +{ + int width=data->rc.right - data->rc.left; + int height=data->rc.bottom - data->rc.top; + RECT rec=data->rc; + + TRACE("msg=%d, data={cb=%d, hwnd=%p, callback=%x, edge=%d, rc=%s, lparam=%lx}\n", + msg, data->cbSize, data->hWnd, data->uCallbackMessage, data->uEdge, + wine_dbgstr_rect(&data->rc), data->lParam); + + switch (msg) + { + case ABM_GETSTATE: + return ABS_ALWAYSONTOP | ABS_AUTOHIDE; + + case ABM_GETTASKBARPOS: + GetWindowRect(data->hWnd, &rec); + data->rc=rec; + return TRUE; + + case ABM_ACTIVATE: + SetActiveWindow(data->hWnd); + return TRUE; + + case ABM_GETAUTOHIDEBAR: + return 0; /* pretend there is no autohide bar */ + + case ABM_NEW: + /* cbSize, hWnd, and uCallbackMessage are used. All other ignored */ + SetWindowPos(data->hWnd,HWND_TOP,0,0,0,0,SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE); + return TRUE; + + case ABM_QUERYPOS: + GetWindowRect(data->hWnd, &(data->rc)); + return TRUE; + + case ABM_REMOVE: + FIXME("ABM_REMOVE broken\n"); + /* FIXME: this is wrong; should it be DestroyWindow instead? */ + /*CloseHandle(data->hWnd);*/ + return TRUE; + + case ABM_SETAUTOHIDEBAR: + SetWindowPos(data->hWnd,HWND_TOP,rec.left+1000,rec.top, + width,height,SWP_SHOWWINDOW); + return TRUE; + + case ABM_SETPOS: + data->uEdge=(ABE_RIGHT | ABE_LEFT); + SetWindowPos(data->hWnd,HWND_TOP,data->rc.left,data->rc.top, + width,height,SWP_SHOWWINDOW); + return TRUE; + + case ABM_WINDOWPOSCHANGED: + return TRUE; + } + + return FALSE; +} + +/************************************************************************* + * SHHelpShortcuts_RunDLLA [SHELL32.@] + * + */ +EXTERN_C DWORD WINAPI SHHelpShortcuts_RunDLLA(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4) +{ + FIXME("(%x, %x, %x, %x) stub!\n", dwArg1, dwArg2, dwArg3, dwArg4); + return 0; +} + +/************************************************************************* + * SHHelpShortcuts_RunDLLA [SHELL32.@] + * + */ +EXTERN_C DWORD WINAPI SHHelpShortcuts_RunDLLW(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4) +{ + FIXME("(%x, %x, %x, %x) stub!\n", dwArg1, dwArg2, dwArg3, dwArg4); + return 0; +} + +/************************************************************************* + * SHLoadInProc [SHELL32.@] + * Create an instance of specified object class from within + * the shell process and release it immediately + */ +EXTERN_C HRESULT WINAPI SHLoadInProc (REFCLSID rclsid) +{ + CComPtr ptr; + + TRACE("%s\n", debugstr_guid(&rclsid)); + + CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&ptr); + if (ptr) + return NOERROR; + return DISP_E_MEMBERNOTFOUND; +} + +static VOID SetRegTextData(HWND hWnd, HKEY hKey, LPCWSTR Value, UINT uID) +{ + DWORD dwBufferSize; + DWORD dwType; + LPWSTR lpBuffer; + + if( RegQueryValueExW(hKey, Value, NULL, &dwType, NULL, &dwBufferSize) == ERROR_SUCCESS ) + { + if(dwType == REG_SZ) + { + lpBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwBufferSize); + + if(lpBuffer) + { + if( RegQueryValueExW(hKey, Value, NULL, &dwType, (LPBYTE)lpBuffer, &dwBufferSize) == ERROR_SUCCESS ) + { + SetDlgItemTextW(hWnd, uID, lpBuffer); + } + + HeapFree(GetProcessHeap(), 0, lpBuffer); + } + } + } +} + +INT_PTR CALLBACK AboutAuthorsDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + switch(msg) + { + case WM_INITDIALOG: + { + const char* const *pstr = SHELL_Authors; + + // Add the authors to the list + SendDlgItemMessageW( hWnd, IDC_SHELL_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, FALSE, 0 ); + + while (*pstr) + { + WCHAR name[64]; + + /* authors list is in utf-8 format */ + MultiByteToWideChar( CP_UTF8, 0, *pstr, -1, name, sizeof(name)/sizeof(WCHAR) ); + SendDlgItemMessageW( hWnd, IDC_SHELL_ABOUT_AUTHORS_LISTBOX, LB_ADDSTRING, (WPARAM)-1, (LPARAM)name ); + pstr++; + } + + SendDlgItemMessageW( hWnd, IDC_SHELL_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, TRUE, 0 ); + + return TRUE; + } + } + + return FALSE; +} +/************************************************************************* + * AboutDlgProc (internal) + */ +INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + static DWORD cxLogoBmp; + static DWORD cyLogoBmp; + static HBITMAP hLogoBmp; + static HWND hWndAuthors; + + switch(msg) + { + case WM_INITDIALOG: + { + ABOUT_INFO *info = (ABOUT_INFO *)lParam; + + if (info) + { + const WCHAR szRegKey[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; + HKEY hRegKey; + MEMORYSTATUSEX MemStat; + WCHAR szAppTitle[512]; + WCHAR szAppTitleTemplate[512]; + WCHAR szAuthorsText[20]; + + // Preload the ROS bitmap + hLogoBmp = (HBITMAP)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDB_SHELL_ABOUT_LOGO_24BPP), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); + + if(hLogoBmp) + { + BITMAP bmpLogo; + + GetObject( hLogoBmp, sizeof(BITMAP), &bmpLogo ); + + cxLogoBmp = bmpLogo.bmWidth; + cyLogoBmp = bmpLogo.bmHeight; + } + + // Set App-specific stuff (icon, app name, szOtherStuff string) + SendDlgItemMessageW(hWnd, IDC_SHELL_ABOUT_ICON, STM_SETICON, (WPARAM)info->hIcon, 0); + + GetWindowTextW( hWnd, szAppTitleTemplate, sizeof(szAppTitleTemplate) / sizeof(WCHAR) ); + swprintf( szAppTitle, szAppTitleTemplate, info->szApp ); + SetWindowTextW( hWnd, szAppTitle ); + + SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_APPNAME, info->szApp ); + SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_OTHERSTUFF, info->szOtherStuff ); + + // Set the registered user and organization name + if(RegOpenKeyExW( HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_QUERY_VALUE, &hRegKey ) == ERROR_SUCCESS) + { + SetRegTextData( hWnd, hRegKey, L"RegisteredOwner", IDC_SHELL_ABOUT_REG_USERNAME ); + SetRegTextData( hWnd, hRegKey, L"RegisteredOrganization", IDC_SHELL_ABOUT_REG_ORGNAME ); + + RegCloseKey( hRegKey ); + } + + // Set the value for the installed physical memory + MemStat.dwLength = sizeof(MemStat); + if( GlobalMemoryStatusEx(&MemStat) ) + { + WCHAR szBuf[12]; + + if (MemStat.ullTotalPhys > 1024 * 1024 * 1024) + { + double dTotalPhys; + WCHAR szDecimalSeparator[4]; + WCHAR szUnits[3]; + + // We're dealing with GBs or more + MemStat.ullTotalPhys /= 1024 * 1024; + + if (MemStat.ullTotalPhys > 1024 * 1024) + { + // We're dealing with TBs or more + MemStat.ullTotalPhys /= 1024; + + if (MemStat.ullTotalPhys > 1024 * 1024) + { + // We're dealing with PBs or more + MemStat.ullTotalPhys /= 1024; + + dTotalPhys = (double)MemStat.ullTotalPhys / 1024; + wcscpy( szUnits, L"PB" ); + } + else + { + dTotalPhys = (double)MemStat.ullTotalPhys / 1024; + wcscpy( szUnits, L"TB" ); + } + } + else + { + dTotalPhys = (double)MemStat.ullTotalPhys / 1024; + wcscpy( szUnits, L"GB" ); + } + + // We need the decimal point of the current locale to display the RAM size correctly + if (GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, + szDecimalSeparator, + sizeof(szDecimalSeparator) / sizeof(WCHAR)) > 0) + { + UCHAR uDecimals; + UINT uIntegral; + + uIntegral = (UINT)dTotalPhys; + uDecimals = (UCHAR)((UINT)(dTotalPhys * 100) - uIntegral * 100); + + // Display the RAM size with 2 decimals + swprintf(szBuf, L"%u%s%02u %s", uIntegral, szDecimalSeparator, uDecimals, szUnits); + } + } + else + { + // We're dealing with MBs, don't show any decimals + swprintf( szBuf, L"%u MB", (UINT)MemStat.ullTotalPhys / 1024 / 1024 ); + } + + SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_PHYSMEM, szBuf); + } + + // Add the Authors dialog + hWndAuthors = CreateDialogW( shell32_hInstance, MAKEINTRESOURCEW(IDD_SHELL_ABOUT_AUTHORS), hWnd, AboutAuthorsDlgProc ); + LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_AUTHORS, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) ); + SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_AUTHORS, szAuthorsText ); + } + + return TRUE; + } + + case WM_PAINT: + { + if(hLogoBmp) + { + PAINTSTRUCT ps; + HDC hdc; + HDC hdcMem; + + hdc = BeginPaint(hWnd, &ps); + hdcMem = CreateCompatibleDC(hdc); + + if(hdcMem) + { + SelectObject(hdcMem, hLogoBmp); + BitBlt(hdc, 0, 0, cxLogoBmp, cyLogoBmp, hdcMem, 0, 0, SRCCOPY); + + DeleteDC(hdcMem); + } + + EndPaint(hWnd, &ps); + } + }; break; + + case WM_COMMAND: + { + switch(wParam) + { + case IDOK: + case IDCANCEL: + EndDialog(hWnd, TRUE); + return TRUE; + + case IDC_SHELL_ABOUT_AUTHORS: + { + static BOOL bShowingAuthors = FALSE; + WCHAR szAuthorsText[20]; + + if(bShowingAuthors) + { + LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_AUTHORS, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) ); + ShowWindow( hWndAuthors, SW_HIDE ); + } + else + { + LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_BACK, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) ); + ShowWindow( hWndAuthors, SW_SHOW ); + } + + SetDlgItemTextW( hWnd, IDC_SHELL_ABOUT_AUTHORS, szAuthorsText ); + bShowingAuthors = !bShowingAuthors; + return TRUE; + } + } + }; break; + + case WM_CLOSE: + EndDialog(hWnd, TRUE); + break; + } + + return FALSE; +} + + +/************************************************************************* + * ShellAboutA [SHELL32.288] + */ +BOOL WINAPI ShellAboutA( HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon ) +{ + BOOL ret; + LPWSTR appW = NULL, otherW = NULL; + int len; + + if (szApp) + { + len = MultiByteToWideChar(CP_ACP, 0, szApp, -1, NULL, 0); + appW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, szApp, -1, appW, len); + } + if (szOtherStuff) + { + len = MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, NULL, 0); + otherW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, otherW, len); + } + + ret = ShellAboutW(hWnd, appW, otherW, hIcon); + + HeapFree(GetProcessHeap(), 0, otherW); + HeapFree(GetProcessHeap(), 0, appW); + return ret; +} + + +/************************************************************************* + * ShellAboutW [SHELL32.289] + */ +BOOL WINAPI ShellAboutW( HWND hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff, + HICON hIcon ) +{ + ABOUT_INFO info; + HRSRC hRes; + DLGTEMPLATE *DlgTemplate; + BOOL bRet; + + TRACE("\n"); + + // DialogBoxIndirectParamW will be called with the hInstance of the calling application, so we have to preload the dialog template + if(!(hRes = FindResourceW(shell32_hInstance, MAKEINTRESOURCEW(IDD_SHELL_ABOUT), (LPWSTR)RT_DIALOG))) + return FALSE; + if(!(DlgTemplate = (DLGTEMPLATE *)LoadResource(shell32_hInstance, hRes))) + return FALSE; + + info.szApp = szApp; + info.szOtherStuff = szOtherStuff; + info.hIcon = hIcon ? hIcon : LoadIconW( 0, (LPWSTR)IDI_WINLOGO ); + + bRet = DialogBoxIndirectParamW((HINSTANCE)GetWindowLongPtrW( hWnd, GWLP_HINSTANCE ), + DlgTemplate, hWnd, AboutDlgProc, (LPARAM)&info ); + return bRet; +} + +/************************************************************************* + * FreeIconList (SHELL32.@) + */ +EXTERN_C void WINAPI FreeIconList( DWORD dw ) +{ + FIXME("%x: stub\n",dw); +} + +/************************************************************************* + * SHLoadNonloadedIconOverlayIdentifiers (SHELL32.@) + */ +EXTERN_C HRESULT WINAPI SHLoadNonloadedIconOverlayIdentifiers( VOID ) +{ + FIXME("stub\n"); + return S_OK; +} + +class CShell32Module : public CComModule +{ +public: +}; + + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_ShellFSFolder, CFSFolder) +OBJECT_ENTRY(CLSID_MyComputer, CDrivesFolder) +OBJECT_ENTRY(CLSID_ShellDesktop, CDesktopFolder) +OBJECT_ENTRY(CLSID_ShellItem, ShellItem) +OBJECT_ENTRY(CLSID_ShellLink, ShellLink) +OBJECT_ENTRY(CLSID_DragDropHelper, IDropTargetHelperImpl) +OBJECT_ENTRY(CLSID_ControlPanel, CControlPanelFolder) +OBJECT_ENTRY(CLSID_AutoComplete, CAutoComplete) +OBJECT_ENTRY(CLSID_MyDocuments, CMyDocsFolder) +OBJECT_ENTRY(CLSID_NetworkPlaces, CNetFolder) +OBJECT_ENTRY(CLSID_FontsFolderShortcut, CFontsFolder) +OBJECT_ENTRY(CLSID_Printers, CPrinterFolder) +OBJECT_ENTRY(CLSID_AdminFolderShortcut, CAdminToolsFolder) +OBJECT_ENTRY(CLSID_RecycleBin, CBitBucket) +OBJECT_ENTRY(CLSID_OpenWithMenu, COpenWithMenu) +OBJECT_ENTRY(CLSID_NewMenu, CNewMenu) +OBJECT_ENTRY(CLSID_StartMenu, CStartMenuCallback) +OBJECT_ENTRY(CLSID_MenuBandSite, CMenuBandSite) +END_OBJECT_MAP() + +CShell32Module gModule; + + +/* +static const struct { + REFIID riid; + LPFNCREATEINSTANCE lpfnCI; +} InterfaceTable[] = { + {CLSID_ShellFSFolder, &IFSFolder_Constructor}, + {CLSID_MyComputer, &ISF_MyComputer_Constructor}, + {CLSID_ShellDesktop, &ISF_Desktop_Constructor}, + {CLSID_ShellItem, &IShellItem_Constructor}, + {CLSID_ShellLink, &IShellLink_Constructor}, + {CLSID_DragDropHelper, &IDropTargetHelper_Constructor}, + {CLSID_ControlPanel, &IControlPanel_Constructor}, + {CLSID_AutoComplete, &IAutoComplete_Constructor}, + {CLSID_MyDocuments, &ISF_MyDocuments_Constructor}, + {CLSID_NetworkPlaces, &ISF_NetworkPlaces_Constructor}, + {CLSID_FontsFolderShortcut, &ISF_Fonts_Constructor}, + {CLSID_Printers, &ISF_Printers_Constructor}, + {CLSID_AdminFolderShortcut, &ISF_AdminTools_Constructor}, + {CLSID_RecycleBin, &RecycleBin_Constructor}, + {CLSID_OpenWithMenu, &SHEOW_Constructor}, + {CLSID_NewMenu, &INewItem_Constructor}, + {CLSID_StartMenu, &StartMenu_Constructor}, + {CLSID_MenuBandSite, &MenuBandSite_Constructor}, +}; +*/ + +/*********************************************************************** + * DllGetVersion [SHELL32.@] + * + * Retrieves version information of the 'SHELL32.DLL' + * + * PARAMS + * pdvi [O] pointer to version information structure. + * + * RETURNS + * Success: S_OK + * Failure: E_INVALIDARG + * + * NOTES + * Returns version of a shell32.dll from IE4.01 SP1. + */ + +STDAPI DllGetVersion(DLLVERSIONINFO *pdvi) +{ + /* FIXME: shouldn't these values come from the version resource? */ + if (pdvi->cbSize == sizeof(DLLVERSIONINFO) || + pdvi->cbSize == sizeof(DLLVERSIONINFO2)) + { + pdvi->dwMajorVersion = WINE_FILEVERSION_MAJOR; + pdvi->dwMinorVersion = WINE_FILEVERSION_MINOR; + pdvi->dwBuildNumber = WINE_FILEVERSION_BUILD; + pdvi->dwPlatformID = WINE_FILEVERSION_PLATFORMID; + if (pdvi->cbSize == sizeof(DLLVERSIONINFO2)) + { + DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2 *)pdvi; + + pdvi2->dwFlags = 0; + pdvi2->ullVersion = MAKEDLLVERULL(WINE_FILEVERSION_MAJOR, + WINE_FILEVERSION_MINOR, + WINE_FILEVERSION_BUILD, + WINE_FILEVERSION_PLATFORMID); + } + TRACE("%u.%u.%u.%u\n", + pdvi->dwMajorVersion, pdvi->dwMinorVersion, + pdvi->dwBuildNumber, pdvi->dwPlatformID); + return S_OK; + } + else + { + WARN("wrong DLLVERSIONINFO size from app\n"); + return E_INVALIDARG; + } +} + +/************************************************************************* + * global variables of the shell32.dll + * all are once per process + * + */ +HINSTANCE shell32_hInstance; +HIMAGELIST ShellSmallIconList = 0; +HIMAGELIST ShellBigIconList = 0; + +void *operator new (size_t, void *buf) +{ + return buf; +} + +/************************************************************************* + * SHELL32 DllMain + * + * NOTES + * calling oleinitialize here breaks sone apps. + */ +STDAPI_(BOOL) DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID fImpLoad) +{ + TRACE("%p 0x%x %p\n", hInstance, dwReason, fImpLoad); + if (dwReason == DLL_PROCESS_ATTACH) + { + /* HACK - the global constructors don't run, so I placement new them here */ + new (&gModule) CShell32Module; + new (&_AtlWinModule) CAtlWinModule; + new (&_AtlBaseModule) CAtlBaseModule; + new (&_AtlComModule) CAtlComModule; + + shell32_hInstance = hInstance; + gModule.Init(ObjectMap, hInstance, NULL); + + DisableThreadLibraryCalls (hInstance); + + /* get full path to this DLL for IExtractIconW_fnGetIconLocation() */ + GetModuleFileNameW(hInstance, swShell32Name, MAX_PATH); + swShell32Name[MAX_PATH - 1] = '\0'; + + InitCommonControlsEx(NULL); + + SIC_Initialize(); + InitChangeNotifications(); + InitIconOverlays(); + } + else if (dwReason == DLL_PROCESS_DETACH) + { + shell32_hInstance = NULL; + SIC_Destroy(); + FreeChangeNotifications(); + gModule.Term(); + } + return TRUE; +} + +/*********************************************************************** + * DllCanUnloadNow (SHELL32.@) + */ +STDAPI DllCanUnloadNow() +{ + return gModule.DllCanUnloadNow(); +} + +/************************************************************************* + * DllGetClassObject [SHELL32.@] + * SHDllGetClassObject [SHELL32.128] + */ +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + HRESULT hResult; + + TRACE("CLSID:%s,IID:%s\n", shdebugstr_guid(&rclsid), shdebugstr_guid(&riid)); + + hResult = gModule.DllGetClassObject(rclsid, riid, ppv); + TRACE("-- pointer to class factory: %p\n", *ppv); + return hResult; +} + +/*********************************************************************** + * DllRegisterServer (BROWSEUI.@) + */ +STDAPI DllRegisterServer() +{ + return gModule.DllRegisterServer(FALSE); +} + +/*********************************************************************** + * DllUnregisterServer (BROWSEUI.@) + */ +STDAPI DllUnregisterServer() +{ + return gModule.DllUnregisterServer(FALSE); +} + +/************************************************************************* + * DllInstall [SHELL32.@] + * + * PARAMETERS + * + * BOOL bInstall - TRUE for install, FALSE for uninstall + * LPCWSTR pszCmdLine - command line (unused by shell32?) + */ + +HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline) +{ + FIXME("%s %s: stub\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline)); + return S_OK; /* indicate success */ +} diff --git a/reactos/dll/win32/shell32/shell32_main.h b/reactos/dll/win32/shell32/shell32_main.h index 1ec3d95c6cf..729e4423a8c 100644 --- a/reactos/dll/win32/shell32/shell32_main.h +++ b/reactos/dll/win32/shell32/shell32_main.h @@ -50,7 +50,7 @@ extern HINSTANCE shell32_hInstance; extern HIMAGELIST ShellSmallIconList; extern HIMAGELIST ShellBigIconList; -BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList); +extern "C" BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList); /* Iconcache */ #define INVALID_INDEX -1 @@ -81,45 +81,22 @@ DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len); /**************************************************************************** * Class constructors */ -LPDATAOBJECT IDataObject_Constructor(HWND hwndOwner, LPCITEMIDLIST myPidl, LPCITEMIDLIST * apidl, UINT cidl); -LPENUMFORMATETC IEnumFORMATETC_Constructor(UINT, const FORMATETC []); +HRESULT IDataObject_Constructor(HWND hwndOwner, LPCITEMIDLIST pMyPidl, LPCITEMIDLIST * apidl, UINT cidl, IDataObject **dataObject); +HRESULT IEnumFORMATETC_Constructor(UINT cfmt, const FORMATETC afmt[], IEnumFORMATETC **enumerator); LPCLASSFACTORY IClassFactory_Constructor(REFCLSID); IContextMenu2 * ISvItemCm_Constructor(LPSHELLFOLDER pSFParent, LPCITEMIDLIST pidl, const LPCITEMIDLIST *aPidls, UINT uItemCount); HRESULT WINAPI INewItem_Constructor(IUnknown * pUnkOuter, REFIID riif, LPVOID *ppv); IContextMenu2 * ISvStaticItemCm_Constructor(LPSHELLFOLDER pSFParent, LPCITEMIDLIST pidl, LPCITEMIDLIST *apidl, UINT cidl, HKEY hKey); IContextMenu2 * ISvBgCm_Constructor(LPSHELLFOLDER pSFParent, BOOL bDesktop); -LPSHELLVIEW IShellView_Constructor(LPSHELLFOLDER); +HRESULT WINAPI IShellView_Constructor(IShellFolder *pFolder, IShellView **newView); -HRESULT WINAPI IFSFolder_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI IShellItem_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI IShellLink_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); HRESULT WINAPI IShellLink_ConstructFromFile(IUnknown * pUnkOuter, REFIID riid, LPCITEMIDLIST pidl, LPVOID * ppv); -HRESULT WINAPI ISF_Desktop_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI ISF_MyComputer_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI ISF_Printers_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI ISF_MyDocuments_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI ISF_NetworkPlaces_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI ISF_Fonts_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI ISF_AdminTools_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI IDropTargetHelper_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); HRESULT WINAPI IFileSystemBindData_Constructor(const WIN32_FIND_DATAW *pfd, LPBC *ppV); -HRESULT WINAPI IControlPanel_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI UnixFolder_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); -HRESULT WINAPI UnixDosFolder_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppv); -HRESULT WINAPI FolderShortcut_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppv); -HRESULT WINAPI MyDocuments_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppv); -HRESULT WINAPI RecycleBin_Constructor(IUnknown * pUnkOuter, REFIID riif, LPVOID *ppv); -HRESULT WINAPI SHEOW_Constructor(IUnknown * pUnkOuter, REFIID riif, LPVOID *ppv); -HRESULT WINAPI ShellFSFolder_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppv); -HRESULT WINAPI StartMenu_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppv); -HRESULT WINAPI MenuBandSite_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID *ppv); extern HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST, LPWSTR, UINT, int*); HRESULT WINAPI CPanel_ExtractIconA(LPITEMIDLIST pidl, LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); HRESULT WINAPI CPanel_ExtractIconW(LPITEMIDLIST pidl, LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); -HRESULT WINAPI IAutoComplete_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); - LPEXTRACTICONA IExtractIconA_Constructor(LPCITEMIDLIST); LPEXTRACTICONW IExtractIconW_Constructor(LPCITEMIDLIST); @@ -183,29 +160,29 @@ static BOOL __inline SHELL_OsIsUnicode(void) SHFree(*ptr); \ *ptr = NULL; \ }; -static void __inline __SHCloneStrA(char ** target,const char * source) +static void __inline __SHCloneStrA(char **target, const char *source) { - *target = SHAlloc(strlen(source)+1); + *target = (char *)SHAlloc(strlen(source) + 1); strcpy(*target, source); } -static void __inline __SHCloneStrWtoA(char ** target, const WCHAR * source) +static void __inline __SHCloneStrWtoA(char **target, const WCHAR *source) { int len = WideCharToMultiByte(CP_ACP, 0, source, -1, NULL, 0, NULL, NULL); - *target = SHAlloc(len); + *target = (char *)SHAlloc(len); WideCharToMultiByte(CP_ACP, 0, source, -1, *target, len, NULL, NULL); } -static void __inline __SHCloneStrW(WCHAR ** target, const WCHAR * source) +static void __inline __SHCloneStrW(WCHAR **target, const WCHAR *source) { - *target = SHAlloc( (lstrlenW(source)+1) * sizeof(WCHAR) ); + *target = (WCHAR *)SHAlloc((lstrlenW(source) + 1) * sizeof(WCHAR) ); lstrcpyW(*target, source); } -static LPWSTR __inline __SHCloneStrAtoW(WCHAR ** target, const char * source) +static LPWSTR __inline __SHCloneStrAtoW(WCHAR **target, const char *source) { int len = MultiByteToWideChar(CP_ACP, 0, source, -1, NULL, 0); - *target = SHAlloc(len*sizeof(WCHAR)); + *target = (WCHAR *)SHAlloc(len * sizeof(WCHAR)); MultiByteToWideChar(CP_ACP, 0, source, -1, *target, len); return *target; } @@ -235,7 +212,7 @@ BOOL SHELL_IsShortcut(LPCITEMIDLIST); INT_PTR CALLBACK SH_FileGeneralDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK SH_FileVersionDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -HPROPSHEETPAGE SH_CreatePropertySheetPage(LPSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle); +HPROPSHEETPAGE SH_CreatePropertySheetPage(LPCSTR resname, DLGPROC dlgproc, LPARAM lParam, LPWSTR szTitle); BOOL SH_ShowDriveProperties(WCHAR * drive, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST * apidl); BOOL SH_ShowRecycleBinProperties(WCHAR sDrive); BOOL SH_ShowPropertiesDialog(LPWSTR lpf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST * apidl); diff --git a/reactos/dll/win32/shell32/shellitem.cpp b/reactos/dll/win32/shell32/shellitem.cpp new file mode 100644 index 00000000000..995d3b235af --- /dev/null +++ b/reactos/dll/win32/shell32/shellitem.cpp @@ -0,0 +1,248 @@ +/* + * IShellItem implementation + * + * Copyright 2008 Vincent Povirk for CodeWeavers + * 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); + +EXTERN_C HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent, + IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi); + +ShellItem::ShellItem() +{ + pidl = NULL; +} + +ShellItem::~ShellItem() +{ + ILFree(pidl); +} + +HRESULT ShellItem::get_parent_pidl(LPITEMIDLIST *parent_pidl) +{ + *parent_pidl = ILClone(pidl); + if (*parent_pidl) + { + if (ILRemoveLastID(*parent_pidl)) + return S_OK; + else + { + ILFree(*parent_pidl); + *parent_pidl = NULL; + return E_INVALIDARG; + } + } + else + { + *parent_pidl = NULL; + return E_OUTOFMEMORY; + } +} + +HRESULT ShellItem::get_parent_shellfolder(IShellFolder **ppsf) +{ + LPITEMIDLIST parent_pidl; + CComPtr desktop; + HRESULT ret; + + ret = get_parent_pidl(&parent_pidl); + if (SUCCEEDED(ret)) + { + ret = SHGetDesktopFolder(&desktop); + if (SUCCEEDED(ret)) + ret = desktop->BindToObject(parent_pidl, NULL, IID_IShellFolder, (void**)ppsf); + ILFree(parent_pidl); + } + + return ret; +} + +HRESULT WINAPI ShellItem::BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) +{ + FIXME("(%p,%p,%s,%p,%p)\n", this, pbc, shdebugstr_guid(&rbhid), riid, ppvOut); + + *ppvOut = NULL; + + return E_NOTIMPL; +} + +HRESULT WINAPI ShellItem::GetParent(IShellItem **ppsi) +{ + LPITEMIDLIST parent_pidl; + HRESULT ret; + + TRACE("(%p,%p)\n", this, ppsi); + + ret = get_parent_pidl(&parent_pidl); + if (SUCCEEDED(ret)) + { + ret = SHCreateShellItem(NULL, NULL, parent_pidl, ppsi); + ILFree(parent_pidl); + } + + return ret; +} + +HRESULT WINAPI ShellItem::GetDisplayName(SIGDN sigdnName, LPWSTR *ppszName) +{ + FIXME("(%p,%x,%p)\n", this, sigdnName, ppszName); + + *ppszName = NULL; + + return E_NOTIMPL; +} + +HRESULT WINAPI ShellItem::GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) +{ + CComPtr parent_folder; + LPITEMIDLIST child_pidl; + HRESULT ret; + + TRACE("(%p,%x,%p)\n", this, sfgaoMask, psfgaoAttribs); + + ret = get_parent_shellfolder(&parent_folder); + if (SUCCEEDED(ret)) + { + child_pidl = ILFindLastID(pidl); + *psfgaoAttribs = sfgaoMask; + ret = parent_folder->GetAttributesOf(1, (LPCITEMIDLIST*)&child_pidl, psfgaoAttribs); + } + + return ret; +} + +HRESULT WINAPI ShellItem::Compare(IShellItem *oth, SICHINTF hint, int *piOrder) +{ + FIXME("(%p,%p,%x,%p)\n", this, oth, hint, piOrder); + + return E_NOTIMPL; +} + +HRESULT WINAPI ShellItem::GetClassID(CLSID *pClassID) +{ + TRACE("(%p,%p)\n", this, pClassID); + + *pClassID = CLSID_ShellItem; + return S_OK; +} + + +HRESULT WINAPI ShellItem::SetIDList(LPCITEMIDLIST pidlx) +{ + LPITEMIDLIST new_pidl; + + TRACE("(%p,%p)\n", this, pidlx); + + new_pidl = ILClone(pidlx); + + if (new_pidl) + { + ILFree(pidl); + pidl = new_pidl; + return S_OK; + } + else + return E_OUTOFMEMORY; +} + +HRESULT WINAPI ShellItem::GetIDList(LPITEMIDLIST *ppidl) +{ + TRACE("(%p,%p)\n", this, ppidl); + + *ppidl = ILClone(pidl); + if (*ppidl) + return S_OK; + else + return E_OUTOFMEMORY; +} + +HRESULT WINAPI SHCreateShellItem(LPCITEMIDLIST pidlParent, + IShellFolder *psfParent, LPCITEMIDLIST pidl, IShellItem **ppsi) +{ + IShellItem *newShellItem; + LPITEMIDLIST new_pidl; + CComPtr newPersistIDList; + HRESULT ret; + + TRACE("(%p,%p,%p,%p)\n", pidlParent, psfParent, pidl, ppsi); + + if (!pidl) + { + return E_INVALIDARG; + } + else if (pidlParent || psfParent) + { + LPITEMIDLIST temp_parent=NULL; + if (!pidlParent) + { + CComPtr ppf2Parent; + + if (FAILED(psfParent->QueryInterface(IID_IPersistFolder2, (void**)&ppf2Parent))) + { + FIXME("couldn't get IPersistFolder2 interface of parent\n"); + return E_NOINTERFACE; + } + + if (FAILED(ppf2Parent->GetCurFolder(&temp_parent))) + { + FIXME("couldn't get parent PIDL\n"); + return E_NOINTERFACE; + } + + pidlParent = temp_parent; + } + + new_pidl = ILCombine(pidlParent, pidl); + ILFree(temp_parent); + + if (!new_pidl) + return E_OUTOFMEMORY; + } + else + { + new_pidl = ILClone(pidl); + if (!new_pidl) + return E_OUTOFMEMORY; + } + + ret = ShellItem::_CreatorClass::CreateInstance(NULL, IID_IShellItem, (void**)&newShellItem); + if (FAILED(ret)) + { + *ppsi = NULL; + ILFree(new_pidl); + return ret; + } + ret = newShellItem->QueryInterface(IID_IPersistIDList, (void **)&newPersistIDList); + if (FAILED(ret)) + { + ILFree(new_pidl); + return ret; + } + ret = newPersistIDList->SetIDList(new_pidl); + if (FAILED(ret)) + { + ILFree(new_pidl); + return ret; + } + ILFree(new_pidl); + *ppsi = newShellItem; + return ret; +} diff --git a/reactos/dll/win32/shell32/shellitem.h b/reactos/dll/win32/shell32/shellitem.h new file mode 100644 index 00000000000..546fb74c44e --- /dev/null +++ b/reactos/dll/win32/shell32/shellitem.h @@ -0,0 +1,62 @@ +/* + * IShellItem implementation + * + * Copyright 2008 Vincent Povirk for CodeWeavers + * 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 + */ + +#ifndef _SHELLITEM_H_ +#define _SHELLITEM_H_ + +class ShellItem : + public CComCoClass, + public CComObjectRootEx, + public IShellItem, + public IPersistIDList +{ +private: + LPITEMIDLIST pidl; +public: + ShellItem(); + ~ShellItem(); + HRESULT get_parent_pidl(LPITEMIDLIST *parent_pidl); + HRESULT get_parent_shellfolder(IShellFolder **ppsf); + + // IShellItem + virtual HRESULT WINAPI BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut); + virtual HRESULT WINAPI GetParent(IShellItem **ppsi); + virtual HRESULT WINAPI GetDisplayName(SIGDN sigdnName, LPWSTR *ppszName); + virtual HRESULT WINAPI GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs); + virtual HRESULT WINAPI Compare(IShellItem *oth, SICHINTF hint, int *piOrder); + + // IPersistIDList + virtual HRESULT WINAPI GetClassID(CLSID *pClassID); + virtual HRESULT WINAPI SetIDList(LPCITEMIDLIST pidl); + virtual HRESULT WINAPI GetIDList(LPITEMIDLIST *ppidl); + +DECLARE_NO_REGISTRY() +DECLARE_NOT_AGGREGATABLE(ShellItem) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(ShellItem) + COM_INTERFACE_ENTRY_IID(IID_IShellItem, IShellItem) + COM_INTERFACE_ENTRY_IID(IID_IPersistIDList, IPersistIDList) +END_COM_MAP() +}; + +#endif // _SHELLITEM_H_ diff --git a/reactos/dll/win32/shell32/shelllink.cpp b/reactos/dll/win32/shell32/shelllink.cpp new file mode 100644 index 00000000000..fa0a251ea01 --- /dev/null +++ b/reactos/dll/win32/shell32/shelllink.cpp @@ -0,0 +1,2215 @@ +/* + * + * Copyright 1997 Marcus Meissner + * Copyright 1998 Juergen Schmied + * Copyright 2005 Mike McCormack + * 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 + * + * NOTES + * Nearly complete information about the binary formats + * of .lnk files available at http://www.wotsit.org + * + * You can use winedump to examine the contents of a link file: + * winedump lnk sc.lnk + * + * MSI advertised shortcuts are totally undocumented. They provide an + * icon for a program that is not yet installed, and invoke MSI to + * install the program when the shortcut is clicked on. They are + * created by passing a special string to SetPath, and the information + * in that string is parsed an stored. + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +#define SHLINK_LOCAL 0 +#define SHLINK_REMOTE 1 +#define MAX_PROPERTY_SHEET_PAGE 32 + +/* link file formats */ + +#include "pshpack1.h" + +struct LINK_HEADER +{ + DWORD dwSize; /* 0x00 size of the header - 0x4c */ + GUID MagicGuid; /* 0x04 is CLSID_ShellLink */ + DWORD dwFlags; /* 0x14 describes elements following */ + DWORD dwFileAttr; /* 0x18 attributes of the target file */ + FILETIME Time1; /* 0x1c */ + FILETIME Time2; /* 0x24 */ + FILETIME Time3; /* 0x2c */ + DWORD dwFileLength; /* 0x34 File length */ + DWORD nIcon; /* 0x38 icon number */ + DWORD fStartup; /* 0x3c startup type */ + DWORD wHotKey; /* 0x40 hotkey */ + DWORD Unknown5; /* 0x44 */ + DWORD Unknown6; /* 0x48 */ +}; + +struct LOCATION_INFO +{ + DWORD dwTotalSize; + DWORD dwHeaderSize; + DWORD dwFlags; + DWORD dwVolTableOfs; + DWORD dwLocalPathOfs; + DWORD dwNetworkVolTableOfs; + DWORD dwFinalPathOfs; +}; + +struct LOCAL_VOLUME_INFO +{ + DWORD dwSize; + DWORD dwType; + DWORD dwVolSerial; + DWORD dwVolLabelOfs; +}; + +struct volume_info +{ + DWORD type; + DWORD serial; + WCHAR label[12]; /* assume 8.3 */ +}; + +#include "poppack.h" + +/* IShellLink Implementation */ + +static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath); + +/* strdup on the process heap */ +static LPWSTR __inline HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str) +{ + INT len; + LPWSTR p; + + assert(str); + + len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); + p = (LPWSTR)HeapAlloc( heap, flags, len*sizeof (WCHAR) ); + if( !p ) + return p; + MultiByteToWideChar( CP_ACP, 0, str, -1, p, len ); + return p; +} + +static LPWSTR __inline strdupW( LPCWSTR src ) +{ + LPWSTR dest; + if (!src) return NULL; + dest = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, (wcslen(src)+1)*sizeof(WCHAR) ); + if (dest) + wcscpy(dest, src); + return dest; +} + +ShellLink::ShellLink() +{ + pPidl = NULL; + wHotKey = 0; + memset(&time1, 0, sizeof(time1)); + memset(&time2, 0, sizeof(time2)); + memset(&time3, 0, sizeof(time3)); + iShowCmd = SW_SHOWNORMAL; + sIcoPath = NULL; + iIcoNdx = 0; + sPath = NULL; + sArgs = NULL; + sWorkDir = NULL; + sDescription = NULL; + sPathRel = NULL; + sProduct = NULL; + sComponent = NULL; + memset(&volume, 0, sizeof(volume)); + sLinkPath = NULL; + bRunAs = FALSE; + bDirty = FALSE; + iIdOpen = -1; +} + +ShellLink::~ShellLink() +{ + TRACE("-- destroying IShellLink(%p)\n", this); + + HeapFree(GetProcessHeap(), 0, sIcoPath); + HeapFree(GetProcessHeap(), 0, sArgs); + HeapFree(GetProcessHeap(), 0, sWorkDir); + HeapFree(GetProcessHeap(), 0, sDescription); + HeapFree(GetProcessHeap(), 0, sPath); + HeapFree(GetProcessHeap(), 0, sLinkPath); + + if (pPidl) + ILFree(pPidl); +} + +HRESULT WINAPI ShellLink::GetClassID(CLSID *pclsid ) +{ + TRACE("%p %p\n", this, pclsid); + + if (pclsid == NULL) + return E_POINTER; + *pclsid = CLSID_ShellLink; + return S_OK; +} + +HRESULT WINAPI ShellLink::IsDirty() +{ + TRACE("(%p)\n",this); + + if (bDirty) + return S_OK; + + return S_FALSE; +} + +HRESULT WINAPI ShellLink::Load(LPCOLESTR pszFileName, DWORD dwMode) +{ + HRESULT r; + CComPtr stm; + + TRACE("(%p, %s, %x)\n",this, debugstr_w(pszFileName), dwMode); + + if (dwMode == 0) + dwMode = STGM_READ | STGM_SHARE_DENY_WRITE; + r = SHCreateStreamOnFileW(pszFileName, dwMode, &stm); + if (SUCCEEDED(r)) + { + HeapFree(GetProcessHeap(), 0, sLinkPath); + sLinkPath = strdupW(pszFileName); + r = Load(stm); + ShellLink_UpdatePath(sPathRel, pszFileName, sWorkDir, &sPath); + bDirty = FALSE; + } + TRACE("-- returning hr %08x\n", r); + return r; +} + +static BOOL StartLinkProcessor( LPCOLESTR szLink ) +{ + static const WCHAR szFormat[] = { + 'w','i','n','e','m','e','n','u','b','u','i','l','d','e','r','.','e','x','e', + ' ','-','w',' ','"','%','s','"',0 }; + LONG len; + LPWSTR buffer; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + BOOL ret; + + len = sizeof(szFormat) + wcslen( szLink ) * sizeof(WCHAR); + buffer = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, len ); + if( !buffer ) + return FALSE; + + swprintf( buffer, szFormat, szLink ); + + TRACE("starting %s\n",debugstr_w(buffer)); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + + ret = CreateProcessW( NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ); + + HeapFree( GetProcessHeap(), 0, buffer ); + + if (ret) + { + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + } + + return ret; +} + +HRESULT WINAPI ShellLink::Save(LPCOLESTR pszFileName, BOOL fRemember) +{ + HRESULT r; + CComPtr stm; + + TRACE("(%p)->(%s)\n", this, debugstr_w(pszFileName)); + + if (!pszFileName) + return E_FAIL; + + r = SHCreateStreamOnFileW( pszFileName, STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE, &stm ); + if( SUCCEEDED( r ) ) + { + r = Save(stm, FALSE); + + if( SUCCEEDED( r ) ) + { + if ( sLinkPath ) + { + HeapFree(GetProcessHeap(), 0, sLinkPath); + } + sLinkPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(pszFileName)+1) * sizeof(WCHAR)); + if ( sLinkPath ) + { + wcscpy(sLinkPath, pszFileName); + } + + StartLinkProcessor( pszFileName ); + + bDirty = FALSE; + } + else + { + DeleteFileW( pszFileName ); + WARN("Failed to create shortcut %s\n", debugstr_w(pszFileName) ); + } + } + + return r; +} + +HRESULT WINAPI ShellLink::SaveCompleted(LPCOLESTR pszFileName) +{ + FIXME("(%p)->(%s)\n", this, debugstr_w(pszFileName)); + return NOERROR; +} + +HRESULT WINAPI ShellLink::GetCurFile(LPOLESTR *ppszFileName) +{ + *ppszFileName = NULL; + + if ( !sLinkPath) + { + /* IPersistFile::GetCurFile called before IPersistFile::Save */ + return S_FALSE; + } + + *ppszFileName = (LPOLESTR)CoTaskMemAlloc((wcslen(sLinkPath)+1) * sizeof(WCHAR)); + if (!*ppszFileName) + { + /* out of memory */ + return E_OUTOFMEMORY; + } + + /* copy last saved filename */ + wcscpy(*ppszFileName, sLinkPath); + + return NOERROR; +} + +/************************************************************************ + * IPersistStream_IsDirty (IPersistStream) + */ + +static HRESULT Stream_LoadString( IStream* stm, BOOL unicode, LPWSTR *pstr ) +{ + DWORD count; + USHORT len; + LPSTR temp; + LPWSTR str; + HRESULT r; + + TRACE("%p\n", stm); + + count = 0; + r = stm->Read(&len, sizeof(len), &count); + if ( FAILED (r) || ( count != sizeof(len) ) ) + return E_FAIL; + + if( unicode ) + len *= sizeof (WCHAR); + + TRACE("reading %d\n", len); + temp = (LPSTR)HeapAlloc(GetProcessHeap(), 0, len+sizeof(WCHAR)); + if( !temp ) + return E_OUTOFMEMORY; + count = 0; + r = stm->Read(temp, len, &count); + if( FAILED (r) || ( count != len ) ) + { + HeapFree( GetProcessHeap(), 0, temp ); + return E_FAIL; + } + + TRACE("read %s\n", debugstr_an(temp,len)); + + /* convert to unicode if necessary */ + if( !unicode ) + { + count = MultiByteToWideChar( CP_ACP, 0, temp, len, NULL, 0 ); + str = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, (count+1)*sizeof (WCHAR) ); + if( !str ) + { + HeapFree( GetProcessHeap(), 0, temp ); + return E_OUTOFMEMORY; + } + MultiByteToWideChar( CP_ACP, 0, temp, len, str, count ); + HeapFree( GetProcessHeap(), 0, temp ); + } + else + { + count /= 2; + str = (LPWSTR)temp; + } + str[count] = 0; + + *pstr = str; + + return S_OK; +} + +static HRESULT Stream_ReadChunk( IStream* stm, LPVOID *data ) +{ + DWORD size; + ULONG count; + HRESULT r; + struct sized_chunk { + DWORD size; + unsigned char data[1]; + } *chunk; + + TRACE("%p\n",stm); + + r = stm->Read(&size, sizeof(size), &count ); + if( FAILED( r ) || count != sizeof(size) ) + return E_FAIL; + + chunk = (sized_chunk *)HeapAlloc( GetProcessHeap(), 0, size ); + if( !chunk ) + return E_OUTOFMEMORY; + + chunk->size = size; + r = stm->Read(chunk->data, size - sizeof(size), &count ); + if( FAILED( r ) || count != (size - sizeof(size)) ) + { + HeapFree( GetProcessHeap(), 0, chunk ); + return E_FAIL; + } + + TRACE("Read %d bytes\n",chunk->size); + + *data = chunk; + + return S_OK; +} + +static BOOL Stream_LoadVolume( LOCAL_VOLUME_INFO *vol, ShellLink::volume_info *volume ) +{ + const int label_sz = sizeof volume->label/sizeof volume->label[0]; + LPSTR label; + int len; + + volume->serial = vol->dwVolSerial; + volume->type = vol->dwType; + + if( !vol->dwVolLabelOfs ) + return FALSE; + if( vol->dwSize <= vol->dwVolLabelOfs ) + return FALSE; + len = vol->dwSize - vol->dwVolLabelOfs; + + label = (LPSTR) vol; + label += vol->dwVolLabelOfs; + MultiByteToWideChar( CP_ACP, 0, label, len, volume->label, label_sz-1); + + return TRUE; +} + +static LPWSTR Stream_LoadPath( LPCSTR p, DWORD maxlen ) +{ + unsigned int len = 0, wlen; + LPWSTR path; + + while( p[len] && (len < maxlen) ) + len++; + + wlen = MultiByteToWideChar(CP_ACP, 0, p, len, NULL, 0); + path = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wlen+1)*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, p, len, path, wlen); + path[wlen] = 0; + + return path; +} + +static HRESULT Stream_LoadLocation( IStream *stm, + ShellLink::volume_info *volume, LPWSTR *path ) +{ + char *p = NULL; + LOCATION_INFO *loc; + HRESULT r; + DWORD n; + + r = Stream_ReadChunk( stm, (LPVOID*) &p ); + if( FAILED(r) ) + return r; + + loc = (LOCATION_INFO*) p; + if (loc->dwTotalSize < sizeof(LOCATION_INFO)) + { + HeapFree( GetProcessHeap(), 0, p ); + return E_FAIL; + } + + /* if there's valid local volume information, load it */ + if( loc->dwVolTableOfs && + ((loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO)) <= loc->dwTotalSize) ) + { + LOCAL_VOLUME_INFO *volume_info; + + volume_info = (LOCAL_VOLUME_INFO*) &p[loc->dwVolTableOfs]; + Stream_LoadVolume( volume_info, volume ); + } + + /* if there's a local path, load it */ + n = loc->dwLocalPathOfs; + if( n && (n < loc->dwTotalSize) ) + *path = Stream_LoadPath( &p[n], loc->dwTotalSize - n ); + + TRACE("type %d serial %08x name %s path %s\n", volume->type, + volume->serial, debugstr_w(volume->label), debugstr_w(*path)); + + HeapFree( GetProcessHeap(), 0, p ); + return S_OK; +} + +/* + * The format of the advertised shortcut info seems to be: + * + * Offset Description + * ------ ----------- + * + * 0 Length of the block (4 bytes, usually 0x314) + * 4 tag (dword) + * 8 string data in ASCII + * 8+0x104 string data in UNICODE + * + * In the original Win32 implementation the buffers are not initialized + * to zero, so data trailing the string is random garbage. + */ +static HRESULT Stream_LoadAdvertiseInfo( IStream* stm, LPWSTR *str ) +{ + DWORD size; + ULONG count; + HRESULT r; + EXP_DARWIN_LINK buffer; + + TRACE("%p\n",stm); + + r = stm->Read(&buffer.dbh.cbSize, sizeof (DWORD), &count ); + if( FAILED( r ) ) + return r; + + /* make sure that we read the size of the structure even on error */ + size = sizeof buffer - sizeof (DWORD); + if( buffer.dbh.cbSize != sizeof buffer ) + { + ERR("Ooops. This structure is not as expected...\n"); + return E_FAIL; + } + + r = stm->Read(&buffer.dbh.dwSignature, size, &count ); + if( FAILED( r ) ) + return r; + + if( count != size ) + return E_FAIL; + + TRACE("magic %08x string = %s\n", buffer.dbh.dwSignature, debugstr_w(buffer.szwDarwinID)); + + if( (buffer.dbh.dwSignature&0xffff0000) != 0xa0000000 ) + { + ERR("Unknown magic number %08x in advertised shortcut\n", buffer.dbh.dwSignature); + return E_FAIL; + } + + *str = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, + (wcslen(buffer.szwDarwinID)+1) * sizeof(WCHAR) ); + wcscpy( *str, buffer.szwDarwinID ); + + return S_OK; +} + +/************************************************************************ + * IPersistStream_Load (IPersistStream) + */ +HRESULT WINAPI ShellLink::Load(IStream *stm) +{ + LINK_HEADER hdr; + ULONG dwBytesRead; + BOOL unicode; + HRESULT r; + DWORD zero; + + TRACE("%p %p\n", this, stm); + + if (!stm) + return STG_E_INVALIDPOINTER; + + dwBytesRead = 0; + r = stm->Read(&hdr, sizeof(hdr), &dwBytesRead); + if (FAILED(r)) + return r; + + if (dwBytesRead != sizeof(hdr)) + return E_FAIL; + if (hdr.dwSize != sizeof(hdr)) + return E_FAIL; + if (!IsEqualIID(hdr.MagicGuid, CLSID_ShellLink)) + return E_FAIL; + + /* free all the old stuff */ + ILFree(pPidl); + pPidl = NULL; + memset( &volume, 0, sizeof volume ); + HeapFree(GetProcessHeap(), 0, sPath); + sPath = NULL; + HeapFree(GetProcessHeap(), 0, sDescription); + sDescription = NULL; + HeapFree(GetProcessHeap(), 0, sPathRel); + sPathRel = NULL; + HeapFree(GetProcessHeap(), 0, sWorkDir); + sWorkDir = NULL; + HeapFree(GetProcessHeap(), 0, sArgs); + sArgs = NULL; + HeapFree(GetProcessHeap(), 0, sIcoPath); + sIcoPath = NULL; + HeapFree(GetProcessHeap(), 0, sProduct); + sProduct = NULL; + HeapFree(GetProcessHeap(), 0, sComponent); + sComponent = NULL; + + wHotKey = (WORD)hdr.wHotKey; + iIcoNdx = hdr.nIcon; + FileTimeToSystemTime (&hdr.Time1, &time1); + FileTimeToSystemTime (&hdr.Time2, &time2); + FileTimeToSystemTime (&hdr.Time3, &time3); + if (TRACE_ON(shell)) + { + WCHAR sTemp[MAX_PATH]; + GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE, &time1, + NULL, sTemp, sizeof(sTemp)/sizeof(*sTemp)); + TRACE("-- time1: %s\n", debugstr_w(sTemp) ); + GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE, &time2, + NULL, sTemp, sizeof(sTemp)/sizeof(*sTemp)); + TRACE("-- time2: %s\n", debugstr_w(sTemp) ); + GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE, &time3, + NULL, sTemp, sizeof(sTemp)/sizeof(*sTemp)); + TRACE("-- time3: %s\n", debugstr_w(sTemp) ); + } + + /* load all the new stuff */ + if( hdr.dwFlags & SLDF_HAS_ID_LIST ) + { + r = ILLoadFromStream( stm, &pPidl ); + if( FAILED( r ) ) + return r; + } + pdump(pPidl); + + /* load the location information */ + if( hdr.dwFlags & SLDF_HAS_LINK_INFO ) + r = Stream_LoadLocation( stm, &volume, &sPath ); + if( FAILED( r ) ) + goto end; + + unicode = hdr.dwFlags & SLDF_UNICODE; + if( hdr.dwFlags & SLDF_HAS_NAME ) + { + r = Stream_LoadString( stm, unicode, &sDescription ); + TRACE("Description -> %s\n",debugstr_w(sDescription)); + } + if( FAILED( r ) ) + goto end; + + if( hdr.dwFlags & SLDF_HAS_RELPATH ) + { + r = Stream_LoadString( stm, unicode, &sPathRel ); + TRACE("Relative Path-> %s\n",debugstr_w(sPathRel)); + } + if( FAILED( r ) ) + goto end; + + if( hdr.dwFlags & SLDF_HAS_WORKINGDIR ) + { + r = Stream_LoadString( stm, unicode, &sWorkDir ); + TRACE("Working Dir -> %s\n",debugstr_w(sWorkDir)); + } + if( FAILED( r ) ) + goto end; + + if( hdr.dwFlags & SLDF_HAS_ARGS ) + { + r = Stream_LoadString( stm, unicode, &sArgs ); + TRACE("Working Dir -> %s\n",debugstr_w(sArgs)); + } + if( FAILED( r ) ) + goto end; + + if( hdr.dwFlags & SLDF_HAS_ICONLOCATION ) + { + r = Stream_LoadString( stm, unicode, &sIcoPath ); + TRACE("Icon file -> %s\n",debugstr_w(sIcoPath)); + } + if( FAILED( r ) ) + goto end; + +#if (NTDDI_VERSION < NTDDI_LONGHORN) + if( hdr.dwFlags & SLDF_HAS_LOGO3ID ) + { + r = Stream_LoadAdvertiseInfo( stm, &sProduct ); + TRACE("Product -> %s\n",debugstr_w(sProduct)); + } + if( FAILED( r ) ) + goto end; +#endif + + if( hdr.dwFlags & SLDF_HAS_DARWINID ) + { + r = Stream_LoadAdvertiseInfo( stm, &sComponent ); + TRACE("Component -> %s\n",debugstr_w(sComponent)); + } + if( hdr.dwFlags & SLDF_RUNAS_USER ) + { + bRunAs = TRUE; + } + else + { + bRunAs = FALSE; + } + + if( FAILED( r ) ) + goto end; + + r = stm->Read(&zero, sizeof zero, &dwBytesRead); + if( FAILED( r ) || zero || dwBytesRead != sizeof zero ) + ERR("Last word was not zero\n"); + + TRACE("OK\n"); + + pdump (pPidl); + + return S_OK; +end: + return r; +} + +/************************************************************************ + * Stream_WriteString + * + * Helper function for IPersistStream_Save. Writes a unicode string + * with terminating nul byte to a stream, preceded by the its length. + */ +static HRESULT Stream_WriteString( IStream* stm, LPCWSTR str ) +{ + USHORT len = wcslen( str ) + 1; + DWORD count; + HRESULT r; + + r = stm->Write(&len, sizeof(len), &count ); + if( FAILED( r ) ) + return r; + + len *= sizeof(WCHAR); + + r = stm->Write(str, len, &count ); + if( FAILED( r ) ) + return r; + + return S_OK; +} + +/************************************************************************ + * Stream_WriteLocationInfo + * + * Writes the location info to a stream + * + * FIXME: One day we might want to write the network volume information + * and the final path. + * Figure out how Windows deals with unicode paths here. + */ +static HRESULT Stream_WriteLocationInfo( IStream* stm, LPCWSTR path, + ShellLink::volume_info *volume ) +{ + DWORD total_size, path_size, volume_info_size, label_size, final_path_size; + LOCAL_VOLUME_INFO *vol; + LOCATION_INFO *loc; + LPSTR szLabel, szPath, szFinalPath; + ULONG count = 0; + HRESULT hr; + + TRACE("%p %s %p\n", stm, debugstr_w(path), volume); + + /* figure out the size of everything */ + label_size = WideCharToMultiByte( CP_ACP, 0, volume->label, -1, + NULL, 0, NULL, NULL ); + path_size = WideCharToMultiByte( CP_ACP, 0, path, -1, + NULL, 0, NULL, NULL ); + volume_info_size = sizeof *vol + label_size; + final_path_size = 1; + total_size = sizeof *loc + volume_info_size + path_size + final_path_size; + + /* create pointers to everything */ + loc = (LOCATION_INFO *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, total_size); + vol = (LOCAL_VOLUME_INFO*) &loc[1]; + szLabel = (LPSTR) &vol[1]; + szPath = &szLabel[label_size]; + szFinalPath = &szPath[path_size]; + + /* fill in the location information header */ + loc->dwTotalSize = total_size; + loc->dwHeaderSize = sizeof (*loc); + loc->dwFlags = 1; + loc->dwVolTableOfs = sizeof (*loc); + loc->dwLocalPathOfs = sizeof (*loc) + volume_info_size; + loc->dwNetworkVolTableOfs = 0; + loc->dwFinalPathOfs = sizeof (*loc) + volume_info_size + path_size; + + /* fill in the volume information */ + vol->dwSize = volume_info_size; + vol->dwType = volume->type; + vol->dwVolSerial = volume->serial; + vol->dwVolLabelOfs = sizeof (*vol); + + /* copy in the strings */ + WideCharToMultiByte( CP_ACP, 0, volume->label, -1, + szLabel, label_size, NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, path, -1, + szPath, path_size, NULL, NULL ); + szFinalPath[0] = 0; + + hr = stm->Write(loc, total_size, &count ); + HeapFree(GetProcessHeap(), 0, loc); + + return hr; +} + +static EXP_DARWIN_LINK* shelllink_build_darwinid( LPCWSTR string, DWORD magic ) +{ + EXP_DARWIN_LINK *buffer; + + buffer = (EXP_DARWIN_LINK *)LocalAlloc( LMEM_ZEROINIT, sizeof *buffer ); + buffer->dbh.cbSize = sizeof *buffer; + buffer->dbh.dwSignature = magic; + lstrcpynW( buffer->szwDarwinID, string, MAX_PATH ); + WideCharToMultiByte(CP_ACP, 0, string, -1, buffer->szDarwinID, MAX_PATH, NULL, NULL ); + + return buffer; +} + +static HRESULT Stream_WriteAdvertiseInfo( IStream* stm, LPCWSTR string, DWORD magic ) +{ + EXP_DARWIN_LINK *buffer; + ULONG count; + + TRACE("%p\n",stm); + + buffer = shelllink_build_darwinid( string, magic ); + + return stm->Write(buffer, buffer->dbh.cbSize, &count ); +} + +/************************************************************************ + * IPersistStream_Save (IPersistStream) + * + * FIXME: makes assumptions about byte order + */ +HRESULT WINAPI ShellLink::Save(IStream *stm, BOOL fClearDirty) +{ + LINK_HEADER header; + ULONG count; + DWORD zero; + HRESULT r; + + TRACE("%p %p %x\n", this, stm, fClearDirty); + + memset(&header, 0, sizeof(header)); + header.dwSize = sizeof(header); + header.fStartup = iShowCmd; + header.MagicGuid = CLSID_ShellLink; + + header.wHotKey = wHotKey; + header.nIcon = iIcoNdx; + header.dwFlags = SLDF_UNICODE; /* strings are in unicode */ + if( pPidl ) + header.dwFlags |= SLDF_HAS_ID_LIST; + if( sPath ) + header.dwFlags |= SLDF_HAS_LINK_INFO; + if( sDescription ) + header.dwFlags |= SLDF_HAS_NAME; + if( sWorkDir ) + header.dwFlags |= SLDF_HAS_WORKINGDIR; + if( sArgs ) + header.dwFlags |= SLDF_HAS_ARGS; + if( sIcoPath ) + header.dwFlags |= SLDF_HAS_ICONLOCATION; +#if (NTDDI_VERSION < NTDDI_LONGHORN) + if( sProduct ) + header.dwFlags |= SLDF_HAS_LOGO3ID; +#endif + if( sComponent ) + header.dwFlags |= SLDF_HAS_DARWINID; + if( bRunAs ) + header.dwFlags |= SLDF_RUNAS_USER; + + SystemTimeToFileTime ( &time1, &header.Time1 ); + SystemTimeToFileTime ( &time2, &header.Time2 ); + SystemTimeToFileTime ( &time3, &header.Time3 ); + + /* write the Shortcut header */ + r = stm->Write(&header, sizeof(header), &count ); + if( FAILED( r ) ) + { + ERR("Write failed at %d\n",__LINE__); + return r; + } + + TRACE("Writing pidl\n"); + + /* write the PIDL to the shortcut */ + if( pPidl ) + { + r = ILSaveToStream( stm, pPidl ); + if( FAILED( r ) ) + { + ERR("Failed to write PIDL at %d\n",__LINE__); + return r; + } + } + + if( sPath ) + Stream_WriteLocationInfo( stm, sPath, &volume ); + + if( sDescription ) + r = Stream_WriteString( stm, sDescription ); + + if( sPathRel ) + r = Stream_WriteString( stm, sPathRel ); + + if( sWorkDir ) + r = Stream_WriteString( stm, sWorkDir ); + + if( sArgs ) + r = Stream_WriteString( stm, sArgs ); + + if( sIcoPath ) + r = Stream_WriteString( stm, sIcoPath ); + + if( sProduct ) + r = Stream_WriteAdvertiseInfo( stm, sProduct, EXP_SZ_ICON_SIG ); + + if( sComponent ) + r = Stream_WriteAdvertiseInfo( stm, sComponent, EXP_DARWIN_ID_SIG ); + + /* the last field is a single zero dword */ + zero = 0; + r = stm->Write(&zero, sizeof zero, &count ); + + return S_OK; +} + +/************************************************************************ + * IPersistStream_GetSizeMax (IPersistStream) + */ +HRESULT WINAPI ShellLink::GetSizeMax(ULARGE_INTEGER *pcbSize) +{ + TRACE("(%p)\n", this); + + return E_NOTIMPL; +} + +static BOOL SHELL_ExistsFileW(LPCWSTR path) +{ + if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(path)) + return FALSE; + return TRUE; +} + +/************************************************************************** + * ShellLink_UpdatePath + * update absolute path in sPath using relative path in sPathRel + */ +static HRESULT ShellLink_UpdatePath(LPCWSTR sPathRel, LPCWSTR path, LPCWSTR sWorkDir, LPWSTR* psPath) +{ + if (!path || !psPath) + return E_INVALIDARG; + + if (!*psPath && sPathRel) { + WCHAR buffer[2*MAX_PATH], abs_path[2*MAX_PATH]; + LPWSTR final = NULL; + + /* first try if [directory of link file] + [relative path] finds an existing file */ + + GetFullPathNameW( path, MAX_PATH*2, buffer, &final ); + if( !final ) + final = buffer; + wcscpy(final, sPathRel); + + *abs_path = '\0'; + + if (SHELL_ExistsFileW(buffer)) { + if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final)) + wcscpy(abs_path, buffer); + } else { + /* try if [working directory] + [relative path] finds an existing file */ + if (sWorkDir) { + wcscpy(buffer, sWorkDir); + wcscpy(PathAddBackslashW(buffer), sPathRel); + + if (SHELL_ExistsFileW(buffer)) + if (!GetFullPathNameW(buffer, MAX_PATH, abs_path, &final)) + wcscpy(abs_path, buffer); + } + } + + /* FIXME: This is even not enough - not all shell links can be resolved using this algorithm. */ + if (!*abs_path) + wcscpy(abs_path, sPathRel); + + *psPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(abs_path)+1)*sizeof(WCHAR)); + if (!*psPath) + return E_OUTOFMEMORY; + + wcscpy(*psPath, abs_path); + } + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetPath(LPSTR pszFile, INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags) +{ + TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n", + this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(sPath)); + + if (sComponent || sProduct) + return S_FALSE; + + if (cchMaxPath) + pszFile[0] = 0; + if (sPath) + WideCharToMultiByte( CP_ACP, 0, sPath, -1, + pszFile, cchMaxPath, NULL, NULL); + + if (pfd) FIXME("(%p): WIN32_FIND_DATA is not yet filled.\n", this); + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetIDList(LPITEMIDLIST * ppidl) +{ + TRACE("(%p)->(ppidl=%p)\n",this, ppidl); + + if (!pPidl) + { + *ppidl = NULL; + return S_FALSE; + } + *ppidl = ILClone(pPidl); + return S_OK; +} + +HRESULT WINAPI ShellLink::SetIDList(LPCITEMIDLIST pidl) +{ + TRACE("(%p)->(pidl=%p)\n",this, pidl); + + if( pPidl ) + ILFree( pPidl ); + pPidl = ILClone( pidl ); + if( !pPidl ) + return E_FAIL; + + bDirty = TRUE; + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetDescription(LPSTR pszName,INT cchMaxName) +{ + TRACE("(%p)->(%p len=%u)\n",this, pszName, cchMaxName); + + if( cchMaxName ) + pszName[0] = 0; + if( sDescription ) + WideCharToMultiByte( CP_ACP, 0, sDescription, -1, + pszName, cchMaxName, NULL, NULL); + + return S_OK; +} + +HRESULT WINAPI ShellLink::SetDescription(LPCSTR pszName) +{ + TRACE("(%p)->(pName=%s)\n", this, pszName); + + HeapFree(GetProcessHeap(), 0, sDescription); + sDescription = NULL; + + if ( pszName ) { + sDescription = HEAP_strdupAtoW( GetProcessHeap(), 0, pszName); + if ( !sDescription ) + return E_OUTOFMEMORY; + } + bDirty = TRUE; + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetWorkingDirectory(LPSTR pszDir,INT cchMaxPath) +{ + TRACE("(%p)->(%p len=%u)\n", this, pszDir, cchMaxPath); + + if( cchMaxPath ) + pszDir[0] = 0; + if( sWorkDir ) + WideCharToMultiByte( CP_ACP, 0, sWorkDir, -1, + pszDir, cchMaxPath, NULL, NULL); + + return S_OK; +} + +HRESULT WINAPI ShellLink::SetWorkingDirectory(LPCSTR pszDir) +{ + TRACE("(%p)->(dir=%s)\n",this, pszDir); + + HeapFree(GetProcessHeap(), 0, sWorkDir); + sWorkDir = NULL; + + if ( pszDir ) { + sWorkDir = HEAP_strdupAtoW( GetProcessHeap(), 0, pszDir); + if ( !sWorkDir ) + return E_OUTOFMEMORY; + } + bDirty = TRUE; + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetArguments(LPSTR pszArgs,INT cchMaxPath) +{ + TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath); + + if( cchMaxPath ) + pszArgs[0] = 0; + if( sArgs ) + WideCharToMultiByte( CP_ACP, 0, sArgs, -1, + pszArgs, cchMaxPath, NULL, NULL); + + return S_OK; +} + +HRESULT WINAPI ShellLink::SetArguments(LPCSTR pszArgs) +{ + TRACE("(%p)->(args=%s)\n",this, pszArgs); + + HeapFree(GetProcessHeap(), 0, sArgs); + sArgs = NULL; + + if ( pszArgs ) { + sArgs = HEAP_strdupAtoW( GetProcessHeap(), 0, pszArgs); + if( !sArgs ) + return E_OUTOFMEMORY; + } + + bDirty = TRUE; + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetHotkey(WORD *pwHotkey) +{ + TRACE("(%p)->(%p)(0x%08x)\n",this, pwHotkey, wHotKey); + + *pwHotkey = wHotKey; + + return S_OK; +} + +HRESULT WINAPI ShellLink::SetHotkey(WORD wHotkey) +{ + TRACE("(%p)->(hotkey=%x)\n",this, wHotkey); + + wHotKey = wHotkey; + bDirty = TRUE; + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetShowCmd(INT *piShowCmd) +{ + TRACE("(%p)->(%p)\n",this, piShowCmd); + *piShowCmd = iShowCmd; + return S_OK; +} + +HRESULT WINAPI ShellLink::SetShowCmd(INT iShowCmd) +{ + TRACE("(%p) %d\n",this, iShowCmd); + + this->iShowCmd = iShowCmd; + bDirty = TRUE; + + return NOERROR; +} + +static HRESULT SHELL_PidlGeticonLocationA(IShellFolder* psf, LPCITEMIDLIST pidl, + LPSTR pszIconPath, int cchIconPath, int* piIcon) +{ + LPCITEMIDLIST pidlLast; + + HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*)&psf, &pidlLast); + + if (SUCCEEDED(hr)) { + CComPtr pei; + + hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_IExtractIconA, NULL, (LPVOID*)&pei); + + if (SUCCEEDED(hr)) { + hr = pei->GetIconLocation(0, pszIconPath, MAX_PATH, piIcon, NULL); + } + + psf->Release(); + } + + return hr; +} + +HRESULT WINAPI ShellLink::GetIconLocation(LPSTR pszIconPath,INT cchIconPath,INT *piIcon) +{ + TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon); + + pszIconPath[0] = 0; + *piIcon = iIcoNdx; + + if (sIcoPath) + { + WideCharToMultiByte(CP_ACP, 0, sIcoPath, -1, pszIconPath, cchIconPath, NULL, NULL); + return S_OK; + } + + if (pPidl || sPath) + { + CComPtr pdsk; + + HRESULT hr = SHGetDesktopFolder(&pdsk); + + if (SUCCEEDED(hr)) + { + /* first look for an icon using the PIDL (if present) */ + if (pPidl) + hr = SHELL_PidlGeticonLocationA(pdsk, pPidl, pszIconPath, cchIconPath, piIcon); + else + hr = E_FAIL; + + /* if we couldn't find an icon yet, look for it using the file system path */ + if (FAILED(hr) && sPath) + { + LPITEMIDLIST pidl; + + hr = pdsk->ParseDisplayName(0, NULL, sPath, NULL, &pidl, NULL); + + if (SUCCEEDED(hr)) + { + hr = SHELL_PidlGeticonLocationA(pdsk, pidl, pszIconPath, cchIconPath, piIcon); + + SHFree(pidl); + } + } + } + + return hr; + } + return S_OK; +} + +HRESULT WINAPI ShellLink::SetIconLocation(LPCSTR pszIconPath,INT iIcon) +{ + TRACE("(%p)->(path=%s iicon=%u)\n",this, pszIconPath, iIcon); + + HeapFree(GetProcessHeap(), 0, sIcoPath); + sIcoPath = NULL; + + if ( pszIconPath ) + { + sIcoPath = HEAP_strdupAtoW(GetProcessHeap(), 0, pszIconPath); + if ( !sIcoPath ) + return E_OUTOFMEMORY; + } + + iIcoNdx = iIcon; + bDirty = TRUE; + + return S_OK; +} + +HRESULT WINAPI ShellLink::SetRelativePath(LPCSTR pszPathRel, DWORD dwReserved) +{ + TRACE("(%p)->(path=%s %x)\n",this, pszPathRel, dwReserved); + + HeapFree(GetProcessHeap(), 0, sPathRel); + sPathRel = NULL; + + if ( pszPathRel ) + { + sPathRel = HEAP_strdupAtoW(GetProcessHeap(), 0, pszPathRel); + bDirty = TRUE; + } + + return ShellLink_UpdatePath(sPathRel, sPath, sWorkDir, &sPath); +} + +HRESULT WINAPI ShellLink::Resolve(HWND hwnd, DWORD fFlags) +{ + HRESULT hr = S_OK; + BOOL bSuccess; + + TRACE("(%p)->(hwnd=%p flags=%x)\n",this, hwnd, fFlags); + + /*FIXME: use IResolveShellLink interface */ + + if (!sPath && pPidl) + { + WCHAR buffer[MAX_PATH]; + + bSuccess = SHGetPathFromIDListW(pPidl, buffer); + + if (bSuccess && *buffer) + { + sPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(buffer)+1)*sizeof(WCHAR)); + + if (!sPath) + return E_OUTOFMEMORY; + + wcscpy(sPath, buffer); + + bDirty = TRUE; + } + else + hr = S_OK; /* don't report an error occurred while just caching information */ + } + + if (!sIcoPath && sPath) + { + sIcoPath = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(sPath)+1)*sizeof(WCHAR)); + + if (!sIcoPath) + return E_OUTOFMEMORY; + + wcscpy(sIcoPath, sPath); + iIcoNdx = 0; + + bDirty = TRUE; + } + + return hr; +} + +HRESULT WINAPI ShellLink::SetPath(LPCSTR pszFile) +{ + HRESULT r; + LPWSTR str; + + TRACE("(%p)->(path=%s)\n",this, pszFile); + if (pszFile == NULL) + return E_INVALIDARG; + + str = HEAP_strdupAtoW(GetProcessHeap(), 0, pszFile); + if (!str) + return E_OUTOFMEMORY; + + r = SetPath(str); + HeapFree( GetProcessHeap(), 0, str ); + + return r; +} + +HRESULT WINAPI ShellLink::GetPath(LPWSTR pszFile,INT cchMaxPath, WIN32_FIND_DATAW *pfd, DWORD fFlags) +{ + TRACE("(%p)->(pfile=%p len=%u find_data=%p flags=%u)(%s)\n", + this, pszFile, cchMaxPath, pfd, fFlags, debugstr_w(sPath)); + + if (sComponent || sProduct) + return S_FALSE; + + if (cchMaxPath) + pszFile[0] = 0; + + if (sPath) + lstrcpynW( pszFile, sPath, cchMaxPath ); + + if (pfd) FIXME("(%p): WIN32_FIND_DATA is not yet filled.\n", this); + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetDescription(LPWSTR pszName,INT cchMaxName) +{ + TRACE("(%p)->(%p len=%u)\n",this, pszName, cchMaxName); + + pszName[0] = 0; + if (sDescription) + lstrcpynW( pszName, sDescription, cchMaxName ); + + return S_OK; +} + +HRESULT WINAPI ShellLink::SetDescription(LPCWSTR pszName) +{ + TRACE("(%p)->(desc=%s)\n",this, debugstr_w(pszName)); + + HeapFree(GetProcessHeap(), 0, sDescription); + sDescription = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, + (wcslen( pszName )+1)*sizeof(WCHAR) ); + if ( !sDescription ) + return E_OUTOFMEMORY; + + wcscpy( sDescription, pszName ); + bDirty = TRUE; + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetWorkingDirectory(LPWSTR pszDir,INT cchMaxPath) +{ + TRACE("(%p)->(%p len %u)\n", this, pszDir, cchMaxPath); + + if( cchMaxPath ) + pszDir[0] = 0; + if( sWorkDir ) + lstrcpynW( pszDir, sWorkDir, cchMaxPath ); + + return S_OK; +} + +HRESULT WINAPI ShellLink::SetWorkingDirectory(LPCWSTR pszDir) +{ + TRACE("(%p)->(dir=%s)\n",this, debugstr_w(pszDir)); + + HeapFree(GetProcessHeap(), 0, sWorkDir); + sWorkDir = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, + (wcslen( pszDir )+1)*sizeof (WCHAR) ); + if ( !sWorkDir ) + return E_OUTOFMEMORY; + wcscpy( sWorkDir, pszDir ); + bDirty = TRUE; + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetArguments(LPWSTR pszArgs,INT cchMaxPath) +{ + TRACE("(%p)->(%p len=%u)\n", this, pszArgs, cchMaxPath); + + if( cchMaxPath ) + pszArgs[0] = 0; + if( sArgs ) + lstrcpynW( pszArgs, sArgs, cchMaxPath ); + + return NOERROR; +} + +HRESULT WINAPI ShellLink::SetArguments(LPCWSTR pszArgs) +{ + TRACE("(%p)->(args=%s)\n",this, debugstr_w(pszArgs)); + + HeapFree(GetProcessHeap(), 0, sArgs); + sArgs = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, + (wcslen( pszArgs )+1)*sizeof (WCHAR) ); + if ( !sArgs ) + return E_OUTOFMEMORY; + wcscpy( sArgs, pszArgs ); + bDirty = TRUE; + + return S_OK; +} + +static HRESULT SHELL_PidlGeticonLocationW(IShellFolder* psf, LPCITEMIDLIST pidl, + LPWSTR pszIconPath, int cchIconPath, int* piIcon) +{ + LPCITEMIDLIST pidlLast; + UINT wFlags; + + HRESULT hr = SHBindToParent(pidl, IID_IShellFolder, (LPVOID*)&psf, &pidlLast); + + if (SUCCEEDED(hr)) { + CComPtr pei; + + hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_IExtractIconW, NULL, (LPVOID*)&pei); + + if (SUCCEEDED(hr)) { + hr = pei->GetIconLocation(0, pszIconPath, MAX_PATH, piIcon, &wFlags); + } + + psf->Release(); + } + + return hr; +} + +HRESULT WINAPI ShellLink::GetIconLocation(LPWSTR pszIconPath,INT cchIconPath,INT *piIcon) +{ + TRACE("(%p)->(%p len=%u iicon=%p)\n", this, pszIconPath, cchIconPath, piIcon); + + pszIconPath[0] = 0; + *piIcon = iIcoNdx; + + if (sIcoPath) + { + lstrcpynW(pszIconPath, sIcoPath, cchIconPath); + return S_OK; + } + + if (pPidl || sPath) + { + CComPtr pdsk; + + HRESULT hr = SHGetDesktopFolder(&pdsk); + + if (SUCCEEDED(hr)) + { + /* first look for an icon using the PIDL (if present) */ + if (pPidl) + hr = SHELL_PidlGeticonLocationW(pdsk, pPidl, pszIconPath, cchIconPath, piIcon); + else + hr = E_FAIL; + + /* if we couldn't find an icon yet, look for it using the file system path */ + if (FAILED(hr) && sPath) + { + LPITEMIDLIST pidl; + + hr = pdsk->ParseDisplayName(0, NULL, sPath, NULL, &pidl, NULL); + + if (SUCCEEDED(hr)) + { + hr = SHELL_PidlGeticonLocationW(pdsk, pidl, pszIconPath, cchIconPath, piIcon); + + SHFree(pidl); + } + } + } + return hr; + } + return S_OK; +} + +HRESULT WINAPI ShellLink::SetIconLocation(LPCWSTR pszIconPath,INT iIcon) +{ + TRACE("(%p)->(path=%s iicon=%u)\n",this, debugstr_w(pszIconPath), iIcon); + + HeapFree(GetProcessHeap(), 0, sIcoPath); + sIcoPath = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, + (wcslen( pszIconPath )+1)*sizeof (WCHAR) ); + if ( !sIcoPath ) + return E_OUTOFMEMORY; + wcscpy( sIcoPath, pszIconPath ); + + iIcoNdx = iIcon; + bDirty = TRUE; + + return S_OK; +} + +HRESULT WINAPI ShellLink::SetRelativePath(LPCWSTR pszPathRel, DWORD dwReserved) +{ + TRACE("(%p)->(path=%s %x)\n",this, debugstr_w(pszPathRel), dwReserved); + + HeapFree(GetProcessHeap(), 0, sPathRel); + sPathRel = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, + (wcslen( pszPathRel )+1) * sizeof (WCHAR) ); + if ( !sPathRel ) + return E_OUTOFMEMORY; + wcscpy( sPathRel, pszPathRel ); + bDirty = TRUE; + + return ShellLink_UpdatePath(sPathRel, sPath, sWorkDir, &sPath); +} + +LPWSTR ShellLink::ShellLink_GetAdvertisedArg(LPCWSTR str) +{ + LPWSTR ret; + LPCWSTR p; + DWORD len; + + if( !str ) + return NULL; + + p = wcschr( str, ':' ); + if( !p ) + return NULL; + len = p - str; + ret = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR)*(len+1)); + if( !ret ) + return ret; + memcpy( ret, str, sizeof(WCHAR)*len ); + ret[len] = 0; + return ret; +} + +HRESULT ShellLink::ShellLink_SetAdvertiseInfo(LPCWSTR str) +{ + LPCWSTR szComponent = NULL, szProduct = NULL, p; + WCHAR szGuid[39]; + HRESULT r; + GUID guid; + int len; + + while( str[0] ) + { + /* each segment must start with two colons */ + if( str[0] != ':' || str[1] != ':' ) + return E_FAIL; + + /* the last segment is just two colons */ + if( !str[2] ) + break; + str += 2; + + /* there must be a colon straight after a guid */ + p = wcschr( str, ':' ); + if( !p ) + return E_FAIL; + len = p - str; + if( len != 38 ) + return E_FAIL; + + /* get the guid, and check it's validly formatted */ + memcpy( szGuid, str, sizeof(WCHAR)*len ); + szGuid[len] = 0; + r = CLSIDFromString( szGuid, &guid ); + if( r != S_OK ) + return r; + str = p + 1; + + /* match it up to a guid that we care about */ + if( IsEqualGUID( guid, SHELL32_AdvtShortcutComponent ) && !szComponent ) + szComponent = str; + else if( IsEqualGUID(guid, SHELL32_AdvtShortcutProduct ) && !szProduct ) + szProduct = str; + else + return E_FAIL; + + /* skip to the next field */ + str = wcschr( str, ':' ); + if( !str ) + return E_FAIL; + } + + /* we have to have a component for an advertised shortcut */ + if( !szComponent ) + return E_FAIL; + + sComponent = ShellLink_GetAdvertisedArg( szComponent ); + sProduct = ShellLink_GetAdvertisedArg( szProduct ); + + TRACE("Component = %s\n", debugstr_w(sComponent)); + TRACE("Product = %s\n", debugstr_w(sProduct)); + + return S_OK; +} + +static BOOL ShellLink_GetVolumeInfo(LPCWSTR path, ShellLink::volume_info *volume) +{ + const int label_sz = sizeof volume->label/sizeof volume->label[0]; + WCHAR drive[4] = { path[0], ':', '\\', 0 }; + BOOL r; + + volume->type = GetDriveTypeW(drive); + r = GetVolumeInformationW(drive, volume->label, label_sz, &volume->serial, NULL, NULL, NULL, 0); + TRACE("r = %d type %d serial %08x name %s\n", r, + volume->type, volume->serial, debugstr_w(volume->label)); + return r; +} + +HRESULT WINAPI ShellLink::SetPath(LPCWSTR pszFile) +{ + WCHAR buffer[MAX_PATH]; + LPWSTR fname, unquoted = NULL; + HRESULT hr = S_OK; + UINT len; + + TRACE("(%p)->(path=%s)\n",this, debugstr_w(pszFile)); + + if (!pszFile) return E_INVALIDARG; + + /* quotes at the ends of the string are stripped */ + len = wcslen(pszFile); + if (pszFile[0] == '"' && pszFile[len-1] == '"') + { + unquoted = strdupW(pszFile); + PathUnquoteSpacesW(unquoted); + pszFile = unquoted; + } + + /* any other quote marks are invalid */ + if (wcschr(pszFile, '"')) + { + HeapFree(GetProcessHeap(), 0, unquoted); + return S_FALSE; + } + + HeapFree(GetProcessHeap(), 0, sPath); + sPath = NULL; + + HeapFree(GetProcessHeap(), 0, sComponent); + sComponent = NULL; + + if (pPidl) + ILFree(pPidl); + pPidl = NULL; + + if (S_OK != ShellLink_SetAdvertiseInfo(pszFile )) + { + if (*pszFile == '\0') + *buffer = '\0'; + else if (!GetFullPathNameW(pszFile, MAX_PATH, buffer, &fname)) + return E_FAIL; + else if(!PathFileExistsW(buffer) && + !SearchPathW(NULL, pszFile, NULL, MAX_PATH, buffer, NULL)) + hr = S_FALSE; + + pPidl = SHSimpleIDListFromPathW(pszFile); + ShellLink_GetVolumeInfo(buffer, &volume); + + sPath = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, + (wcslen( buffer )+1) * sizeof (WCHAR) ); + if (!sPath) + return E_OUTOFMEMORY; + + wcscpy(sPath, buffer); + } + bDirty = TRUE; + HeapFree(GetProcessHeap(), 0, unquoted); + + return hr; +} + +HRESULT WINAPI ShellLink::AddDataBlock(void* pDataBlock ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI ShellLink::CopyDataBlock(DWORD dwSig, void** ppDataBlock ) +{ + LPVOID block = NULL; + HRESULT r = E_FAIL; + + TRACE("%p %08x %p\n", this, dwSig, ppDataBlock ); + + switch (dwSig) + { + case EXP_DARWIN_ID_SIG: + if (!sComponent) + break; + block = shelllink_build_darwinid( sComponent, dwSig ); + r = S_OK; + break; + case EXP_SZ_LINK_SIG: + case NT_CONSOLE_PROPS_SIG: + case NT_FE_CONSOLE_PROPS_SIG: + case EXP_SPECIAL_FOLDER_SIG: + case EXP_SZ_ICON_SIG: + FIXME("valid but unhandled datablock %08x\n", dwSig); + break; + default: + ERR("unknown datablock %08x\n", dwSig); + } + *ppDataBlock = block; + return r; +} + +HRESULT WINAPI ShellLink::RemoveDataBlock(DWORD dwSig ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI ShellLink::GetFlags(DWORD* pdwFlags ) +{ + DWORD flags = 0; + + FIXME("%p %p\n", this, pdwFlags ); + + /* FIXME: add more */ + if (sArgs) + flags |= SLDF_HAS_ARGS; + if (sComponent) + flags |= SLDF_HAS_DARWINID; + if (sIcoPath) + flags |= SLDF_HAS_ICONLOCATION; +#if (NTDDI_VERSION < NTDDI_LONGHORN) + if (sProduct) + flags |= SLDF_HAS_LOGO3ID; +#endif + if (pPidl) + flags |= SLDF_HAS_ID_LIST; + + *pdwFlags = flags; + + return S_OK; +} + +HRESULT WINAPI ShellLink::SetFlags(DWORD dwFlags ) +{ + FIXME("\n"); + return E_NOTIMPL; +} + +/************************************************************************** + * ShellLink implementation of IShellExtInit::Initialize() + * + * Loads the shelllink from the dataobject the shell is pointing to. + */ +HRESULT WINAPI ShellLink::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID ) +{ + FORMATETC format; + STGMEDIUM stgm; + UINT count; + HRESULT r = E_FAIL; + + TRACE("%p %p %p %p\n", this, pidlFolder, pdtobj, hkeyProgID ); + + if( !pdtobj ) + return r; + + format.cfFormat = CF_HDROP; + format.ptd = NULL; + format.dwAspect = DVASPECT_CONTENT; + format.lindex = -1; + format.tymed = TYMED_HGLOBAL; + + if( FAILED(pdtobj->GetData(&format, &stgm ) ) ) + return r; + + count = DragQueryFileW((HDROP)stgm.hGlobal, -1, NULL, 0 ); + if( count == 1 ) + { + LPWSTR path; + + count = DragQueryFileW((HDROP)stgm.hGlobal, 0, NULL, 0 ); + count++; + path = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, count*sizeof(WCHAR) ); + if( path ) + { + count = DragQueryFileW((HDROP)stgm.hGlobal, 0, path, count ); + r = Load(path, 0 ); + HeapFree(GetProcessHeap(), 0, path ); + } + } + ReleaseStgMedium(&stgm ); + + return r; +} + +HRESULT WINAPI ShellLink::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) +{ + WCHAR szOpen[20]; + MENUITEMINFOW mii; + int id = 1; + + TRACE("%p %p %u %u %u %u\n", this, + hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags ); + + if ( !hmenu ) + return E_INVALIDARG; + + if (!LoadStringW(shell32_hInstance, IDS_OPEN_VERB, szOpen, sizeof(szOpen)/sizeof(WCHAR))) + szOpen[0] = L'\0'; + else + szOpen[(sizeof(szOpen)/sizeof(WCHAR))-1] = L'\0'; + + memset( &mii, 0, sizeof(mii) ); + mii.cbSize = sizeof (mii); + mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; + mii.dwTypeData = (LPWSTR)szOpen; + mii.cch = wcslen( mii.dwTypeData ); + mii.wID = idCmdFirst + id++; + mii.fState = MFS_DEFAULT | MFS_ENABLED; + mii.fType = MFT_STRING; + if (!InsertMenuItemW( hmenu, indexMenu, TRUE, &mii )) + return E_FAIL; + iIdOpen = 1; + + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, id ); +} + +static LPWSTR +shelllink_get_msi_component_path( LPWSTR component ) +{ + LPWSTR path; + DWORD r, sz = 0; + + r = CommandLineFromMsiDescriptor( component, NULL, &sz ); + if (r != ERROR_SUCCESS) + return NULL; + + sz++; + path = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) ); + r = CommandLineFromMsiDescriptor( component, path, &sz ); + if (r != ERROR_SUCCESS) + { + HeapFree( GetProcessHeap(), 0, path ); + path = NULL; + } + + TRACE("returning %s\n", debugstr_w( path ) ); + + return path; +} + +HRESULT WINAPI ShellLink::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) +{ + static const WCHAR szOpen[] = { 'o','p','e','n',0 }; + static const WCHAR szCplOpen[] = { 'c','p','l','o','p','e','n',0 }; + SHELLEXECUTEINFOW sei; + HWND hwnd = NULL; /* FIXME: get using interface set from IObjectWithSite */ + LPWSTR args = NULL; + LPWSTR path = NULL; + HRESULT r; + + TRACE("%p %p\n", this, lpici ); + + if ( lpici->cbSize < sizeof (CMINVOKECOMMANDINFO) ) + return E_INVALIDARG; + + r = Resolve(hwnd, 0 ); + if ( FAILED( r ) ) + { + TRACE("failed to resolve component with error 0x%08x", r); + return r; + } + if ( sComponent ) + { + path = shelllink_get_msi_component_path( sComponent ); + if (!path) + return E_FAIL; + } + else + path = strdupW( sPath ); + + if ( lpici->cbSize == sizeof (CMINVOKECOMMANDINFOEX) && + ( lpici->fMask & CMIC_MASK_UNICODE ) ) + { + LPCMINVOKECOMMANDINFOEX iciex = (LPCMINVOKECOMMANDINFOEX) lpici; + DWORD len = 2; + + if ( sArgs ) + len += wcslen( sArgs ); + if ( iciex->lpParametersW ) + len += wcslen( iciex->lpParametersW ); + + args = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + args[0] = 0; + if ( sArgs ) + wcscat( args, sArgs ); + if ( iciex->lpParametersW ) + { + static const WCHAR space[] = { ' ', 0 }; + wcscat( args, space ); + wcscat( args, iciex->lpParametersW ); + } + } + else if (sArgs != NULL) + { + args = strdupW(sArgs); + } + + memset( &sei, 0, sizeof sei ); + sei.cbSize = sizeof sei; + sei.fMask = SEE_MASK_UNICODE | (lpici->fMask & (SEE_MASK_NOASYNC|SEE_MASK_ASYNCOK|SEE_MASK_FLAG_NO_UI)); + sei.lpFile = path; + sei.nShow = iShowCmd; + sei.lpDirectory = sWorkDir; + sei.lpParameters = args; + sei.lpVerb = szOpen; + + // HACK for ShellExecuteExW + if (!wcsstr(sPath, L".cpl")) + sei.lpVerb = szOpen; + else + sei.lpVerb = szCplOpen; + + if( ShellExecuteExW( &sei ) ) + r = S_OK; + else + r = E_FAIL; + + HeapFree( GetProcessHeap(), 0, args ); + HeapFree( GetProcessHeap(), 0, path ); + + return r; +} + +HRESULT WINAPI ShellLink::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax) +{ + FIXME("%p %lu %u %p %p %u\n", this, idCmd, uType, pwReserved, pszName, cchMax ); + + return E_NOTIMPL; +} + +INT_PTR CALLBACK ExtendedShortcutProc(HWND hwndDlg, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + HWND hDlgCtrl; + + switch(uMsg) + { + case WM_INITDIALOG: + if (lParam) + { + hDlgCtrl = GetDlgItem(hwndDlg, 14000); + SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0); + } + return TRUE; + case WM_COMMAND: + hDlgCtrl = GetDlgItem(hwndDlg, 14000); + if (LOWORD(wParam) == IDOK) + { + if ( SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED ) + EndDialog(hwndDlg, 1); + else + EndDialog(hwndDlg, 0); + } + else if (LOWORD(wParam) == IDCANCEL) + { + EndDialog(hwndDlg, -1); + } + else if (LOWORD(wParam) == 14000) + { + if ( SendMessage(hDlgCtrl, BM_GETCHECK, 0, 0) == BST_CHECKED) + SendMessage(hDlgCtrl, BM_SETCHECK, BST_UNCHECKED, 0); + else + SendMessage(hDlgCtrl, BM_SETCHECK, BST_CHECKED, 0); + } + } + return FALSE; +} + +/************************************************************************** + * SH_ShellLinkDlgProc + * + * dialog proc of the shortcut property dialog + */ + +INT_PTR CALLBACK ShellLink::SH_ShellLinkDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LPPROPSHEETPAGEW ppsp; + LPPSHNOTIFY lppsn; + ShellLink *pThis; + HWND hDlgCtrl; + WCHAR szBuffer[MAX_PATH]; + WCHAR * ptr; + int IconIndex; + INT_PTR result; + + pThis = (ShellLink *)GetWindowLongPtr(hwndDlg, DWLP_USER); + + switch(uMsg) + { + case WM_INITDIALOG: + { + ppsp = (LPPROPSHEETPAGEW)lParam; + if (ppsp == NULL) + break; + + TRACE("ShellLink_DlgProc (WM_INITDIALOG hwnd %p lParam %p ppsplParam %x)\n",hwndDlg, lParam, ppsp->lParam); + + pThis = (ShellLink *)ppsp->lParam; + SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pThis); + + TRACE("sArgs: %S sComponent: %S sDescription: %S sIcoPath: %S sPath: %S sPathRel: %S sProduct: %S sWorkDir: %S\n", pThis->sArgs, pThis->sComponent, pThis->sDescription, + pThis->sIcoPath, pThis->sPath, pThis->sPathRel, pThis->sProduct, pThis->sWorkDir); + + /* target location */ + wchar_t * wTrgtLocat; + const int ch = '\\'; + wTrgtLocat = wcsrchr(pThis->sWorkDir, ch)+1; + hDlgCtrl = GetDlgItem( hwndDlg, 14007 ); + SendMessageW(hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)wTrgtLocat); + + /* target path */ + hDlgCtrl = GetDlgItem( hwndDlg, 14009 ); + if ( hDlgCtrl != NULL ) + SendMessageW( hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)pThis->sPath ); + + /* working dir */ + hDlgCtrl = GetDlgItem( hwndDlg, 14011 ); + if ( hDlgCtrl != NULL ) + SendMessageW( hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)pThis->sWorkDir ); + + /* description */ + hDlgCtrl = GetDlgItem( hwndDlg, 14019 ); + if ( hDlgCtrl != NULL ) + SendMessageW( hDlgCtrl, WM_SETTEXT, (WPARAM)NULL, (LPARAM)pThis->sDescription ); + return TRUE; + } + + case WM_NOTIFY: + lppsn = (LPPSHNOTIFY) lParam; + if ( lppsn->hdr.code == PSN_APPLY ) + { + /* set working directory */ + hDlgCtrl = GetDlgItem( hwndDlg, 14011 ); + SendMessageW( hDlgCtrl, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szBuffer ); + pThis->SetWorkingDirectory(szBuffer); + /* set link destination */ + hDlgCtrl = GetDlgItem( hwndDlg, 14009 ); + SendMessageW( hDlgCtrl, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)szBuffer); + if ( !SHELL_ExistsFileW(szBuffer) ) + { + //FIXME load localized error msg + MessageBoxW( hwndDlg, L"file not existing", szBuffer, MB_OK ); + SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE ); + return TRUE; + } + ptr = wcsrchr(szBuffer, L'.'); + if (ptr && !_wcsnicmp(ptr, L".lnk", 4)) + { + // FIXME load localized error msg + MessageBoxW( hwndDlg, L"You cannot create a link to a shortcut", L"Error", MB_ICONERROR ); + SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE ); + return TRUE; + } + + pThis->SetPath(szBuffer); + + TRACE("This %p sLinkPath %S\n", pThis, pThis->sLinkPath); + pThis->Save(pThis->sLinkPath, TRUE ); + SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR ); + return TRUE; + } + break; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case 14020: + /// + /// FIXME + /// open target directory + /// + return TRUE; + case 14021: + if (pThis->sIcoPath) + wcscpy(szBuffer, pThis->sIcoPath); + IconIndex = pThis->iIcoNdx; + if (PickIconDlg(hwndDlg, szBuffer, MAX_PATH, &IconIndex)) + { + pThis->SetIconLocation(szBuffer, IconIndex); + /// + /// FIXME redraw icon + } + return TRUE; + case 14022: + result = DialogBoxParamW(shell32_hInstance, MAKEINTRESOURCEW(SHELL_EXTENDED_SHORTCUT_DLG), hwndDlg, ExtendedShortcutProc, (LPARAM)pThis->bRunAs); + if (result == 1 || result == 0) + { + if (pThis->bRunAs != result ) + { + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + } + + pThis->bRunAs = result; + } + return TRUE; + } + switch(HIWORD(wParam)) + { + case EN_CHANGE: + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + break; + } + break; + default: + break; + } + return FALSE; +} + +/************************************************************************** + * ShellLink_IShellPropSheetExt interface + */ + +HRESULT WINAPI ShellLink::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) +{ + HPROPSHEETPAGE hPage; + BOOL bRet; + + hPage = SH_CreatePropertySheetPage("SHELL_GENERAL_SHORTCUT_DLG", SH_ShellLinkDlgProc, (LPARAM)this, NULL); + if (hPage == NULL) + { + ERR("failed to create property sheet page\n"); + return E_FAIL; + } + + bRet = pfnAddPage(hPage, lParam); + if (bRet) + return S_OK; + else + return E_FAIL; +} + +HRESULT WINAPI ShellLink::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam) +{ + TRACE("(%p) (uPageID %u, pfnReplacePage %p lParam %p\n", this, uPageID, pfnReplacePage, lParam); + return E_NOTIMPL; +} + +HRESULT WINAPI ShellLink::SetSite(IUnknown *punk) +{ + TRACE("%p %p\n", this, punk); + + site = punk; + + return S_OK; +} + +HRESULT WINAPI ShellLink::GetSite(REFIID iid, void ** ppvSite) +{ + TRACE("%p %s %p\n", this, debugstr_guid(&iid), ppvSite ); + + if (site == NULL) + return E_FAIL; + return site->QueryInterface(iid, ppvSite ); +} + +/************************************************************************** + * IShellLink_ConstructFromFile + */ +HRESULT WINAPI IShellLink_ConstructFromFile(IUnknown *pUnkOuter, REFIID riid, LPCITEMIDLIST pidl, LPVOID *ppv) +{ + CComPtr psl; + + HRESULT hr = ShellLink::_CreatorClass::CreateInstance(NULL, riid, (void**)&psl); + + if (SUCCEEDED(hr)) + { + CComPtr ppf; + + *ppv = NULL; + + hr = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); + + if (SUCCEEDED(hr)) + { + WCHAR path[MAX_PATH]; + + if (SHGetPathFromIDListW(pidl, path)) + hr = ppf->Load(path, 0); + else + hr = E_FAIL; + + if (SUCCEEDED(hr)) + *ppv = psl.Detach(); + } + } + + return hr; +} diff --git a/reactos/dll/win32/shell32/shelllink.h b/reactos/dll/win32/shell32/shelllink.h new file mode 100644 index 00000000000..2005235cc1b --- /dev/null +++ b/reactos/dll/win32/shell32/shelllink.h @@ -0,0 +1,182 @@ +/* + * + * Copyright 1997 Marcus Meissner + * Copyright 1998 Juergen Schmied + * Copyright 2005 Mike McCormack + * 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 + * + */ + +#ifndef _SHELLLINK_H_ +#define _SHELLLINK_H_ + +class ShellLink : + public CComCoClass, + public CComObjectRootEx, + public IShellLinkA, + public IShellLinkW, + public IPersistFile, + public IPersistStream, + public IShellLinkDataList, + public IShellExtInit, + public IContextMenu, + public IObjectWithSite, + public IShellPropSheetExt +{ +public: + /* link file formats */ + + #include "pshpack1.h" + + struct volume_info + { + DWORD type; + DWORD serial; + WCHAR label[12]; /* assume 8.3 */ + }; + + #include "poppack.h" + +private: + /* data structures according to the information in the link */ + LPITEMIDLIST pPidl; + WORD wHotKey; + SYSTEMTIME time1; + SYSTEMTIME time2; + SYSTEMTIME time3; + + DWORD iShowCmd; + LPWSTR sIcoPath; + INT iIcoNdx; + LPWSTR sPath; + LPWSTR sArgs; + LPWSTR sWorkDir; + LPWSTR sDescription; + LPWSTR sPathRel; + LPWSTR sProduct; + LPWSTR sComponent; + volume_info volume; + LPWSTR sLinkPath; + BOOL bRunAs; + BOOL bDirty; + INT iIdOpen; /* id of the "Open" entry in the context menu */ + CComPtr site; +public: + ShellLink(); + ~ShellLink(); + LPWSTR ShellLink_GetAdvertisedArg(LPCWSTR str); + HRESULT ShellLink_SetAdvertiseInfo(LPCWSTR str); + static INT_PTR CALLBACK SH_ShellLinkDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + + // IPersistFile + virtual HRESULT WINAPI GetClassID(CLSID *pclsid); + virtual HRESULT WINAPI IsDirty(); + virtual HRESULT WINAPI Load(LPCOLESTR pszFileName, DWORD dwMode); + virtual HRESULT WINAPI Save(LPCOLESTR pszFileName, BOOL fRemember); + virtual HRESULT WINAPI SaveCompleted(LPCOLESTR pszFileName); + virtual HRESULT WINAPI GetCurFile(LPOLESTR *ppszFileName); + + // IPersistStream +// virtual WINAPI HRESULT GetClassID(CLSID *pclsid); +// virtual HRESULT WINAPI IsDirty(); + virtual HRESULT WINAPI Load(IStream *stm); + virtual HRESULT WINAPI Save(IStream *stm, BOOL fClearDirty); + virtual HRESULT WINAPI GetSizeMax(ULARGE_INTEGER *pcbSize); + + // IShellLinkA + virtual HRESULT WINAPI GetPath(LPSTR pszFile, INT cchMaxPath, WIN32_FIND_DATAA *pfd, DWORD fFlags); + virtual HRESULT WINAPI GetIDList(LPITEMIDLIST * ppidl); + virtual HRESULT WINAPI SetIDList(LPCITEMIDLIST pidl); + virtual HRESULT WINAPI GetDescription(LPSTR pszName,INT cchMaxName); + virtual HRESULT WINAPI SetDescription(LPCSTR pszName); + virtual HRESULT WINAPI GetWorkingDirectory(LPSTR pszDir,INT cchMaxPath); + virtual HRESULT WINAPI SetWorkingDirectory(LPCSTR pszDir); + virtual HRESULT WINAPI GetArguments(LPSTR pszArgs,INT cchMaxPath); + virtual HRESULT WINAPI SetArguments(LPCSTR pszArgs); + virtual HRESULT WINAPI GetHotkey(WORD *pwHotkey); + virtual HRESULT WINAPI SetHotkey(WORD wHotkey); + virtual HRESULT WINAPI GetShowCmd(INT *piShowCmd); + virtual HRESULT WINAPI SetShowCmd(INT iShowCmd); + virtual HRESULT WINAPI GetIconLocation(LPSTR pszIconPath,INT cchIconPath,INT *piIcon); + virtual HRESULT WINAPI SetIconLocation(LPCSTR pszIconPath,INT iIcon); + virtual HRESULT WINAPI SetRelativePath(LPCSTR pszPathRel, DWORD dwReserved); + virtual HRESULT WINAPI Resolve(HWND hwnd, DWORD fFlags); + virtual HRESULT WINAPI SetPath(LPCSTR pszFile); + + // IShellLinkW + virtual HRESULT WINAPI GetPath(LPWSTR pszFile, INT cchMaxPath, WIN32_FIND_DATAW *pfd, DWORD fFlags); +// virtual HRESULT WINAPI GetIDList(LPITEMIDLIST *ppidl); +// virtual HRESULT WINAPI SetIDList(LPCITEMIDLIST pidl); + virtual HRESULT WINAPI GetDescription(LPWSTR pszName, INT cchMaxName); + virtual HRESULT WINAPI SetDescription(LPCWSTR pszName); + virtual HRESULT WINAPI GetWorkingDirectory(LPWSTR pszDir, INT cchMaxPath); + virtual HRESULT WINAPI SetWorkingDirectory(LPCWSTR pszDir); + virtual HRESULT WINAPI GetArguments(LPWSTR pszArgs,INT cchMaxPath); + virtual HRESULT WINAPI SetArguments(LPCWSTR pszArgs); +// virtual HRESULT WINAPI GetHotkey(WORD *pwHotkey); +// virtual HRESULT WINAPI SetHotkey(WORD wHotkey); +// virtual HRESULT WINAPI GetShowCmd(INT *piShowCmd); +// virtual HRESULT WINAPI SetShowCmd(INT iShowCmd); + virtual HRESULT WINAPI GetIconLocation(LPWSTR pszIconPath,INT cchIconPath,INT *piIcon); + virtual HRESULT WINAPI SetIconLocation(LPCWSTR pszIconPath,INT iIcon); + virtual HRESULT WINAPI SetRelativePath(LPCWSTR pszPathRel, DWORD dwReserved); +// virtual HRESULT WINAPI Resolve(HWND hwnd, DWORD fFlags); + virtual HRESULT WINAPI SetPath(LPCWSTR pszFile); + + // IShellLinkDataList + virtual HRESULT WINAPI AddDataBlock(void *pDataBlock); + virtual HRESULT WINAPI CopyDataBlock(DWORD dwSig, void **ppDataBlock); + virtual HRESULT WINAPI RemoveDataBlock(DWORD dwSig); + virtual HRESULT WINAPI GetFlags(DWORD *pdwFlags); + virtual HRESULT WINAPI SetFlags(DWORD dwFlags); + + // IShellExtInit + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID); + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpici); + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax); + + // IShellPropSheetExt + virtual HRESULT WINAPI AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam); + virtual HRESULT WINAPI ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam); + + // IObjectWithSite + virtual HRESULT WINAPI SetSite(IUnknown *punk); + virtual HRESULT WINAPI GetSite(REFIID iid, void **ppvSite); + +DECLARE_REGISTRY_RESOURCEID(IDR_SHELLLINK) +DECLARE_NOT_AGGREGATABLE(ShellLink) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(ShellLink) + COM_INTERFACE_ENTRY2_IID(IID_IPersist, IPersist, IPersistFile) + COM_INTERFACE_ENTRY_IID(IID_IPersistFile, IPersistFile) + COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream) + COM_INTERFACE_ENTRY_IID(IID_IShellLinkA, IShellLinkA) + COM_INTERFACE_ENTRY_IID(IID_IShellLinkW, IShellLinkW) + COM_INTERFACE_ENTRY_IID(IID_IShellLinkDataList, IShellLinkDataList) + COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IShellPropSheetExt, IShellPropSheetExt) + COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) +END_COM_MAP() +}; + +#endif // _SHELLLINK_H_ diff --git a/reactos/dll/win32/shell32/shellole.cpp b/reactos/dll/win32/shell32/shellole.cpp new file mode 100644 index 00000000000..6d1023fba63 --- /dev/null +++ b/reactos/dll/win32/shell32/shellole.cpp @@ -0,0 +1,582 @@ +/* + * handling of SHELL32.DLL OLE-Objects + * + * Copyright 1997 Marcus Meissner + * Copyright 1998 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +extern HRESULT WINAPI IFSFolder_Constructor(IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv); + +static const WCHAR sShell32[12] = {'S','H','E','L','L','3','2','.','D','L','L','\0'}; + +/************************************************************************** + * Default ClassFactory types + */ +typedef HRESULT (CALLBACK *LPFNCREATEINSTANCE)(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObject); +HRESULT IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInst, IClassFactory **theFactory); + +/* FIXME: this should be SHLWAPI.24 since we can't yet import by ordinal */ + +DWORD WINAPI __SHGUIDToStringW (REFGUID guid, LPWSTR str) +{ + WCHAR sFormat[52] = {'{','%','0','8','l','x','-','%','0','4', + 'x','-','%','0','4','x','-','%','0','2', + 'x','%','0','2','x','-','%','0','2','x', + '%','0','2','x','%','0','2','x','%','0', + '2','x','%','0','2','x','%','0','2','x', + '}','\0'}; + + return swprintf ( str, sFormat, + guid.Data1, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7] ); + +} + +/************************************************************************* + * SHCoCreateInstance [SHELL32.102] + * + * Equivalent to CoCreateInstance. Under Windows 9x this function could sometimes + * use the shell32 built-in "mini-COM" without the need to load ole32.dll - see + * SHLoadOLE for details. + * + * Under wine if a "LoadWithoutCOM" value is present or the object resides in + * shell32.dll the function will load the object manually without the help of ole32 + * + * NOTES + * exported by ordinal + * + * SEE ALSO + * CoCreateInstace, SHLoadOLE + */ +HRESULT WINAPI SHCoCreateInstance( + LPCWSTR aclsid, + const CLSID *clsid, + LPUNKNOWN pUnkOuter, + REFIID refiid, + LPVOID *ppv) +{ + DWORD hres; + CLSID iid; + const CLSID * myclsid = clsid; + WCHAR sKeyName[MAX_PATH]; + const WCHAR sCLSID[7] = {'C','L','S','I','D','\\','\0'}; + WCHAR sClassID[60]; + const WCHAR sInProcServer32[16] ={'\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2','\0'}; + const WCHAR sLoadWithoutCOM[15] ={'L','o','a','d','W','i','t','h','o','u','t','C','O','M','\0'}; + WCHAR sDllPath[MAX_PATH]; + HKEY hKey; + DWORD dwSize; + BOOLEAN bLoadFromShell32 = FALSE; + BOOLEAN bLoadWithoutCOM = FALSE; + CComPtr pcf; + + if(!ppv) return E_POINTER; + *ppv=NULL; + + /* if the clsid is a string, convert it */ + if (!clsid) + { + if (!aclsid) return REGDB_E_CLASSNOTREG; + CLSIDFromString((LPOLESTR)aclsid, &iid); + myclsid = &iid; + } + + TRACE("(%p,%s,unk:%p,%s,%p)\n", + aclsid, shdebugstr_guid(myclsid), pUnkOuter, shdebugstr_guid(&refiid), ppv); + + /* we look up the dll path in the registry */ + __SHGUIDToStringW(*myclsid, sClassID); + wcscpy(sKeyName, sCLSID); + wcscat(sKeyName, sClassID); + wcscat(sKeyName, sInProcServer32); + + if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_CLASSES_ROOT, sKeyName, 0, KEY_READ, &hKey)) { + dwSize = sizeof(sDllPath); + SHQueryValueExW(hKey, NULL, 0,0, sDllPath, &dwSize ); + + /* if a special registry key is set, we load a shell extension without help of OLE32 */ + bLoadWithoutCOM = (ERROR_SUCCESS == SHQueryValueExW(hKey, sLoadWithoutCOM, 0, 0, 0, 0)); + + /* if the com object is inside shell32, omit use of ole32 */ + bLoadFromShell32 = (0==lstrcmpiW( PathFindFileNameW(sDllPath), sShell32)); + + RegCloseKey (hKey); + } else { + /* since we can't find it in the registry we try internally */ + bLoadFromShell32 = TRUE; + } + + TRACE("WithoutCom=%u FromShell=%u\n", bLoadWithoutCOM, bLoadFromShell32); + + /* now we create an instance */ + if (bLoadFromShell32) { + if (! SUCCEEDED(DllGetClassObject(*myclsid, IID_IClassFactory, (LPVOID*)&pcf))) { + ERR("LoadFromShell failed for CLSID=%s\n", shdebugstr_guid(myclsid)); + } + } else if (bLoadWithoutCOM) { + + /* load an external dll without ole32 */ + HINSTANCE hLibrary; + typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); + DllGetClassObjectFunc DllGetClassObject; + + if ((hLibrary = LoadLibraryExW(sDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) { + ERR("couldn't load InprocServer32 dll %s\n", debugstr_w(sDllPath)); + hres = E_ACCESSDENIED; + goto end; + } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) { + ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(sDllPath)); + FreeLibrary( hLibrary ); + hres = E_ACCESSDENIED; + goto end; + } else if (! SUCCEEDED(hres = DllGetClassObject(*myclsid, IID_IClassFactory, (LPVOID*)&pcf))) { + TRACE("GetClassObject failed 0x%08x\n", hres); + goto end; + } + + } else { + + /* load an external dll in the usual way */ + hres = CoCreateInstance(*myclsid, pUnkOuter, CLSCTX_INPROC_SERVER, refiid, ppv); + goto end; + } + + /* here we should have a ClassFactory */ + if (!pcf) return E_ACCESSDENIED; + + hres = pcf->CreateInstance(pUnkOuter, refiid, ppv); +end: + if(hres!=S_OK) + { + ERR("failed (0x%08x) to create CLSID:%s IID:%s\n", + hres, shdebugstr_guid(myclsid), shdebugstr_guid(&refiid)); + ERR("class not found in registry\n"); + } + + TRACE("-- instance: %p\n",*ppv); + return hres; +} + +/************************************************************************* + * SHCLSIDFromString [SHELL32.147] + * + * Under Windows 9x this was an ANSI version of CLSIDFromString. It also allowed + * to avoid dependency on ole32.dll (see SHLoadOLE for details). + * + * Under Windows NT/2000/XP this is equivalent to CLSIDFromString + * + * NOTES + * exported by ordinal + * + * SEE ALSO + * CLSIDFromString, SHLoadOLE + */ +DWORD WINAPI SHCLSIDFromStringA (LPCSTR clsid, CLSID *id) +{ + WCHAR buffer[40]; + TRACE("(%p(%s) %p)\n", clsid, clsid, id); + if (!MultiByteToWideChar( CP_ACP, 0, clsid, -1, buffer, sizeof(buffer)/sizeof(WCHAR) )) + return CO_E_CLASSSTRING; + return CLSIDFromString( buffer, id ); +} + +DWORD WINAPI SHCLSIDFromStringW (LPCWSTR clsid, CLSID *id) +{ + TRACE("(%p(%s) %p)\n", clsid, debugstr_w(clsid), id); + return CLSIDFromString((LPWSTR)clsid, id); +} + +EXTERN_C DWORD WINAPI SHCLSIDFromStringAW (LPCVOID clsid, CLSID *id) +{ + if (SHELL_OsIsUnicode()) + return SHCLSIDFromStringW ((LPCWSTR)clsid, id); + return SHCLSIDFromStringA ((LPCSTR)clsid, id); +} + +/************************************************************************* + * SHGetMalloc [SHELL32.@] + * + * Equivalent to CoGetMalloc(MEMCTX_TASK, ...). Under Windows 9x this function + * could use the shell32 built-in "mini-COM" without the need to load ole32.dll - + * see SHLoadOLE for details. + * + * PARAMS + * lpmal [O] Destination for IMalloc interface. + * + * RETURNS + * Success: S_OK. lpmal contains the shells IMalloc interface. + * Failure. An HRESULT error code. + * + * SEE ALSO + * CoGetMalloc, SHLoadOLE + */ +HRESULT WINAPI SHGetMalloc(LPMALLOC *lpmal) +{ + TRACE("(%p)\n", lpmal); + return CoGetMalloc(MEMCTX_TASK, lpmal); +} + +/************************************************************************* + * SHAlloc [SHELL32.196] + * + * Equivalent to CoTaskMemAlloc. Under Windows 9x this function could use + * the shell32 built-in "mini-COM" without the need to load ole32.dll - + * see SHLoadOLE for details. + * + * NOTES + * exported by ordinal + * + * SEE ALSO + * CoTaskMemAlloc, SHLoadOLE + */ +LPVOID WINAPI SHAlloc(DWORD len) +{ + LPVOID ret; + + ret = CoTaskMemAlloc(len); + TRACE("%u bytes at %p\n",len, ret); + return ret; +} + +/************************************************************************* + * SHFree [SHELL32.195] + * + * Equivalent to CoTaskMemFree. Under Windows 9x this function could use + * the shell32 built-in "mini-COM" without the need to load ole32.dll - + * see SHLoadOLE for details. + * + * NOTES + * exported by ordinal + * + * SEE ALSO + * CoTaskMemFree, SHLoadOLE + */ +void WINAPI SHFree(LPVOID pv) +{ + TRACE("%p\n",pv); + CoTaskMemFree(pv); +} + +/************************************************************************* + * SHGetDesktopFolder [SHELL32.@] + */ +HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf) +{ + HRESULT hres = S_OK; + TRACE("\n"); + + if(!psf) return E_INVALIDARG; + *psf = NULL; + hres = CDesktopFolder::_CreatorClass::CreateInstance(NULL, IID_IShellFolder, (void**)psf); + + TRACE("-- %p->(%p)\n",psf, *psf); + return hres; +} +/************************************************************************** + * Default ClassFactory Implementation + * + * SHCreateDefClassObject + * + * NOTES + * Helper function for dlls without their own classfactory. + * A generic classfactory is returned. + * When the CreateInstance of the cf is called the callback is executed. + */ + +class IDefClFImpl : + public CComObjectRootEx, + public IClassFactory +{ +private: + CLSID *rclsid; + LPFNCREATEINSTANCE lpfnCI; + const IID *riidInst; + LONG *pcRefDll; /* pointer to refcounter in external dll (ugrrr...) */ +public: + IDefClFImpl(); + HRESULT Initialize(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInstx); + + // IClassFactory + virtual HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject); + virtual HRESULT WINAPI LockServer(BOOL fLock); + +BEGIN_COM_MAP(IDefClFImpl) + COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory) +END_COM_MAP() +}; + +IDefClFImpl::IDefClFImpl() +{ + lpfnCI = NULL; + riidInst = NULL; + pcRefDll = NULL; + rclsid = NULL; +} + +HRESULT IDefClFImpl::Initialize(LPFNCREATEINSTANCE lpfnCIx, PLONG pcRefDllx, const IID *riidInstx) +{ + lpfnCI = lpfnCIx; + riidInst = riidInstx; + pcRefDll = pcRefDllx; + + if (pcRefDll) + InterlockedIncrement(pcRefDll); + + TRACE("(%p)%s\n", this, shdebugstr_guid(riidInst)); + return S_OK; +} + +/****************************************************************************** + * IDefClF_fnCreateInstance + */ +HRESULT WINAPI IDefClFImpl::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObject) +{ + TRACE("%p->(%p,%s,%p)\n", this, pUnkOuter, shdebugstr_guid(&riid), ppvObject); + + *ppvObject = NULL; + + if (riidInst == NULL || IsEqualCLSID(riid, *riidInst) || IsEqualCLSID(riid, IID_IUnknown)) + { + return lpfnCI(pUnkOuter, riid, ppvObject); + } + + ERR("unknown IID requested %s\n", shdebugstr_guid(&riid)); + return E_NOINTERFACE; +} + +/****************************************************************************** + * IDefClF_fnLockServer + */ +HRESULT WINAPI IDefClFImpl::LockServer(BOOL fLock) +{ + TRACE("%p->(0x%x), not implemented\n", this, fLock); + return E_NOTIMPL; +} + +/************************************************************************** + * IDefClF_fnConstructor + */ + +HRESULT IDefClF_fnConstructor(LPFNCREATEINSTANCE lpfnCI, PLONG pcRefDll, const IID *riidInst, IClassFactory **theFactory) +{ + CComObject *theClassObject; + CComPtr result; + HRESULT hResult; + + if (theFactory == NULL) + return E_POINTER; + *theFactory = NULL; + ATLTRY (theClassObject = new CComObject); + if (theClassObject == NULL) + return E_OUTOFMEMORY; + hResult = theClassObject->QueryInterface (IID_IClassFactory, (void **)&result); + if (FAILED (hResult)) + { + delete theClassObject; + return hResult; + } + hResult = theClassObject->Initialize (lpfnCI, pcRefDll, riidInst); + if (FAILED (hResult)) + return hResult; + *theFactory = result.Detach (); + return S_OK; +} + +/****************************************************************************** + * SHCreateDefClassObject [SHELL32.70] + */ +HRESULT WINAPI SHCreateDefClassObject( + REFIID riid, + LPVOID* ppv, + LPFNCREATEINSTANCE lpfnCI, /* [in] create instance callback entry */ + LPDWORD pcRefDll, /* [in/out] ref count of the dll */ + REFIID riidInst) /* [in] optional interface to the instance */ +{ + IClassFactory *pcf; + HRESULT hResult; + + TRACE("%s %p %p %p %s\n", shdebugstr_guid(&riid), ppv, lpfnCI, pcRefDll, shdebugstr_guid(&riidInst)); + + if (!IsEqualCLSID(riid, IID_IClassFactory)) + return E_NOINTERFACE; + hResult = IDefClF_fnConstructor(lpfnCI, (PLONG)pcRefDll, &riidInst, &pcf); + if (FAILED(hResult)) + return hResult; + *ppv = pcf; + return NOERROR; +} + +/************************************************************************* + * DragAcceptFiles [SHELL32.@] + */ +void WINAPI DragAcceptFiles(HWND hWnd, BOOL b) +{ + LONG exstyle; + + if( !IsWindow(hWnd) ) return; + exstyle = GetWindowLongPtrA(hWnd,GWL_EXSTYLE); + if (b) + exstyle |= WS_EX_ACCEPTFILES; + else + exstyle &= ~WS_EX_ACCEPTFILES; + SetWindowLongPtrA(hWnd,GWL_EXSTYLE,exstyle); +} + +/************************************************************************* + * DragFinish [SHELL32.@] + */ +void WINAPI DragFinish(HDROP h) +{ + TRACE("\n"); + GlobalFree((HGLOBAL)h); +} + +/************************************************************************* + * DragQueryPoint [SHELL32.@] + */ +BOOL WINAPI DragQueryPoint(HDROP hDrop, POINT *p) +{ + DROPFILES *lpDropFileStruct; + BOOL bRet; + + TRACE("\n"); + + lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop); + + *p = lpDropFileStruct->pt; + bRet = lpDropFileStruct->fNC; + + GlobalUnlock(hDrop); + return bRet; +} + +/************************************************************************* + * DragQueryFileA [SHELL32.@] + * DragQueryFile [SHELL32.@] + */ +UINT WINAPI DragQueryFileA( + HDROP hDrop, + UINT lFile, + LPSTR lpszFile, + UINT lLength) +{ + LPSTR lpDrop; + UINT i = 0; + DROPFILES *lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop); + + TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszFile,lLength); + + if(!lpDropFileStruct) goto end; + + lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->pFiles; + + if(lpDropFileStruct->fWide) { + LPWSTR lpszFileW = NULL; + + if(lpszFile) { + lpszFileW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, lLength*sizeof(WCHAR)); + if(lpszFileW == NULL) { + goto end; + } + } + i = DragQueryFileW(hDrop, lFile, lpszFileW, lLength); + + if(lpszFileW) { + WideCharToMultiByte(CP_ACP, 0, lpszFileW, -1, lpszFile, lLength, 0, NULL); + HeapFree(GetProcessHeap(), 0, lpszFileW); + } + goto end; + } + + while (i++ < lFile) + { + while (*lpDrop++); /* skip filename */ + if (!*lpDrop) + { + i = (lFile == 0xFFFFFFFF) ? i : 0; + goto end; + } + } + + i = strlen(lpDrop); + if (!lpszFile ) goto end; /* needed buffer size */ + lstrcpynA (lpszFile, lpDrop, lLength); +end: + GlobalUnlock(hDrop); + return i; +} + +/************************************************************************* + * DragQueryFileW [SHELL32.@] + */ +UINT WINAPI DragQueryFileW( + HDROP hDrop, + UINT lFile, + LPWSTR lpszwFile, + UINT lLength) +{ + LPWSTR lpwDrop; + UINT i = 0; + DROPFILES *lpDropFileStruct = (DROPFILES *) GlobalLock(hDrop); + + TRACE("(%p, %x, %p, %u)\n", hDrop,lFile,lpszwFile,lLength); + + if(!lpDropFileStruct) goto end; + + lpwDrop = (LPWSTR) ((LPSTR)lpDropFileStruct + lpDropFileStruct->pFiles); + + if(lpDropFileStruct->fWide == FALSE) { + LPSTR lpszFileA = NULL; + + if(lpszwFile) { + lpszFileA = (LPSTR)HeapAlloc(GetProcessHeap(), 0, lLength); + if(lpszFileA == NULL) { + goto end; + } + } + i = DragQueryFileA(hDrop, lFile, lpszFileA, lLength); + + if(lpszFileA) { + MultiByteToWideChar(CP_ACP, 0, lpszFileA, -1, lpszwFile, lLength); + HeapFree(GetProcessHeap(), 0, lpszFileA); + } + goto end; + } + + i = 0; + while (i++ < lFile) + { + while (*lpwDrop++); /* skip filename */ + if (!*lpwDrop) + { + i = (lFile == 0xFFFFFFFF) ? i : 0; + goto end; + } + } + + i = wcslen(lpwDrop); + if ( !lpszwFile) goto end; /* needed buffer size */ + lstrcpynW (lpszwFile, lpwDrop, lLength); +end: + GlobalUnlock(hDrop); + return i; +} diff --git a/reactos/dll/win32/shell32/shellord.cpp b/reactos/dll/win32/shell32/shellord.cpp new file mode 100644 index 00000000000..44fa887c7d6 --- /dev/null +++ b/reactos/dll/win32/shell32/shellord.cpp @@ -0,0 +1,2288 @@ +/* + * The parameters of many functions changes between different OS versions + * (NT uses Unicode strings, 95 uses ASCII strings) + * + * Copyright 1997 Marcus Meissner + * 1998 Jürgen 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); +WINE_DECLARE_DEBUG_CHANNEL(pidl); + +/* FIXME: !!! move flags to header file !!! */ +/* dwFlags */ +#define MRUF_STRING_LIST 0 /* list will contain strings */ +#define MRUF_BINARY_LIST 1 /* list will contain binary data */ +#define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */ + +EXTERN_C HANDLE WINAPI CreateMRUListA(LPCREATEMRULISTA lpcml); +EXTERN_C INT WINAPI AddMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData); +EXTERN_C INT WINAPI FindMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum); +EXTERN_C INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize); + + +/* Get a function pointer from a DLL handle */ +#define GET_FUNC(func, funcType, module, name, fail) \ + do { \ + if (!func) { \ + if (!SHELL32_h##module && !(SHELL32_h##module = LoadLibraryA(#module ".dll"))) return fail; \ + func = (funcType)GetProcAddress(SHELL32_h##module, name); \ + if (!func) return fail; \ + } \ + } while (0) + +/* Function pointers for GET_FUNC macro */ +static HMODULE SHELL32_hshlwapi=NULL; + + +/************************************************************************* + * ParseFieldA [internal] + * + * copies a field from a ',' delimited string + * + * first field is nField = 1 + */ +DWORD WINAPI ParseFieldA( + LPCSTR src, + DWORD nField, + LPSTR dst, + DWORD len) +{ + WARN("(%s,0x%08x,%p,%d) semi-stub.\n",debugstr_a(src),nField,dst,len); + + if (!src || !src[0] || !dst || !len) + return 0; + + /* skip n fields delimited by ',' */ + while (nField > 1) + { + if (*src=='\0') return FALSE; + if (*(src++)==',') nField--; + } + + /* copy part till the next ',' to dst */ + while ( *src!='\0' && *src!=',' && (len--)>0 ) *(dst++)=*(src++); + + /* finalize the string */ + *dst=0x0; + + return TRUE; +} + +/************************************************************************* + * ParseFieldW [internal] + * + * copies a field from a ',' delimited string + * + * first field is nField = 1 + */ +DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len) +{ + WARN("(%s,0x%08x,%p,%d) semi-stub.\n", debugstr_w(src), nField, dst, len); + + if (!src || !src[0] || !dst || !len) + return 0; + + /* skip n fields delimited by ',' */ + while (nField > 1) + { + if (*src == 0x0) return FALSE; + if (*src++ == ',') nField--; + } + + /* copy part till the next ',' to dst */ + while ( *src != 0x0 && *src != ',' && (len--)>0 ) *(dst++) = *(src++); + + /* finalize the string */ + *dst = 0x0; + + return TRUE; +} + +/************************************************************************* + * ParseField [SHELL32.58] + */ +EXTERN_C DWORD WINAPI ParseFieldAW(LPCVOID src, DWORD nField, LPVOID dst, DWORD len) +{ + if (SHELL_OsIsUnicode()) + return ParseFieldW((LPCWSTR)src, nField, (LPWSTR)dst, len); + return ParseFieldA((LPCSTR)src, nField, (LPSTR)dst, len); +} + +/************************************************************************* + * GetFileNameFromBrowse [SHELL32.63] + * + */ +BOOL WINAPI GetFileNameFromBrowse( + HWND hwndOwner, + LPWSTR lpstrFile, + UINT nMaxFile, + LPCWSTR lpstrInitialDir, + LPCWSTR lpstrDefExt, + LPCWSTR lpstrFilter, + LPCWSTR lpstrTitle) +{ +typedef BOOL (WINAPI *GetOpenFileNameProc)(OPENFILENAMEW *ofn); + HMODULE hmodule; + GetOpenFileNameProc pGetOpenFileNameW; + OPENFILENAMEW ofn; + BOOL ret; + + TRACE("%p, %s, %d, %s, %s, %s, %s)\n", + hwndOwner, debugstr_w(lpstrFile), nMaxFile, lpstrInitialDir, lpstrDefExt, + lpstrFilter, lpstrTitle); + + hmodule = LoadLibraryW(L"comdlg32.dll"); + if(!hmodule) return FALSE; + pGetOpenFileNameW = (GetOpenFileNameProc)GetProcAddress(hmodule, "GetOpenFileNameW"); + if(!pGetOpenFileNameW) + { + FreeLibrary(hmodule); + return FALSE; + } + + memset(&ofn, 0, sizeof(ofn)); + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwndOwner; + ofn.lpstrFilter = lpstrFilter; + ofn.lpstrFile = lpstrFile; + ofn.nMaxFile = nMaxFile; + ofn.lpstrInitialDir = lpstrInitialDir; + ofn.lpstrTitle = lpstrTitle; + ofn.lpstrDefExt = lpstrDefExt; + ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; + ret = pGetOpenFileNameW(&ofn); + + FreeLibrary(hmodule); + return ret; +} + +/************************************************************************* + * SHGetSetSettings [SHELL32.68] + */ +EXTERN_C VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet) +{ + if(bSet) + { + FIXME("%p 0x%08x TRUE\n", lpss, dwMask); + } + else + { + SHGetSettings((LPSHELLFLAGSTATE)lpss,dwMask); + } +} + +/************************************************************************* + * SHGetSettings [SHELL32.@] + * + * NOTES + * the registry path are for win98 (tested) + * and possibly are the same in nt40 + * + */ +EXTERN_C VOID WINAPI SHGetSettings(LPSHELLFLAGSTATE lpsfs, DWORD dwMask) +{ + HKEY hKey; + DWORD dwData; + DWORD dwDataSize = sizeof (DWORD); + + TRACE("(%p 0x%08x)\n",lpsfs,dwMask); + + if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", + 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) + return; + + if ( (SSF_SHOWEXTENSIONS & dwMask) && !RegQueryValueExA(hKey, "HideFileExt", 0, 0, (LPBYTE)&dwData, &dwDataSize)) + lpsfs->fShowExtensions = ((dwData == 0) ? 0 : 1); + + if ( (SSF_SHOWINFOTIP & dwMask) && !RegQueryValueExA(hKey, "ShowInfoTip", 0, 0, (LPBYTE)&dwData, &dwDataSize)) + lpsfs->fShowInfoTip = ((dwData == 0) ? 0 : 1); + + if ( (SSF_DONTPRETTYPATH & dwMask) && !RegQueryValueExA(hKey, "DontPrettyPath", 0, 0, (LPBYTE)&dwData, &dwDataSize)) + lpsfs->fDontPrettyPath = ((dwData == 0) ? 0 : 1); + + if ( (SSF_HIDEICONS & dwMask) && !RegQueryValueExA(hKey, "HideIcons", 0, 0, (LPBYTE)&dwData, &dwDataSize)) + lpsfs->fHideIcons = ((dwData == 0) ? 0 : 1); + + if ( (SSF_MAPNETDRVBUTTON & dwMask) && !RegQueryValueExA(hKey, "MapNetDrvBtn", 0, 0, (LPBYTE)&dwData, &dwDataSize)) + lpsfs->fMapNetDrvBtn = ((dwData == 0) ? 0 : 1); + + if ( (SSF_SHOWATTRIBCOL & dwMask) && !RegQueryValueExA(hKey, "ShowAttribCol", 0, 0, (LPBYTE)&dwData, &dwDataSize)) + lpsfs->fShowAttribCol = ((dwData == 0) ? 0 : 1); + + if (((SSF_SHOWALLOBJECTS | SSF_SHOWSYSFILES) & dwMask) && !RegQueryValueExA(hKey, "Hidden", 0, 0, (LPBYTE)&dwData, &dwDataSize)) + { if (dwData == 0) + { if (SSF_SHOWALLOBJECTS & dwMask) lpsfs->fShowAllObjects = 0; + if (SSF_SHOWSYSFILES & dwMask) lpsfs->fShowSysFiles = 0; + } + else if (dwData == 1) + { if (SSF_SHOWALLOBJECTS & dwMask) lpsfs->fShowAllObjects = 1; + if (SSF_SHOWSYSFILES & dwMask) lpsfs->fShowSysFiles = 0; + } + else if (dwData == 2) + { if (SSF_SHOWALLOBJECTS & dwMask) lpsfs->fShowAllObjects = 0; + if (SSF_SHOWSYSFILES & dwMask) lpsfs->fShowSysFiles = 1; + } + } + RegCloseKey (hKey); + + TRACE("-- 0x%04x\n", *(WORD*)lpsfs); +} + +/************************************************************************* + * SHShellFolderView_Message [SHELL32.73] + * + * Send a message to an explorer cabinet window. + * + * PARAMS + * hwndCabinet [I] The window containing the shellview to communicate with + * dwMessage [I] The SFVM message to send + * dwParam [I] Message parameter + * + * RETURNS + * fixme. + * + * NOTES + * Message SFVM_REARRANGE = 1 + * + * This message gets sent when a column gets clicked to instruct the + * shell view to re-sort the item list. dwParam identifies the column + * that was clicked. + */ +LRESULT WINAPI SHShellFolderView_Message( + HWND hwndCabinet, + UINT uMessage, + LPARAM lParam) +{ + FIXME("%p %08x %08lx stub\n",hwndCabinet, uMessage, lParam); + return 0; +} + +/************************************************************************* + * RegisterShellHook [SHELL32.181] + * + * Register a shell hook. + * + * PARAMS + * hwnd [I] Window handle + * dwType [I] Type of hook. + * + * NOTES + * Exported by ordinal + */ +BOOL WINAPI RegisterShellHook( + HWND hWnd, + DWORD dwType) +{ + FIXME("(%p,0x%08x):stub.\n",hWnd, dwType); + return TRUE; +} + +/************************************************************************* + * ShellMessageBoxW [SHELL32.182] + * + * See ShellMessageBoxA. + * + * NOTE: + * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW + * because we can't forward to it in the .spec file since it's exported by + * ordinal. If you change the implementation here please update the code in + * shlwapi as well. + */ +EXTERN_C int WINAPI ShellMessageBoxW( + HINSTANCE hInstance, + HWND hWnd, + LPCWSTR lpText, + LPCWSTR lpCaption, + UINT uType, + ...) +{ + WCHAR szText[100],szTitle[100]; + LPCWSTR pszText = szText, pszTitle = szTitle; + LPWSTR pszTemp; + va_list args; + int ret; + + va_start(args, uType); + /* wvsprintfA(buf,fmt, args); */ + + TRACE("(%p,%p,%p,%p,%08x)\n", + hInstance,hWnd,lpText,lpCaption,uType); + + if (IS_INTRESOURCE(lpCaption)) + LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0])); + else + pszTitle = lpCaption; + + if (IS_INTRESOURCE(lpText)) + LoadStringW(hInstance, LOWORD(lpText), szText, sizeof(szText)/sizeof(szText[0])); + else + pszText = lpText; + + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, + pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args); + + va_end(args); + + ret = MessageBoxW(hWnd,pszTemp,pszTitle,uType); + LocalFree(pszTemp); + return ret; +} + +/************************************************************************* + * ShellMessageBoxA [SHELL32.183] + * + * Format and output an error message. + * + * PARAMS + * hInstance [I] Instance handle of message creator + * hWnd [I] Window handle of message creator + * lpText [I] Resource Id of title or LPSTR + * lpCaption [I] Resource Id of title or LPSTR + * uType [I] Type of error message + * + * RETURNS + * A return value from MessageBoxA(). + * + * NOTES + * Exported by ordinal + */ +EXTERN_C int WINAPI ShellMessageBoxA( + HINSTANCE hInstance, + HWND hWnd, + LPCSTR lpText, + LPCSTR lpCaption, + UINT uType, + ...) +{ + char szText[100],szTitle[100]; + LPCSTR pszText = szText, pszTitle = szTitle; + LPSTR pszTemp; + va_list args; + int ret; + + va_start(args, uType); + /* wvsprintfA(buf,fmt, args); */ + + TRACE("(%p,%p,%p,%p,%08x)\n", + hInstance,hWnd,lpText,lpCaption,uType); + + if (IS_INTRESOURCE(lpCaption)) + LoadStringA(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)); + else + pszTitle = lpCaption; + + if (IS_INTRESOURCE(lpText)) + LoadStringA(hInstance, LOWORD(lpText), szText, sizeof(szText)); + else + pszText = lpText; + + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, + pszText, 0, 0, (LPSTR)&pszTemp, 0, &args); + + va_end(args); + + ret = MessageBoxA(hWnd,pszTemp,pszTitle,uType); + LocalFree(pszTemp); + return ret; +} + +/************************************************************************* + * SHRegisterDragDrop [SHELL32.86] + * + * Probably equivalent to RegisterDragDrop but under Windows 95 it could use the + * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE + * for details. Under Windows 98 this function initializes the true OLE when called + * the first time, on XP always returns E_OUTOFMEMORY and it got removed from Vista. + * + * + * NOTES + * exported by ordinal + * + * SEE ALSO + * RegisterDragDrop, SHLoadOLE + */ +HRESULT WINAPI SHRegisterDragDrop( + HWND hWnd, + LPDROPTARGET pDropTarget) +{ + FIXME("(%p,%p):stub.\n", hWnd, pDropTarget); + return RegisterDragDrop(hWnd, pDropTarget); +} + +/************************************************************************* + * SHRevokeDragDrop [SHELL32.87] + * + * Probably equivalent to RevokeDragDrop but under Windows 9x it could use the + * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE + * for details. Function removed from Windows Vista. + * + * NOTES + * exported by ordinal + * + * SEE ALSO + * RevokeDragDrop, SHLoadOLE + */ +HRESULT WINAPI SHRevokeDragDrop(HWND hWnd) +{ + FIXME("(%p):stub.\n",hWnd); + return RevokeDragDrop(hWnd); +} + +/************************************************************************* + * SHDoDragDrop [SHELL32.88] + * + * Probably equivalent to DoDragDrop but under Windows 9x it could use the + * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE + * for details + * + * NOTES + * exported by ordinal + * + * SEE ALSO + * DoDragDrop, SHLoadOLE + */ +HRESULT WINAPI SHDoDragDrop( + HWND hWnd, + LPDATAOBJECT lpDataObject, + LPDROPSOURCE lpDropSource, + DWORD dwOKEffect, + LPDWORD pdwEffect) +{ + FIXME("(%p %p %p 0x%08x %p):stub.\n", + hWnd, lpDataObject, lpDropSource, dwOKEffect, pdwEffect); + return DoDragDrop(lpDataObject, lpDropSource, dwOKEffect, pdwEffect); +} + +/************************************************************************* + * ArrangeWindows [SHELL32.184] + * + */ +WORD WINAPI ArrangeWindows( + HWND hwndParent, + DWORD dwReserved, + LPCRECT lpRect, + WORD cKids, + CONST HWND * lpKids) +{ + /* Unimplemented in WinXP SP3 */ + TRACE("(%p 0x%08x %p 0x%04x %p):stub.\n", + hwndParent, dwReserved, lpRect, cKids, lpKids); + return 0; +} + +/************************************************************************* + * SignalFileOpen [SHELL32.103] + * + * NOTES + * exported by ordinal + */ +EXTERN_C BOOL WINAPI +SignalFileOpen (LPCITEMIDLIST pidl) +{ + FIXME("(0x%08x):stub.\n", pidl); + + return 0; +} + +/************************************************************************* + * SHADD_get_policy - helper function for SHAddToRecentDocs + * + * PARAMETERS + * policy [IN] policy name (null termed string) to find + * type [OUT] ptr to DWORD to receive type + * buffer [OUT] ptr to area to hold data retrieved + * len [IN/OUT] ptr to DWORD holding size of buffer and getting + * length filled + * + * RETURNS + * result of the SHQueryValueEx call + */ +static INT SHADD_get_policy(LPCSTR policy, LPDWORD type, LPVOID buffer, LPDWORD len) +{ + HKEY Policy_basekey; + INT ret; + + /* Get the key for the policies location in the registry + */ + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", + 0, KEY_READ, &Policy_basekey)) { + + if (RegOpenKeyExA(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", + 0, KEY_READ, &Policy_basekey)) { + TRACE("No Explorer Policies location exists. Policy wanted=%s\n", + policy); + *len = 0; + return ERROR_FILE_NOT_FOUND; + } + } + + /* Retrieve the data if it exists + */ + ret = SHQueryValueExA(Policy_basekey, policy, 0, type, buffer, len); + RegCloseKey(Policy_basekey); + return ret; +} + + +/************************************************************************* + * SHADD_compare_mru - helper function for SHAddToRecentDocs + * + * PARAMETERS + * data1 [IN] data being looked for + * data2 [IN] data in MRU + * cbdata [IN] length from FindMRUData call (not used) + * + * RETURNS + * position within MRU list that data was added. + */ +static INT CALLBACK SHADD_compare_mru(LPCVOID data1, LPCVOID data2, DWORD cbData) +{ + return lstrcmpiA((LPCSTR)data1, (LPCSTR)data2); +} + +/************************************************************************* + * SHADD_create_add_mru_data - helper function for SHAddToRecentDocs + * + * PARAMETERS + * mruhandle [IN] handle for created MRU list + * doc_name [IN] null termed pure doc name + * new_lnk_name [IN] null termed path and file name for .lnk file + * buffer [IN/OUT] 2048 byte area to construct MRU data + * len [OUT] ptr to int to receive space used in buffer + * + * RETURNS + * position within MRU list that data was added. + */ +static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR new_lnk_name, + LPSTR buffer, INT *len) +{ + LPSTR ptr; + INT wlen; + + /*FIXME: Document: + * RecentDocs MRU data structure seems to be: + * +0h document file name w/ terminating 0h + * +nh short int w/ size of remaining + * +n+2h 02h 30h, or 01h 30h, or 00h 30h - unknown + * +n+4h 10 bytes zeros - unknown + * +n+eh shortcut file name w/ terminating 0h + * +n+e+nh 3 zero bytes - unknown + */ + + /* Create the MRU data structure for "RecentDocs" + */ + ptr = buffer; + lstrcpyA(ptr, doc_name); + ptr += (lstrlenA(buffer) + 1); + wlen= lstrlenA(new_lnk_name) + 1 + 12; + *((short int*)ptr) = wlen; + ptr += 2; /* step past the length */ + *(ptr++) = 0x30; /* unknown reason */ + *(ptr++) = 0; /* unknown, but can be 0x00, 0x01, 0x02 */ + memset(ptr, 0, 10); + ptr += 10; + lstrcpyA(ptr, new_lnk_name); + ptr += (lstrlenA(new_lnk_name) + 1); + memset(ptr, 0, 3); + ptr += 3; + *len = ptr - buffer; + + /* Add the new entry into the MRU list + */ + return AddMRUData(mruhandle, buffer, *len); +} + +/************************************************************************* + * SHAddToRecentDocs [SHELL32.@] + * + * Modify (add/clear) Shell's list of recently used documents. + * + * PARAMETERS + * uFlags [IN] SHARD_PATHA, SHARD_PATHW or SHARD_PIDL + * pv [IN] string or pidl, NULL clears the list + * + * NOTES + * exported by name + * + * FIXME + * convert to unicode + */ +void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv) +{ +/* If list is a string list lpfnCompare has the following prototype + * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2) + * for binary lists the prototype is + * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData) + * where cbData is the no. of bytes to compare. + * Need to check what return value means identical - 0? + */ + + + UINT olderrormode; + HKEY HCUbasekey; + CHAR doc_name[MAX_PATH]; + CHAR link_dir[MAX_PATH]; + CHAR new_lnk_filepath[MAX_PATH]; + CHAR new_lnk_name[MAX_PATH]; + CHAR * ext; + CComPtr ppM; + LPITEMIDLIST pidl; + HWND hwnd = 0; /* FIXME: get real window handle */ + INT ret; + DWORD data[64], datalen, type; + + TRACE("%04x %p\n", uFlags, pv); + + /*FIXME: Document: + * RecentDocs MRU data structure seems to be: + * +0h document file name w/ terminating 0h + * +nh short int w/ size of remaining + * +n+2h 02h 30h, or 01h 30h, or 00h 30h - unknown + * +n+4h 10 bytes zeros - unknown + * +n+eh shortcut file name w/ terminating 0h + * +n+e+nh 3 zero bytes - unknown + */ + + /* See if we need to do anything. + */ + datalen = 64; + ret=SHADD_get_policy( "NoRecentDocsHistory", &type, data, &datalen); + if ((ret > 0) && (ret != ERROR_FILE_NOT_FOUND)) { + ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret); + return; + } + if (ret == ERROR_SUCCESS) { + if (!( (type == REG_DWORD) || + ((type == REG_BINARY) && (datalen == 4)) )) { + ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n", + type, datalen); + return; + } + + TRACE("policy value for NoRecentDocsHistory = %08x\n", data[0]); + /* now test the actual policy value */ + if ( data[0] != 0) + return; + } + + /* Open key to where the necessary info is + */ + /* FIXME: This should be done during DLL PROCESS_ATTACH (or THREAD_ATTACH) + * and the close should be done during the _DETACH. The resulting + * key is stored in the DLL global data. + */ + if (RegCreateKeyExA(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", + 0, 0, 0, KEY_READ, 0, &HCUbasekey, 0)) { + ERR("Failed to create 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'\n"); + return; + } + + /* Get path to user's "Recent" directory + */ + if(SUCCEEDED(SHGetMalloc(&ppM))) { + if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_RECENT, + &pidl))) { + SHGetPathFromIDListA(pidl, link_dir); + ppM->Free(pidl); + } + else { + /* serious issues */ + link_dir[0] = 0; + ERR("serious issues 1\n"); + } + } + else { + /* serious issues */ + link_dir[0] = 0; + ERR("serious issues 2\n"); + } + TRACE("Users Recent dir %s\n", link_dir); + + /* If no input, then go clear the lists */ + if (!pv) { + /* clear user's Recent dir + */ + + /* FIXME: delete all files in "link_dir" + * + * while( more files ) { + * lstrcpyA(old_lnk_name, link_dir); + * PathAppendA(old_lnk_name, filenam); + * DeleteFileA(old_lnk_name); + * } + */ + FIXME("should delete all files in %s\\\n", link_dir); + + /* clear MRU list + */ + /* MS Bug ?? v4.72.3612.1700 of shell32 does the delete against + * HKEY_LOCAL_MACHINE version of ...CurrentVersion\Explorer + * and naturally it fails w/ rc=2. It should do it against + * HKEY_CURRENT_USER which is where it is stored, and where + * the MRU routines expect it!!!! + */ + RegDeleteKeyA(HCUbasekey, "RecentDocs"); + RegCloseKey(HCUbasekey); + return; + } + + /* Have data to add, the jobs to be done: + * 1. Add document to MRU list in registry "HKCU\Software\ + * Microsoft\Windows\CurrentVersion\Explorer\RecentDocs". + * 2. Add shortcut to document in the user's Recent directory + * (CSIDL_RECENT). + * 3. Add shortcut to Start menu's Documents submenu. + */ + + /* Get the pure document name from the input + */ + switch (uFlags) + { + case SHARD_PIDL: + SHGetPathFromIDListA((LPCITEMIDLIST)pv, doc_name); + break; + + case SHARD_PATHA: + lstrcpynA(doc_name, (LPCSTR)pv, MAX_PATH); + break; + + case SHARD_PATHW: + WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pv, -1, doc_name, MAX_PATH, NULL, NULL); + break; + + default: + FIXME("Unsupported flags: %u\n", uFlags); + return; + } + + TRACE("full document name %s\n", debugstr_a(doc_name)); + + /* check if file is a shortcut */ + ext = strrchr(doc_name, '.'); + if (!lstrcmpiA(ext, ".lnk")) + { + CComPtr ShellLink; + IShellLink_ConstructFromFile(NULL, IID_IShellLinkA, (LPCITEMIDLIST)SHSimpleIDListFromPathA(doc_name), (LPVOID*)&ShellLink); + ShellLink->GetPath(doc_name, MAX_PATH, NULL, 0); + } + + ext = strrchr(doc_name, '.'); + if (!lstrcmpiA(ext, ".exe")) + { + /* executables are not added */ + return; + } + + PathStripPathA(doc_name); + TRACE("stripped document name %s\n", debugstr_a(doc_name)); + + + /* *** JOB 1: Update registry for ...\Explorer\RecentDocs list *** */ + + { /* on input needs: + * doc_name - pure file-spec, no path + * link_dir - path to the user's Recent directory + * HCUbasekey - key of ...Windows\CurrentVersion\Explorer" node + * creates: + * new_lnk_name- pure file-spec, no path for new .lnk file + * new_lnk_filepath + * - path and file name of new .lnk file + */ + CREATEMRULISTA mymru; + HANDLE mruhandle; + INT len, pos, bufused, err; + INT i; + DWORD attr; + CHAR buffer[2048]; + CHAR *ptr; + CHAR old_lnk_name[MAX_PATH]; + short int slen; + + mymru.cbSize = sizeof(CREATEMRULISTA); + mymru.nMaxItems = 15; + mymru.dwFlags = MRUF_BINARY_LIST | MRUF_DELAYED_SAVE; + mymru.hKey = HCUbasekey; + mymru.lpszSubKey = "RecentDocs"; + mymru.lpfnCompare = (PROC)SHADD_compare_mru; + mruhandle = CreateMRUListA(&mymru); + if (!mruhandle) { + /* MRU failed */ + ERR("MRU processing failed, handle zero\n"); + RegCloseKey(HCUbasekey); + return; + } + len = lstrlenA(doc_name); + pos = FindMRUData(mruhandle, doc_name, len, 0); + + /* Now get the MRU entry that will be replaced + * and delete the .lnk file for it + */ + if ((bufused = EnumMRUListA(mruhandle, (pos == -1) ? 14 : pos, + buffer, 2048)) != -1) { + ptr = buffer; + ptr += (lstrlenA(buffer) + 1); + slen = *((short int*)ptr); + ptr += 2; /* skip the length area */ + if (bufused >= slen + (ptr-buffer)) { + /* buffer size looks good */ + ptr += 12; /* get to string */ + len = bufused - (ptr-buffer); /* get length of buf remaining */ + if ((lstrlenA(ptr) > 0) && (lstrlenA(ptr) <= len-1)) { + /* appears to be good string */ + lstrcpyA(old_lnk_name, link_dir); + PathAppendA(old_lnk_name, ptr); + if (!DeleteFileA(old_lnk_name)) { + if ((attr = GetFileAttributesA(old_lnk_name)) == INVALID_FILE_ATTRIBUTES) { + if ((err = GetLastError()) != ERROR_FILE_NOT_FOUND) { + ERR("Delete for %s failed, err=%d, attr=%08x\n", + old_lnk_name, err, attr); + } + else { + TRACE("old .lnk file %s did not exist\n", + old_lnk_name); + } + } + else { + ERR("Delete for %s failed, attr=%08x\n", + old_lnk_name, attr); + } + } + else { + TRACE("deleted old .lnk file %s\n", old_lnk_name); + } + } + } + } + + /* Create usable .lnk file name for the "Recent" directory + */ + wsprintfA(new_lnk_name, "%s.lnk", doc_name); + lstrcpyA(new_lnk_filepath, link_dir); + PathAppendA(new_lnk_filepath, new_lnk_name); + i = 1; + olderrormode = SetErrorMode(SEM_FAILCRITICALERRORS); + while (GetFileAttributesA(new_lnk_filepath) != INVALID_FILE_ATTRIBUTES) { + i++; + wsprintfA(new_lnk_name, "%s (%u).lnk", doc_name, i); + lstrcpyA(new_lnk_filepath, link_dir); + PathAppendA(new_lnk_filepath, new_lnk_name); + } + SetErrorMode(olderrormode); + TRACE("new shortcut will be %s\n", new_lnk_filepath); + + /* Now add the new MRU entry and data + */ + pos = SHADD_create_add_mru_data(mruhandle, doc_name, new_lnk_name, + buffer, &len); + FreeMRUList(mruhandle); + TRACE("Updated MRU list, new doc is position %d\n", pos); + } + + /* *** JOB 2: Create shortcut in user's "Recent" directory *** */ + + { /* on input needs: + * doc_name - pure file-spec, no path + * new_lnk_filepath + * - path and file name of new .lnk file + * uFlags[in] - flags on call to SHAddToRecentDocs + * pv[in] - document path/pidl on call to SHAddToRecentDocs + */ + CComPtr psl; + CComPtr pPf; + HRESULT hres; + CHAR desc[MAX_PATH]; + WCHAR widelink[MAX_PATH]; + + CoInitialize(0); + + hres = CoCreateInstance(CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + IID_IShellLinkA, + (void **)&psl); + if(SUCCEEDED(hres)) { + + hres = psl->QueryInterface(IID_IPersistFile, + (LPVOID *)&pPf); + if(FAILED(hres)) { + /* bombed */ + ERR("failed QueryInterface for IPersistFile %08x\n", hres); + goto fail; + } + + /* Set the document path or pidl */ + if (uFlags == SHARD_PIDL) { + hres = psl->SetIDList((LPCITEMIDLIST) pv); + } else { + hres = psl->SetPath((LPCSTR) pv); + } + if(FAILED(hres)) { + /* bombed */ + ERR("failed Set{IDList|Path} %08x\n", hres); + goto fail; + } + + lstrcpyA(desc, "Shortcut to "); + lstrcatA(desc, doc_name); + hres = psl->SetDescription(desc); + if(FAILED(hres)) { + /* bombed */ + ERR("failed SetDescription %08x\n", hres); + goto fail; + } + + MultiByteToWideChar(CP_ACP, 0, new_lnk_filepath, -1, + widelink, MAX_PATH); + /* create the short cut */ + hres = pPf->Save(widelink, TRUE); + if(FAILED(hres)) { + /* bombed */ + ERR("failed IPersistFile::Save %08x\n", hres); + goto fail; + } + hres = pPf->SaveCompleted(widelink); + TRACE("shortcut %s has been created, result=%08x\n", + new_lnk_filepath, hres); + } + else { + ERR("CoCreateInstance failed, hres=%08x\n", hres); + } + } + + fail: + CoUninitialize(); + + /* all done */ + RegCloseKey(HCUbasekey); + return; +} + +/************************************************************************* + * SHCreateShellFolderViewEx [SHELL32.174] + * + * Create a new instance of the default Shell folder view object. + * + * RETURNS + * Success: S_OK + * Failure: error value + * + * NOTES + * see IShellFolder::CreateViewObject + */ +HRESULT WINAPI SHCreateShellFolderViewEx( + LPCSFV psvcbi, /* [in] shelltemplate struct */ + IShellView **ppv) /* [out] IShellView pointer */ +{ + IShellView * psf; + HRESULT hRes; + + TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n", + psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback, + psvcbi->fvm, psvcbi->psvOuter); + + hRes = IShellView_Constructor(psvcbi->pshf, &psf); + if (FAILED(hRes)) + return hRes; + + if (!psf) + return E_OUTOFMEMORY; + + psf->AddRef(); + hRes = psf->QueryInterface(IID_IShellView, (LPVOID *)ppv); + psf->Release(); + + return hRes; +} +/************************************************************************* + * SHWinHelp [SHELL32.127] + * + */ +EXTERN_C HRESULT WINAPI SHWinHelp (DWORD v, DWORD w, DWORD x, DWORD z) +{ FIXME("0x%08x 0x%08x 0x%08x 0x%08x stub\n",v,w,x,z); + return 0; +} +/************************************************************************* + * SHRunControlPanel [SHELL32.161] + * + */ +EXTERN_C BOOL WINAPI SHRunControlPanel (LPCWSTR lpcszCmdLine, HWND hwndMsgParent) +{ + FIXME("0x%08x 0x%08x stub\n",lpcszCmdLine,hwndMsgParent); + return 0; +} + +static LPUNKNOWN SHELL32_IExplorerInterface=0; +/************************************************************************* + * SHSetInstanceExplorer [SHELL32.176] + * + * NOTES + * Sets the interface + */ +VOID WINAPI SHSetInstanceExplorer (LPUNKNOWN lpUnknown) +{ TRACE("%p\n", lpUnknown); + SHELL32_IExplorerInterface = lpUnknown; +} +/************************************************************************* + * SHGetInstanceExplorer [SHELL32.@] + * + * NOTES + * gets the interface pointer of the explorer and a reference + */ +HRESULT WINAPI SHGetInstanceExplorer (IUnknown **lpUnknown) +{ TRACE("%p\n", lpUnknown); + + *lpUnknown = SHELL32_IExplorerInterface; + + if (!SHELL32_IExplorerInterface) + return E_FAIL; + + SHELL32_IExplorerInterface->AddRef(); + return NOERROR; +} +/************************************************************************* + * SHFreeUnusedLibraries [SHELL32.123] + * + * Probably equivalent to CoFreeUnusedLibraries but under Windows 9x it could use + * the shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE + * for details + * + * NOTES + * exported by ordinal + * + * SEE ALSO + * CoFreeUnusedLibraries, SHLoadOLE + */ +void WINAPI SHFreeUnusedLibraries (void) +{ + FIXME("stub\n"); + CoFreeUnusedLibraries(); +} +/************************************************************************* + * DAD_AutoScroll [SHELL32.129] + * + */ +BOOL WINAPI DAD_AutoScroll(HWND hwnd, AUTO_SCROLL_DATA *samples, const POINT * pt) +{ + FIXME("hwnd = %p %p %p\n",hwnd,samples,pt); + return 0; +} +/************************************************************************* + * DAD_DragEnter [SHELL32.130] + * + */ +BOOL WINAPI DAD_DragEnter(HWND hwnd) +{ + FIXME("hwnd = %p\n",hwnd); + return FALSE; +} +/************************************************************************* + * DAD_DragEnterEx [SHELL32.131] + * + */ +BOOL WINAPI DAD_DragEnterEx(HWND hwnd, POINT p) +{ + FIXME("hwnd = %p (%d,%d)\n",hwnd,p.x,p.y); + return FALSE; +} +/************************************************************************* + * DAD_DragMove [SHELL32.134] + * + */ +BOOL WINAPI DAD_DragMove(POINT p) +{ + FIXME("(%d,%d)\n",p.x,p.y); + return FALSE; +} +/************************************************************************* + * DAD_DragLeave [SHELL32.132] + * + */ +BOOL WINAPI DAD_DragLeave(VOID) +{ + FIXME("\n"); + return FALSE; +} +/************************************************************************* + * DAD_SetDragImage [SHELL32.136] + * + * NOTES + * exported by name + */ +BOOL WINAPI DAD_SetDragImage( + HIMAGELIST himlTrack, + LPPOINT lppt) +{ + FIXME("%p %p stub\n",himlTrack, lppt); + return 0; +} +/************************************************************************* + * DAD_ShowDragImage [SHELL32.137] + * + * NOTES + * exported by name + */ +BOOL WINAPI DAD_ShowDragImage(BOOL bShow) +{ + FIXME("0x%08x stub\n",bShow); + return 0; +} + +static const WCHAR szwCabLocation[] = { + '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','\\', + 'C','a','b','i','n','e','t','S','t','a','t','e',0 +}; + +static const WCHAR szwSettings[] = { 'S','e','t','t','i','n','g','s',0 }; + +/************************************************************************* + * ReadCabinetState [SHELL32.651] NT 4.0 + * + */ +BOOL WINAPI ReadCabinetState(CABINETSTATE *cs, int length) +{ + HKEY hkey = 0; + DWORD type, r; + + TRACE("%p %d\n", cs, length); + + if( (cs == NULL) || (length < (int)sizeof(*cs)) ) + return FALSE; + + r = RegOpenKeyW( HKEY_CURRENT_USER, szwCabLocation, &hkey ); + if( r == ERROR_SUCCESS ) + { + type = REG_BINARY; + r = RegQueryValueExW( hkey, szwSettings, + NULL, &type, (LPBYTE)cs, (LPDWORD)&length ); + RegCloseKey( hkey ); + + } + + /* if we can't read from the registry, create default values */ + if ( (r != ERROR_SUCCESS) || (cs->cLength < sizeof(*cs)) || + (cs->cLength != length) ) + { + ERR("Initializing shell cabinet settings\n"); + memset(cs, 0, sizeof(*cs)); + cs->cLength = sizeof(*cs); + cs->nVersion = 2; + cs->fFullPathTitle = FALSE; + cs->fSaveLocalView = TRUE; + cs->fNotShell = FALSE; + cs->fSimpleDefault = TRUE; + cs->fDontShowDescBar = FALSE; + cs->fNewWindowMode = FALSE; + cs->fShowCompColor = FALSE; + cs->fDontPrettyNames = FALSE; + cs->fAdminsCreateCommonGroups = TRUE; + cs->fMenuEnumFilter = 96; + } + + return TRUE; +} + +/************************************************************************* + * WriteCabinetState [SHELL32.652] NT 4.0 + * + */ +BOOL WINAPI WriteCabinetState(CABINETSTATE *cs) +{ + DWORD r; + HKEY hkey = 0; + + TRACE("%p\n",cs); + + if( cs == NULL ) + return FALSE; + + r = RegCreateKeyExW( HKEY_CURRENT_USER, szwCabLocation, 0, + NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL); + if( r == ERROR_SUCCESS ) + { + r = RegSetValueExW( hkey, szwSettings, 0, + REG_BINARY, (LPBYTE) cs, cs->cLength); + + RegCloseKey( hkey ); + } + + return (r==ERROR_SUCCESS); +} + +/************************************************************************* + * FileIconInit [SHELL32.660] + * + */ +BOOL WINAPI FileIconInit(BOOL bFullInit) +{ FIXME("(%s)\n", bFullInit ? "true" : "false"); + return 0; +} + +/************************************************************************* + * IsUserAnAdmin [SHELL32.680] NT 4.0 + * + * Checks whether the current user is a member of the Administrators group. + * + * PARAMS + * None + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI IsUserAnAdmin(VOID) +{ + SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY}; + HANDLE hToken; + DWORD dwSize; + PTOKEN_GROUPS lpGroups; + PSID lpSid; + DWORD i; + BOOL bResult = FALSE; + + TRACE("\n"); + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) + { + return FALSE; + } + + if (!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize)) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + CloseHandle(hToken); + return FALSE; + } + } + + lpGroups = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), 0, dwSize); + if (lpGroups == NULL) + { + CloseHandle(hToken); + return FALSE; + } + + if (!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize)) + { + HeapFree(GetProcessHeap(), 0, lpGroups); + CloseHandle(hToken); + return FALSE; + } + + CloseHandle(hToken); + + if (!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, + &lpSid)) + { + HeapFree(GetProcessHeap(), 0, lpGroups); + return FALSE; + } + + for (i = 0; i < lpGroups->GroupCount; i++) + { + if (EqualSid(lpSid, lpGroups->Groups[i].Sid)) + { + bResult = TRUE; + break; + } + } + + FreeSid(lpSid); + HeapFree(GetProcessHeap(), 0, lpGroups); + return bResult; +} + +/************************************************************************* + * SHAllocShared [SHELL32.520] + * + * See shlwapi.SHAllocShared + */ +HANDLE WINAPI SHAllocShared(LPVOID lpvData, DWORD dwSize, DWORD dwProcId) +{ + typedef HANDLE (WINAPI *SHAllocSharedProc)(LPCVOID, DWORD, DWORD); + static SHAllocSharedProc pSHAllocShared; + + GET_FUNC(pSHAllocShared, SHAllocSharedProc, shlwapi, (char*)7, NULL); + return pSHAllocShared(lpvData, dwSize, dwProcId); +} + +/************************************************************************* + * SHLockShared [SHELL32.521] + * + * See shlwapi.SHLockShared + */ +LPVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId) +{ + typedef HANDLE (WINAPI *SHLockSharedProc)(HANDLE, DWORD); + static SHLockSharedProc pSHLockShared; + + GET_FUNC(pSHLockShared, SHLockSharedProc, shlwapi, (char*)8, NULL); + return pSHLockShared(hShared, dwProcId); +} + +/************************************************************************* + * SHUnlockShared [SHELL32.522] + * + * See shlwapi.SHUnlockShared + */ +BOOL WINAPI SHUnlockShared(LPVOID lpView) +{ + typedef HANDLE (WINAPI *SHUnlockSharedProc)(LPCVOID); + static SHUnlockSharedProc pSHUnlockShared; + + GET_FUNC(pSHUnlockShared, SHUnlockSharedProc, shlwapi, (char*)9, FALSE); + return pSHUnlockShared(lpView) != NULL; +} + +/************************************************************************* + * SHFreeShared [SHELL32.523] + * + * See shlwapi.SHFreeShared + */ +BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId) +{ + typedef HANDLE (WINAPI *SHFreeSharedProc)(HANDLE, DWORD); + static SHFreeSharedProc pSHFreeShared; + + GET_FUNC(pSHFreeShared, SHFreeSharedProc, shlwapi, (char*)10, FALSE); + return pSHFreeShared(hShared, dwProcId) != NULL; +} + +/************************************************************************* + * SetAppStartingCursor [SHELL32.99] + */ +EXTERN_C HRESULT WINAPI SetAppStartingCursor(HWND u, DWORD v) +{ FIXME("hwnd=%p 0x%04x stub\n",u,v ); + return 0; +} + +/************************************************************************* + * SHLoadOLE [SHELL32.151] + * + * To reduce the memory usage of Windows 95, its shell32 contained an + * internal implementation of a part of COM (see e.g. SHGetMalloc, SHCoCreateInstance, + * SHRegisterDragDrop etc.) that allowed to use in-process STA objects without + * the need to load OLE32.DLL. If OLE32.DLL was already loaded, the SH* function + * would just call the Co* functions. + * + * The SHLoadOLE was called when OLE32.DLL was being loaded to transfer all the + * information from the shell32 "mini-COM" to ole32.dll. + * + * See http://blogs.msdn.com/oldnewthing/archive/2004/07/05/173226.aspx for a + * detailed description. + * + * Under wine ole32.dll is always loaded as it is imported by shlwapi.dll which is + * imported by shell32 and no "mini-COM" is used (except for the "LoadWithoutCOM" + * hack in SHCoCreateInstance) + */ +HRESULT WINAPI SHLoadOLE(LPARAM lParam) +{ FIXME("0x%08lx stub\n",lParam); + return S_OK; +} +/************************************************************************* + * DriveType [SHELL32.64] + * + */ +EXTERN_C int WINAPI DriveType(int DriveType) +{ + WCHAR root[] = L"A:\\"; + root[0] = L'A' + DriveType; + return GetDriveTypeW(root); +} + +/************************************************************************* + * InvalidateDriveType [SHELL32.65] + * Unimplemented in XP SP3 + */ +EXTERN_C int WINAPI InvalidateDriveType(int u) +{ + TRACE("0x%08x stub\n",u); + return 0; +} + +/************************************************************************* + * SHAbortInvokeCommand [SHELL32.198] + * + */ +EXTERN_C HRESULT WINAPI SHAbortInvokeCommand(void) +{ FIXME("stub\n"); + return 1; +} + +/************************************************************************* + * SHOutOfMemoryMessageBox [SHELL32.126] + * + */ +int WINAPI SHOutOfMemoryMessageBox( + HWND hwndOwner, + LPCSTR lpCaption, + UINT uType) +{ + FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType); + return 0; +} + +/************************************************************************* + * SHFlushClipboard [SHELL32.121] + * + */ +EXTERN_C HRESULT WINAPI SHFlushClipboard(void) +{ + return OleFlushClipboard(); +} + +/************************************************************************* + * SHWaitForFileToOpen [SHELL32.97] + * + */ +BOOL WINAPI SHWaitForFileToOpen( + LPCITEMIDLIST pidl, + DWORD dwFlags, + DWORD dwTimeout) +{ + FIXME("%p 0x%08x 0x%08x stub\n", pidl, dwFlags, dwTimeout); + return 0; +} + +/************************************************************************ + * RLBuildListOfPaths [SHELL32.146] + * + * NOTES + * builds a DPA + */ +EXTERN_C DWORD WINAPI RLBuildListOfPaths (void) +{ FIXME("stub\n"); + return 0; +} + +/************************************************************************ + * SHValidateUNC [SHELL32.173] + * + */ +EXTERN_C BOOL WINAPI SHValidateUNC (HWND hwndOwner, LPWSTR pszFile, UINT fConnect) +{ + FIXME("0x%08x 0x%08x 0x%08x stub\n",hwndOwner,pszFile,fConnect); + return 0; +} + +/************************************************************************ + * DoEnvironmentSubstA [SHELL32.@] + * + * Replace %KEYWORD% in the str with the value of variable KEYWORD + * from environment. If it is not found the %KEYWORD% is left + * intact. If the buffer is too small, str is not modified. + * + * PARAMS + * pszString [I] '\0' terminated string with %keyword%. + * [O] '\0' terminated string with %keyword% substituted. + * cchString [I] size of str. + * + * RETURNS + * cchString length in the HIWORD; + * TRUE in LOWORD if subst was successful and FALSE in other case + */ +EXTERN_C DWORD WINAPI DoEnvironmentSubstA(LPSTR pszString, UINT cchString) +{ + LPSTR dst; + BOOL res = FALSE; + FIXME("(%s, %d) stub\n", debugstr_a(pszString), cchString); + if (pszString == NULL) /* Really return 0? */ + return 0; + if ((dst = (LPSTR)HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(CHAR)))) + { + DWORD num = ExpandEnvironmentStringsA(pszString, dst, cchString); + if (num && num < cchString) /* dest buffer is too small */ + { + res = TRUE; + memcpy(pszString, dst, num); + } + HeapFree(GetProcessHeap(), 0, dst); + } + return MAKELONG(res,cchString); /* Always cchString? */ +} + +/************************************************************************ + * DoEnvironmentSubstW [SHELL32.@] + * + * See DoEnvironmentSubstA. + */ +EXTERN_C DWORD WINAPI DoEnvironmentSubstW(LPWSTR pszString, UINT cchString) +{ + LPWSTR dst; + BOOL res = FALSE; + FIXME("(%s, %d): stub\n", debugstr_w(pszString), cchString); + if ((dst = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(WCHAR)))) + { + DWORD num = ExpandEnvironmentStringsW(pszString, dst, cchString); + if (num) + { + res = TRUE; + wcscpy(pszString, dst); + } + HeapFree(GetProcessHeap(), 0, dst); + } + + return MAKELONG(res,cchString); +} + +/************************************************************************ + * DoEnvironmentSubst [SHELL32.53] + * + * See DoEnvironmentSubstA. + */ +DWORD WINAPI DoEnvironmentSubstAW(LPVOID x, UINT y) +{ + if (SHELL_OsIsUnicode()) + return DoEnvironmentSubstW((LPWSTR)x, y); + return DoEnvironmentSubstA((LPSTR)x, y); +} + +/************************************************************************* + * GUIDFromStringA [SHELL32.703] + */ +BOOL WINAPI GUIDFromStringA(LPCSTR str, LPGUID guid) +{ + TRACE("GUIDFromStringA() stub\n"); + return FALSE; +} + +/************************************************************************* + * GUIDFromStringW [SHELL32.704] + */ +BOOL WINAPI GUIDFromStringW(LPCWSTR str, LPGUID guid) +{ + UNICODE_STRING guid_str; + + RtlInitUnicodeString(&guid_str, str); + return !RtlGUIDFromString(&guid_str, guid); +} + +/************************************************************************* + * PathIsTemporaryW [SHELL32.714] + */ +EXTERN_C BOOL WINAPI PathIsTemporaryW(LPWSTR Str) +{ + FIXME("(%s)stub\n", debugstr_w(Str)); + return FALSE; +} + +/************************************************************************* + * PathIsTemporaryA [SHELL32.713] + */ +EXTERN_C BOOL WINAPI PathIsTemporaryA(LPSTR Str) +{ + FIXME("(%s)stub\n", debugstr_a(Str)); + return FALSE; +} + +typedef struct _PSXA +{ + UINT uiCount; + UINT uiAllocated; + IShellPropSheetExt *pspsx[0]; +} PSXA, *PPSXA; + +typedef struct _PSXA_CALL +{ + LPFNADDPROPSHEETPAGE lpfnAddReplaceWith; + LPARAM lParam; + BOOL bCalled; + BOOL bMultiple; + UINT uiCount; +} PSXA_CALL, *PPSXA_CALL; + +static BOOL CALLBACK PsxaCall(HPROPSHEETPAGE hpage, LPARAM lParam) +{ + PPSXA_CALL Call = (PPSXA_CALL)lParam; + + if (Call != NULL) + { + if ((Call->bMultiple || !Call->bCalled) && + Call->lpfnAddReplaceWith(hpage, Call->lParam)) + { + Call->bCalled = TRUE; + Call->uiCount++; + return TRUE; + } + } + + return FALSE; +} + +/************************************************************************* + * SHAddFromPropSheetExtArray [SHELL32.167] + */ +UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) +{ + PSXA_CALL Call; + UINT i; + PPSXA psxa = (PPSXA)hpsxa; + + TRACE("(%p,%p,%08lx)\n", hpsxa, lpfnAddPage, lParam); + + if (psxa) + { + ZeroMemory(&Call, sizeof(Call)); + Call.lpfnAddReplaceWith = lpfnAddPage; + Call.lParam = lParam; + Call.bMultiple = TRUE; + + /* Call the AddPage method of all registered IShellPropSheetExt interfaces */ + for (i = 0; i != psxa->uiCount; i++) + { + psxa->pspsx[i]->AddPages(PsxaCall, (LPARAM)&Call); + } + + return Call.uiCount; + } + + return 0; +} + +/************************************************************************* + * SHCreatePropSheetExtArray [SHELL32.168] + */ +HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface) +{ + return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL); +} + + +/************************************************************************* + * SHCreatePropSheetExtArrayEx [SHELL32.194] + */ +EXTERN_C HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, IDataObject *pDataObj) +{ + static const WCHAR szPropSheetSubKey[] = {'s','h','e','l','l','e','x','\\','P','r','o','p','e','r','t','y','S','h','e','e','t','H','a','n','d','l','e','r','s',0}; + WCHAR szHandler[64]; + DWORD dwHandlerLen; + WCHAR szClsidHandler[39]; + DWORD dwClsidSize; + CLSID clsid; + LONG lRet; + DWORD dwIndex; + HKEY hkBase, hkPropSheetHandlers; + PPSXA psxa = NULL; + HRESULT hr; + + TRACE("(%p,%s,%u)\n", hKey, debugstr_w(pszSubKey), max_iface); + + if (max_iface == 0) + return NULL; + + /* Open the registry key */ + lRet = RegOpenKeyW(hKey, pszSubKey, &hkBase); + if (lRet != ERROR_SUCCESS) + return NULL; + + lRet = RegOpenKeyExW(hkBase, szPropSheetSubKey, 0, KEY_ENUMERATE_SUB_KEYS, &hkPropSheetHandlers); + RegCloseKey(hkBase); + if (lRet == ERROR_SUCCESS) + { + /* Create and initialize the Property Sheet Extensions Array */ + psxa = (PPSXA)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(PSXA) + max_iface * sizeof(IShellPropSheetExt *)); + if (psxa) + { + psxa->uiAllocated = max_iface; + + /* Enumerate all subkeys and attempt to load the shell extensions */ + dwIndex = 0; + do + { + dwHandlerLen = sizeof(szHandler) / sizeof(szHandler[0]); + lRet = RegEnumKeyExW(hkPropSheetHandlers, dwIndex++, szHandler, &dwHandlerLen, NULL, NULL, NULL, NULL); + if (lRet != ERROR_SUCCESS) + { + if (lRet == ERROR_MORE_DATA) + continue; + + if (lRet == ERROR_NO_MORE_ITEMS) + lRet = ERROR_SUCCESS; + break; + } + szHandler[(sizeof(szHandler) / sizeof(szHandler[0])) - 1] = 0; + hr = CLSIDFromString(szHandler, &clsid); + if (FAILED(hr)) + { + dwClsidSize = sizeof(szClsidHandler); + if (SHGetValueW(hkPropSheetHandlers, szHandler, NULL, NULL, szClsidHandler, &dwClsidSize) == ERROR_SUCCESS) + { + szClsidHandler[(sizeof(szClsidHandler) / sizeof(szClsidHandler[0])) - 1] = 0; + hr = CLSIDFromString(szClsidHandler, &clsid); + } + } + if (SUCCEEDED(hr)) + { + CComPtr psxi; + CComPtr pspsx; + + /* Attempt to get an IShellPropSheetExt and an IShellExtInit instance. + Only if both interfaces are supported it's a real shell extension. + Then call IShellExtInit's Initialize method. */ + if (SUCCEEDED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER/* | CLSCTX_NO_CODE_DOWNLOAD */, IID_IShellPropSheetExt, (LPVOID *)&pspsx))) + { + if (SUCCEEDED(pspsx->QueryInterface(IID_IShellExtInit, (PVOID *)&psxi))) + { + if (SUCCEEDED(psxi->Initialize(NULL, pDataObj, hKey))) + { + /* Add the IShellPropSheetExt instance to the array */ + psxa->pspsx[psxa->uiCount++] = pspsx.Detach(); + } + } + } + } + } while (psxa->uiCount != psxa->uiAllocated); + } + else + lRet = ERROR_NOT_ENOUGH_MEMORY; + + RegCloseKey(hkPropSheetHandlers); + } + + if (lRet != ERROR_SUCCESS && psxa) + { + SHDestroyPropSheetExtArray((HPSXA)psxa); + psxa = NULL; + } + + return (HPSXA)psxa; +} + +/************************************************************************* + * SHReplaceFromPropSheetExtArray [SHELL32.170] + */ +UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam) +{ + PSXA_CALL Call; + UINT i; + PPSXA psxa = (PPSXA)hpsxa; + + TRACE("(%p,%u,%p,%08lx)\n", hpsxa, uPageID, lpfnReplaceWith, lParam); + + if (psxa) + { + ZeroMemory(&Call, sizeof(Call)); + Call.lpfnAddReplaceWith = lpfnReplaceWith; + Call.lParam = lParam; + + /* Call the ReplacePage method of all registered IShellPropSheetExt interfaces. + Each shell extension is only allowed to call the callback once during the callback. */ + for (i = 0; i != psxa->uiCount; i++) + { + Call.bCalled = FALSE; + psxa->pspsx[i]->ReplacePage(uPageID, PsxaCall, (LPARAM)&Call); + } + + return Call.uiCount; + } + + return 0; +} + +/************************************************************************* + * SHDestroyPropSheetExtArray [SHELL32.169] + */ +void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa) +{ + UINT i; + PPSXA psxa = (PPSXA)hpsxa; + + TRACE("(%p)\n", hpsxa); + + if (psxa) + { + for (i = 0; i != psxa->uiCount; i++) + { + psxa->pspsx[i]->Release(); + } + + LocalFree((HLOCAL)psxa); + } +} + +/************************************************************************* + * CIDLData_CreateFromIDArray [SHELL32.83] + * + * Create IDataObject from PIDLs?? + */ +HRESULT WINAPI CIDLData_CreateFromIDArray( + LPCITEMIDLIST pidlFolder, + UINT cpidlFiles, + LPCITEMIDLIST *lppidlFiles, + IDataObject **ppdataObject) +{ + UINT i; + HWND hwnd = 0; /*FIXME: who should be hwnd of owner? set to desktop */ + HRESULT hResult; + + TRACE("(%p, %d, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject); + if (TRACE_ON(pidl)) + { + pdump (pidlFolder); + for (i = 0; i < cpidlFiles; i++) + pdump(lppidlFiles[i]); + } + hResult = IDataObject_Constructor(hwnd, pidlFolder, lppidlFiles, cpidlFiles, ppdataObject); + return hResult; +} + +/************************************************************************* + * SHCreateStdEnumFmtEtc [SHELL32.74] + * + * NOTES + * + */ +HRESULT WINAPI SHCreateStdEnumFmtEtc( + UINT cFormats, + const FORMATETC *lpFormats, + LPENUMFORMATETC *ppenumFormatetc) +{ + IEnumFORMATETC *pef; + HRESULT hRes; + TRACE("cf=%d fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc); + + hRes = IEnumFORMATETC_Constructor(cFormats, lpFormats, &pef); + if (FAILED(hRes)) + return hRes; + + pef->AddRef(); + hRes = pef->QueryInterface(IID_IEnumFORMATETC, (LPVOID*)ppenumFormatetc); + pef->Release(); + + return hRes; +} + + +/************************************************************************* + * SHCreateShellFolderView (SHELL32.256) + */ +HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv, IShellView **ppsv) +{ + HRESULT ret = S_OK; + + FIXME("SHCreateShellFolderView() stub\n"); + + if (!pcsfv || sizeof(*pcsfv) != pcsfv->cbSize) + ret = E_INVALIDARG; + else + { + LPVOID lpdata = 0;/*LocalAlloc(LMEM_ZEROINIT, 0x4E4);*/ + + if (!lpdata) + ret = E_OUTOFMEMORY; + else + { + /* Initialize and return unknown lpdata structure */ + } + } + + return ret; +} + +/************************************************************************* + * SHFindFiles (SHELL32.90) + */ +BOOL WINAPI SHFindFiles( LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile ) +{ + FIXME("%p %p\n", pidlFolder, pidlSaveFile ); + return FALSE; +} + +/************************************************************************* + * SHUpdateImageW (SHELL32.192) + * + * Notifies the shell that an icon in the system image list has been changed. + * + * PARAMS + * pszHashItem [I] Path to file that contains the icon. + * iIndex [I] Zero-based index of the icon in the file. + * uFlags [I] Flags determining the icon attributes. See notes. + * iImageIndex [I] Index of the icon in the system image list. + * + * RETURNS + * Nothing + * + * NOTES + * uFlags can be one or more of the following flags: + * GIL_NOTFILENAME - pszHashItem is not a file name. + * GIL_SIMULATEDOC - Create a document icon using the specified icon. + */ +void WINAPI SHUpdateImageW(LPCWSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex) +{ + FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_w(pszHashItem), iIndex, uFlags, iImageIndex); +} + +/************************************************************************* + * SHUpdateImageA (SHELL32.191) + * + * See SHUpdateImageW. + */ +VOID WINAPI SHUpdateImageA(LPCSTR pszHashItem, INT iIndex, UINT uFlags, INT iImageIndex) +{ + FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_a(pszHashItem), iIndex, uFlags, iImageIndex); +} + +INT WINAPI SHHandleUpdateImage(LPCITEMIDLIST pidlExtra) +{ + FIXME("%p - stub\n", pidlExtra); + + return -1; +} + +BOOL WINAPI SHObjectProperties(HWND hwnd, DWORD dwType, LPCWSTR szObject, LPCWSTR szPage) +{ + FIXME("%p, 0x%08x, %s, %s - stub\n", hwnd, dwType, debugstr_w(szObject), debugstr_w(szPage)); + + return TRUE; +} + +BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy, + UINT uFlags) +{ + WCHAR wszLinkTo[MAX_PATH]; + WCHAR wszDir[MAX_PATH]; + WCHAR wszName[MAX_PATH]; + BOOL res; + + MultiByteToWideChar(CP_ACP, 0, pszLinkTo, -1, wszLinkTo, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, pszDir, -1, wszDir, MAX_PATH); + + res = SHGetNewLinkInfoW(wszLinkTo, wszDir, wszName, pfMustCopy, uFlags); + + if (res) + WideCharToMultiByte(CP_ACP, 0, wszName, -1, pszName, MAX_PATH, NULL, NULL); + + return res; +} + +BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy, + UINT uFlags) +{ + const WCHAR *basename; + WCHAR *dst_basename; + int i=2; + static const WCHAR lnkformat[] = {'%','s','.','l','n','k',0}; + static const WCHAR lnkformatnum[] = {'%','s',' ','(','%','d',')','.','l','n','k',0}; + + TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(pszLinkTo), debugstr_w(pszDir), + pszName, pfMustCopy, uFlags); + + *pfMustCopy = FALSE; + + if (uFlags & SHGNLI_PIDL) + { + FIXME("SHGNLI_PIDL flag unsupported\n"); + return FALSE; + } + + if (uFlags) + FIXME("ignoring flags: 0x%08x\n", uFlags); + + /* FIXME: should test if the file is a shortcut or DOS program */ + if (GetFileAttributesW(pszLinkTo) == INVALID_FILE_ATTRIBUTES) + return FALSE; + + basename = strrchrW(pszLinkTo, '\\'); + if (basename) + basename = basename+1; + else + basename = pszLinkTo; + + lstrcpynW(pszName, pszDir, MAX_PATH); + if (!PathAddBackslashW(pszName)) + return FALSE; + + dst_basename = pszName + strlenW(pszName); + + snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, lnkformat, basename); + + while (GetFileAttributesW(pszName) != INVALID_FILE_ATTRIBUTES) + { + snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, lnkformatnum, basename, i); + i++; + } + + return TRUE; +} + +/************************************************************************* + * SHStartNetConnectionDialog (SHELL32.@) + */ +HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType) +{ + FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRemoteName), dwType); + + return S_OK; +} +/************************************************************************* + * SHEmptyRecycleBinA (SHELL32.@) + */ +HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags) +{ + LPWSTR szRootPathW = NULL; + int len; + HRESULT hr; + + TRACE("%p, %s, 0x%08x\n", hwnd, debugstr_a(pszRootPath), dwFlags); + + if (pszRootPath) + { + len = MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, NULL, 0); + if (len == 0) + return HRESULT_FROM_WIN32(GetLastError()); + szRootPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!szRootPathW) + return E_OUTOFMEMORY; + if (MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, szRootPathW, len) == 0) + { + HeapFree(GetProcessHeap(), 0, szRootPathW); + return HRESULT_FROM_WIN32(GetLastError()); + } + } + + hr = SHEmptyRecycleBinW(hwnd, szRootPathW, dwFlags); + HeapFree(GetProcessHeap(), 0, szRootPathW); + + return hr; +} + +HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags) +{ + WCHAR szPath[MAX_PATH] = {0}; + DWORD dwSize, dwType; + LONG ret; + + TRACE("%p, %s, 0x%08x\n", hwnd, debugstr_w(pszRootPath), dwFlags); + + if (!(dwFlags & SHERB_NOCONFIRMATION)) + { + /* FIXME + * enumerate available files + * show confirmation dialog + */ + FIXME("show confirmation dialog\n"); + } + + if (dwFlags & SHERB_NOPROGRESSUI) + { + ret = EmptyRecycleBinW(pszRootPath); + } + else + { + /* FIXME + * show a progress dialog + */ + ret = EmptyRecycleBinW(pszRootPath); + } + + if (!ret) + return HRESULT_FROM_WIN32(GetLastError()); + + if (!(dwFlags & SHERB_NOSOUND)) + { + dwSize = sizeof(szPath); + ret = RegGetValueW(HKEY_CURRENT_USER, + L"AppEvents\\Schemes\\Apps\\Explorer\\EmptyRecycleBin\\.Current", + NULL, + RRF_RT_REG_EXPAND_SZ, + &dwType, + (PVOID)szPath, + &dwSize); + if (ret != ERROR_SUCCESS) + return S_OK; + + if (dwType != REG_EXPAND_SZ) /* type dismatch */ + return S_OK; + + szPath[(sizeof(szPath)/sizeof(WCHAR))-1] = L'\0'; + PlaySoundW(szPath, NULL, SND_FILENAME); + } + return S_OK; +} + +HRESULT WINAPI SHQueryRecycleBinA(LPCSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo) +{ + LPWSTR szRootPathW = NULL; + int len; + HRESULT hr; + + TRACE("%s, %p\n", debugstr_a(pszRootPath), pSHQueryRBInfo); + + if (pszRootPath) + { + len = MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, NULL, 0); + if (len == 0) + return HRESULT_FROM_WIN32(GetLastError()); + szRootPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!szRootPathW) + return E_OUTOFMEMORY; + if (MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, szRootPathW, len) == 0) + { + HeapFree(GetProcessHeap(), 0, szRootPathW); + return HRESULT_FROM_WIN32(GetLastError()); + } + } + + hr = SHQueryRecycleBinW(szRootPathW, pSHQueryRBInfo); + HeapFree(GetProcessHeap(), 0, szRootPathW); + + return hr; +} + +HRESULT WINAPI SHQueryRecycleBinW(LPCWSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo) +{ + FIXME("%s, %p - stub\n", debugstr_w(pszRootPath), pSHQueryRBInfo); + + if (!(pszRootPath) || (pszRootPath[0] == 0) || + !(pSHQueryRBInfo) || (pSHQueryRBInfo->cbSize < sizeof(SHQUERYRBINFO))) + { + return E_INVALIDARG; + } + + pSHQueryRBInfo->i64Size = 0; + pSHQueryRBInfo->i64NumItems = 0; + + return S_OK; +} + +/************************************************************************* + * SHSetLocalizedName (SHELL32.@) + */ +EXTERN_C HRESULT WINAPI SHSetLocalizedName(LPCWSTR pszPath, LPCWSTR pszResModule, int idsRes) +{ + FIXME("%p, %s, %d - stub\n", pszPath, debugstr_w(pszResModule), idsRes); + + return S_OK; +} + +/************************************************************************* + * LinkWindow_RegisterClass (SHELL32.258) + */ +EXTERN_C BOOL WINAPI LinkWindow_RegisterClass(void) +{ + FIXME("()\n"); + return TRUE; +} + +/************************************************************************* + * LinkWindow_UnregisterClass (SHELL32.259) + */ +EXTERN_C BOOL WINAPI LinkWindow_UnregisterClass(void) +{ + FIXME("()\n"); + return TRUE; + +} + +/************************************************************************* + * SHFlushSFCache (SHELL32.526) + * + * Notifies the shell that a user-specified special folder location has changed. + * + * NOTES + * In Wine, the shell folder registry values are not cached, so this function + * has no effect. + */ +EXTERN_C void WINAPI SHFlushSFCache(void) +{ +} + +/************************************************************************* + * SHGetImageList (SHELL32.727) + * + * Returns a copy of a shell image list. + * + * NOTES + * Windows XP features 4 sizes of image list, and Vista 5. Wine currently + * only supports the traditional small and large image lists, so requests + * for the others will currently fail. + */ +EXTERN_C HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv) +{ + HIMAGELIST hLarge, hSmall; + HIMAGELIST hNew; + HRESULT ret = E_FAIL; + + /* Wine currently only maintains large and small image lists */ + if ((iImageList != SHIL_LARGE) && (iImageList != SHIL_SMALL) && (iImageList != SHIL_SYSSMALL)) + { + FIXME("Unsupported image list %i requested\n", iImageList); + return E_FAIL; + } + + Shell_GetImageLists(&hLarge, &hSmall); + hNew = ImageList_Duplicate(iImageList == SHIL_LARGE ? hLarge : hSmall); + + /* Get the interface for the new image list */ + if (hNew) + { + ret = HIMAGELIST_QueryInterface(hNew, riid, ppv); + ImageList_Destroy(hNew); + } + + return ret; +} + +/************************************************************************* + * SHParseDisplayName [shell version 6.0] + */ +EXTERN_C HRESULT WINAPI SHParseDisplayName(LPCWSTR pszName, IBindCtx *pbc, + LPITEMIDLIST *ppidl, SFGAOF sfgaoIn, SFGAOF *psfgaoOut) +{ + CComPtr psfDesktop; + HRESULT hr=E_FAIL; + ULONG dwAttr=sfgaoIn; + + if(!ppidl) + return E_INVALIDARG; + + if (!pszName || !psfgaoOut) + { + *ppidl = NULL; + return E_INVALIDARG; + } + + hr = SHGetDesktopFolder(&psfDesktop); + if (FAILED(hr)) + { + *ppidl = NULL; + return hr; + } + + hr = psfDesktop->ParseDisplayName((HWND)NULL, pbc, (LPOLESTR)pszName, (ULONG *)NULL, ppidl, &dwAttr); + + psfDesktop->Release(); + + if (SUCCEEDED(hr)) + *psfgaoOut = dwAttr; + else + *ppidl = NULL; + + return hr; +} diff --git a/reactos/dll/win32/shell32/shellpath.cpp b/reactos/dll/win32/shell32/shellpath.cpp new file mode 100644 index 00000000000..34e2a186c27 --- /dev/null +++ b/reactos/dll/win32/shell32/shellpath.cpp @@ -0,0 +1,2030 @@ +/* + * Path Functions + * + * Copyright 1998, 1999, 2000 Juergen Schmied + * Copyright 2004 Juan Lang + * + * 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 + * + * NOTES: + * + * Many of these functions are in SHLWAPI.DLL also + * + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* + ########## Combining and Constructing paths ########## +*/ + +/************************************************************************* + * PathAppend [SHELL32.36] + */ +BOOL WINAPI PathAppendAW( + LPVOID lpszPath1, + LPCVOID lpszPath2) +{ + if (SHELL_OsIsUnicode()) + return PathAppendW((LPWSTR)lpszPath1, (LPCWSTR)lpszPath2); + return PathAppendA((LPSTR)lpszPath1, (LPCSTR)lpszPath2); +} + +/************************************************************************* + * PathBuildRoot [SHELL32.30] + */ +LPVOID WINAPI PathBuildRootAW(LPVOID lpszPath, int drive) +{ + if(SHELL_OsIsUnicode()) + return PathBuildRootW((LPWSTR)lpszPath, drive); + return PathBuildRootA((LPSTR)lpszPath, drive); +} + +/************************************************************************* + * PathGetExtensionA [internal] + * + * NOTES + * exported by ordinal + * return value points to the first char after the dot + */ +static LPSTR PathGetExtensionA(LPCSTR lpszPath) +{ + TRACE("(%s)\n",lpszPath); + + lpszPath = PathFindExtensionA(lpszPath); + return (LPSTR)(*lpszPath?(lpszPath+1):lpszPath); +} + +/************************************************************************* + * PathGetExtensionW [internal] + */ +LPWSTR PathGetExtensionW(LPCWSTR lpszPath) +{ + TRACE("(%s)\n",debugstr_w(lpszPath)); + + lpszPath = PathFindExtensionW(lpszPath); + return (LPWSTR)(*lpszPath?(lpszPath+1):lpszPath); +} + +/************************************************************************* + * SHPathGetExtension [SHELL32.158] + */ +EXTERN_C LPVOID WINAPI SHPathGetExtensionW(LPCWSTR lpszPath, DWORD void1, DWORD void2) +{ + return PathGetExtensionW(lpszPath); +} + +/************************************************************************* + * PathRemoveFileSpec [SHELL32.35] + */ +BOOL WINAPI PathRemoveFileSpecAW(LPVOID lpszPath) +{ + if (SHELL_OsIsUnicode()) + return PathRemoveFileSpecW((LPWSTR)lpszPath); + return PathRemoveFileSpecA((LPSTR)lpszPath); +} + +/* + Path Manipulations +*/ + +/************************************************************************* + * PathGetShortPathA [internal] + */ +static void PathGetShortPathA(LPSTR pszPath) +{ + CHAR path[MAX_PATH]; + + TRACE("%s\n", pszPath); + + if (GetShortPathNameA(pszPath, path, MAX_PATH)) + { + lstrcpyA(pszPath, path); + } +} + +/************************************************************************* + * PathGetShortPathW [internal] + */ +static void PathGetShortPathW(LPWSTR pszPath) +{ + WCHAR path[MAX_PATH]; + + TRACE("%s\n", debugstr_w(pszPath)); + + if (GetShortPathNameW(pszPath, path, MAX_PATH)) + { + wcscpy(pszPath, path); + } +} + +/************************************************************************* + * PathGetShortPath [SHELL32.92] + */ +EXTERN_C VOID WINAPI PathGetShortPathAW(LPVOID pszPath) +{ + if(SHELL_OsIsUnicode()) + PathGetShortPathW((LPWSTR)pszPath); + PathGetShortPathA((LPSTR)pszPath); +} + +/* + ########## Path Testing ########## +*/ + +/************************************************************************* + * PathIsRoot [SHELL32.29] + */ +BOOL WINAPI PathIsRootAW(LPCVOID lpszPath) +{ + if (SHELL_OsIsUnicode()) + return PathIsRootW((LPWSTR)lpszPath); + return PathIsRootA((LPSTR)lpszPath); +} + +/************************************************************************* + * PathIsExeA [internal] + */ +static BOOL PathIsExeA (LPCSTR lpszPath) +{ + LPCSTR lpszExtension = PathGetExtensionA(lpszPath); + int i; + static const char * const lpszExtensions[] = + {"exe", "com", "pif", "cmd", "bat", "scf", "scr", NULL }; + + TRACE("path=%s\n",lpszPath); + + for(i=0; lpszExtensions[i]; i++) + if (!lstrcmpiA(lpszExtension,lpszExtensions[i])) return TRUE; + + return FALSE; +} + +/************************************************************************* + * PathIsExeW [internal] + */ +static BOOL PathIsExeW (LPCWSTR lpszPath) +{ + LPCWSTR lpszExtension = PathGetExtensionW(lpszPath); + int i; + static const WCHAR lpszExtensions[][4] = + {{'e','x','e','\0'}, {'c','o','m','\0'}, {'p','i','f','\0'}, + {'c','m','d','\0'}, {'b','a','t','\0'}, {'s','c','f','\0'}, + {'s','c','r','\0'}, {'\0'} }; + + TRACE("path=%s\n",debugstr_w(lpszPath)); + + for(i=0; lpszExtensions[i][0]; i++) + if (!strcmpiW(lpszExtension,lpszExtensions[i])) return TRUE; + + return FALSE; +} + +/************************************************************************* + * PathIsExe [SHELL32.43] + */ +BOOL WINAPI PathIsExeAW (LPCVOID path) +{ + if (SHELL_OsIsUnicode()) + return PathIsExeW ((LPWSTR)path); + return PathIsExeA((LPSTR)path); +} + +/************************************************************************* + * PathFileExists [SHELL32.45] + */ +BOOL WINAPI PathFileExistsAW (LPCVOID lpszPath) +{ + if (SHELL_OsIsUnicode()) + return PathFileExistsW ((LPWSTR)lpszPath); + return PathFileExistsA ((LPSTR)lpszPath); +} + +/************************************************************************* + * PathIsSameRoot [SHELL32.650] + */ +BOOL WINAPI PathIsSameRootAW(LPCVOID lpszPath1, LPCVOID lpszPath2) +{ + if (SHELL_OsIsUnicode()) + return PathIsSameRootW((LPCWSTR)lpszPath1, (LPCWSTR)lpszPath2); + return PathIsSameRootA((LPCSTR)lpszPath1, (LPCSTR)lpszPath2); +} + +/************************************************************************* + * IsLFNDriveA [SHELL32.41] + */ +EXTERN_C BOOL WINAPI IsLFNDriveA(LPCSTR lpszPath) +{ + DWORD fnlen; + + if (!GetVolumeInformationA(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0)) + return FALSE; + return fnlen > 12; +} + +/************************************************************************* + * IsLFNDriveW [SHELL32.42] + */ +EXTERN_C BOOL WINAPI IsLFNDriveW(LPCWSTR lpszPath) +{ + DWORD fnlen; + + if (!GetVolumeInformationW(lpszPath, NULL, 0, NULL, &fnlen, NULL, NULL, 0)) + return FALSE; + return fnlen > 12; +} + +/************************************************************************* + * IsLFNDrive [SHELL32.119] + */ +EXTERN_C BOOL WINAPI IsLFNDriveAW(LPCVOID lpszPath) +{ + if (SHELL_OsIsUnicode()) + return IsLFNDriveW((LPCWSTR)lpszPath); + return IsLFNDriveA((LPCSTR)lpszPath); +} + +/* + ########## Creating Something Unique ########## +*/ +/************************************************************************* + * PathMakeUniqueNameA [internal] + */ +BOOL WINAPI PathMakeUniqueNameA( + LPSTR lpszBuffer, + DWORD dwBuffSize, + LPCSTR lpszShortName, + LPCSTR lpszLongName, + LPCSTR lpszPathName) +{ + FIXME("%p %u %s %s %s stub\n", + lpszBuffer, dwBuffSize, debugstr_a(lpszShortName), + debugstr_a(lpszLongName), debugstr_a(lpszPathName)); + return TRUE; +} + +/************************************************************************* + * PathMakeUniqueNameW [internal] + */ +BOOL WINAPI PathMakeUniqueNameW( + LPWSTR lpszBuffer, + DWORD dwBuffSize, + LPCWSTR lpszShortName, + LPCWSTR lpszLongName, + LPCWSTR lpszPathName) +{ + FIXME("%p %u %s %s %s stub\n", + lpszBuffer, dwBuffSize, debugstr_w(lpszShortName), + debugstr_w(lpszLongName), debugstr_w(lpszPathName)); + return TRUE; +} + +/************************************************************************* + * PathMakeUniqueName [SHELL32.47] + */ +BOOL WINAPI PathMakeUniqueNameAW( + LPVOID lpszBuffer, + DWORD dwBuffSize, + LPCVOID lpszShortName, + LPCVOID lpszLongName, + LPCVOID lpszPathName) +{ + if (SHELL_OsIsUnicode()) + return PathMakeUniqueNameW((LPWSTR)lpszBuffer, dwBuffSize, (LPCWSTR)lpszShortName, (LPCWSTR)lpszLongName, (LPCWSTR)lpszPathName); + return PathMakeUniqueNameA((LPSTR)lpszBuffer, dwBuffSize, (LPCSTR)lpszShortName, (LPCSTR)lpszLongName, (LPCSTR)lpszPathName); +} + +/************************************************************************* + * PathYetAnotherMakeUniqueName [SHELL32.75] + * + * NOTES + * exported by ordinal + */ +BOOL WINAPI PathYetAnotherMakeUniqueName( + LPWSTR lpszBuffer, + LPCWSTR lpszPathName, + LPCWSTR lpszShortName, + LPCWSTR lpszLongName) +{ + FIXME("(%p, %s, %s ,%s):stub.\n", + lpszBuffer, debugstr_w(lpszPathName), debugstr_w(lpszShortName), debugstr_w(lpszLongName)); + return TRUE; +} + + +/* + ########## cleaning and resolving paths ########## + */ + +/************************************************************************* + * PathCleanupSpec [SHELL32.171] + * + * lpszFile is changed in place. + */ +int WINAPI PathCleanupSpec( LPCWSTR lpszPathW, LPWSTR lpszFileW ) +{ + int i = 0; + DWORD rc = 0; + int length = 0; + + if (SHELL_OsIsUnicode()) + { + LPWSTR p = lpszFileW; + + TRACE("Cleanup %s\n",debugstr_w(lpszFileW)); + + if (lpszPathW) + length = wcslen(lpszPathW); + + while (*p) + { + int gct = PathGetCharTypeW(*p); + if (gct == GCT_INVALID || gct == GCT_WILD || gct == GCT_SEPARATOR) + { + lpszFileW[i]='-'; + rc |= PCS_REPLACEDCHAR; + } + else + lpszFileW[i]=*p; + i++; + p++; + if (length + i == MAX_PATH) + { + rc |= PCS_FATAL | PCS_PATHTOOLONG; + break; + } + } + lpszFileW[i]=0; + } + else + { + LPSTR lpszFileA = (LPSTR)lpszFileW; + LPCSTR lpszPathA = (LPCSTR)lpszPathW; + LPSTR p = lpszFileA; + + TRACE("Cleanup %s\n",debugstr_a(lpszFileA)); + + if (lpszPathA) + length = strlen(lpszPathA); + + while (*p) + { + int gct = PathGetCharTypeA(*p); + if (gct == GCT_INVALID || gct == GCT_WILD || gct == GCT_SEPARATOR) + { + lpszFileA[i]='-'; + rc |= PCS_REPLACEDCHAR; + } + else + lpszFileA[i]=*p; + i++; + p++; + if (length + i == MAX_PATH) + { + rc |= PCS_FATAL | PCS_PATHTOOLONG; + break; + } + } + lpszFileA[i]=0; + } + return rc; +} + +/************************************************************************* + * PathQualifyA [SHELL32] + */ +BOOL WINAPI PathQualifyA(LPCSTR pszPath) +{ + FIXME("%s\n",pszPath); + return 0; +} + +/************************************************************************* + * PathQualifyW [SHELL32] + */ +BOOL WINAPI PathQualifyW(LPCWSTR pszPath) +{ + FIXME("%s\n",debugstr_w(pszPath)); + return 0; +} + +/************************************************************************* + * PathQualify [SHELL32.49] + */ +BOOL WINAPI PathQualifyAW(LPCVOID pszPath) +{ + if (SHELL_OsIsUnicode()) + return PathQualifyW((LPCWSTR)pszPath); + return PathQualifyA((LPCSTR)pszPath); +} + +/************************************************************************* + * PathResolveA [SHELL32.51] + */ +BOOL WINAPI PathResolveA( + LPSTR lpszPath, + LPCSTR *alpszPaths, + DWORD dwFlags) +{ + FIXME("(%s,%p,0x%08x),stub!\n", + lpszPath, *alpszPaths, dwFlags); + return 0; +} + +/************************************************************************* + * PathResolveW [SHELL32] + */ +BOOL WINAPI PathResolveW( + LPWSTR lpszPath, + LPCWSTR *alpszPaths, + DWORD dwFlags) +{ + FIXME("(%s,%p,0x%08x),stub!\n", + debugstr_w(lpszPath), debugstr_w(*alpszPaths), dwFlags); + return 0; +} + +/************************************************************************* + * PathResolve [SHELL32.51] + */ +BOOL WINAPI PathResolveAW( + LPVOID lpszPath, + LPCVOID *alpszPaths, + DWORD dwFlags) +{ + if (SHELL_OsIsUnicode()) + return PathResolveW((LPWSTR)lpszPath, (LPCWSTR *)alpszPaths, dwFlags); + return PathResolveA((LPSTR)lpszPath, (LPCSTR *)alpszPaths, dwFlags); +} + +/************************************************************************* +* PathProcessCommandA [SHELL32.653] +*/ +LONG WINAPI PathProcessCommandA ( + LPCSTR lpszPath, + LPSTR lpszBuff, + DWORD dwBuffSize, + DWORD dwFlags) +{ + FIXME("%s %p 0x%04x 0x%04x stub\n", + lpszPath, lpszBuff, dwBuffSize, dwFlags); + if(!lpszPath) return -1; + if(lpszBuff) strcpy(lpszBuff, lpszPath); + return strlen(lpszPath); +} + +/************************************************************************* +* PathProcessCommandW +*/ +LONG WINAPI PathProcessCommandW ( + LPCWSTR lpszPath, + LPWSTR lpszBuff, + DWORD dwBuffSize, + DWORD dwFlags) +{ + FIXME("(%s, %p, 0x%04x, 0x%04x) stub\n", + debugstr_w(lpszPath), lpszBuff, dwBuffSize, dwFlags); + if(!lpszPath) return -1; + if(lpszBuff) wcscpy(lpszBuff, lpszPath); + return wcslen(lpszPath); +} + +/************************************************************************* +* PathProcessCommand (SHELL32.653) +*/ +LONG WINAPI PathProcessCommandAW ( + LPCVOID lpszPath, + LPVOID lpszBuff, + DWORD dwBuffSize, + DWORD dwFlags) +{ + if (SHELL_OsIsUnicode()) + return PathProcessCommandW((LPCWSTR)lpszPath, (LPWSTR)lpszBuff, dwBuffSize, dwFlags); + return PathProcessCommandA((LPCSTR)lpszPath, (LPSTR)lpszBuff, dwBuffSize, dwFlags); +} + +/* + ########## special ########## +*/ + +static const WCHAR szCurrentVersion[] = {'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','\0'}; +static const WCHAR Administrative_ToolsW[] = {'A','d','m','i','n','i','s','t','r','a','t','i','v','e',' ','T','o','o','l','s','\0'}; +static const WCHAR AppDataW[] = {'A','p','p','D','a','t','a','\0'}; +static const WCHAR CacheW[] = {'C','a','c','h','e','\0'}; +static const WCHAR CD_BurningW[] = {'C','D',' ','B','u','r','n','i','n','g','\0'}; +static const WCHAR Common_Administrative_ToolsW[] = {'C','o','m','m','o','n',' ','A','d','m','i','n','i','s','t','r','a','t','i','v','e',' ','T','o','o','l','s','\0'}; +static const WCHAR Common_AppDataW[] = {'C','o','m','m','o','n',' ','A','p','p','D','a','t','a','\0'}; +static const WCHAR Common_DesktopW[] = {'C','o','m','m','o','n',' ','D','e','s','k','t','o','p','\0'}; +static const WCHAR Common_DocumentsW[] = {'C','o','m','m','o','n',' ','D','o','c','u','m','e','n','t','s','\0'}; +static const WCHAR CommonFilesDirW[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r','\0'}; +static const WCHAR CommonMusicW[] = {'C','o','m','m','o','n','M','u','s','i','c','\0'}; +static const WCHAR CommonPicturesW[] = {'C','o','m','m','o','n','P','i','c','t','u','r','e','s','\0'}; +static const WCHAR Common_ProgramsW[] = {'C','o','m','m','o','n',' ','P','r','o','g','r','a','m','s','\0'}; +static const WCHAR Common_StartUpW[] = {'C','o','m','m','o','n',' ','S','t','a','r','t','U','p','\0'}; +static const WCHAR Common_Start_MenuW[] = {'C','o','m','m','o','n',' ','S','t','a','r','t',' ','M','e','n','u','\0'}; +static const WCHAR Common_TemplatesW[] = {'C','o','m','m','o','n',' ','T','e','m','p','l','a','t','e','s','\0'}; +static const WCHAR CommonVideoW[] = {'C','o','m','m','o','n','V','i','d','e','o','\0'}; +static const WCHAR CookiesW[] = {'C','o','o','k','i','e','s','\0'}; +static const WCHAR DesktopW[] = {'D','e','s','k','t','o','p','\0'}; +static const WCHAR FavoritesW[] = {'F','a','v','o','r','i','t','e','s','\0'}; +static const WCHAR FontsW[] = {'F','o','n','t','s','\0'}; +static const WCHAR HistoryW[] = {'H','i','s','t','o','r','y','\0'}; +static const WCHAR Local_AppDataW[] = {'L','o','c','a','l',' ','A','p','p','D','a','t','a','\0'}; +static const WCHAR My_MusicW[] = {'M','y',' ','M','u','s','i','c','\0'}; +static const WCHAR My_PicturesW[] = {'M','y',' ','P','i','c','t','u','r','e','s','\0'}; +static const WCHAR My_VideoW[] = {'M','y',' ','V','i','d','e','o','\0'}; +static const WCHAR NetHoodW[] = {'N','e','t','H','o','o','d','\0'}; +static const WCHAR PersonalW[] = {'P','e','r','s','o','n','a','l','\0'}; +static const WCHAR PrintHoodW[] = {'P','r','i','n','t','H','o','o','d','\0'}; +static const WCHAR ProgramFilesDirW[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r','\0'}; +static const WCHAR ProgramsW[] = {'P','r','o','g','r','a','m','s','\0'}; +static const WCHAR RecentW[] = {'R','e','c','e','n','t','\0'}; +static const WCHAR ResourcesW[] = {'R','e','s','o','u','r','c','e','s','\0'}; +static const WCHAR SendToW[] = {'S','e','n','d','T','o','\0'}; +static const WCHAR StartUpW[] = {'S','t','a','r','t','U','p','\0'}; +static const WCHAR Start_MenuW[] = {'S','t','a','r','t',' ','M','e','n','u','\0'}; +static const WCHAR TemplatesW[] = {'T','e','m','p','l','a','t','e','s','\0'}; +static const WCHAR DefaultW[] = {'.','D','e','f','a','u','l','t','\0'}; +static const WCHAR AllUsersProfileW[] = {'%','A','L','L','U','S','E','R','S','P','R','O','F','I','L','E','%','\0'}; +static const WCHAR UserProfileW[] = {'%','U','S','E','R','P','R','O','F','I','L','E','%','\0'}; +static const WCHAR SystemDriveW[] = {'%','S','y','s','t','e','m','D','r','i','v','e','%','\0'}; +static const WCHAR ProfileListW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','P','r','o','f','i','l','e','L','i','s','t',0}; +static const WCHAR ProfilesDirectoryW[] = {'P','r','o','f','i','l','e','s','D','i','r','e','c','t','o','r','y',0}; +static const WCHAR AllUsersProfileValueW[] = {'A','l','l','U','s','e','r','s','P','r','o','f','i','l','e','\0'}; +static const WCHAR szSHFolders[] = {'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','\\','S','h','e','l','l',' ','F','o','l','d','e','r','s','\0'}; +static const WCHAR szSHUserFolders[] = {'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','\\','U','s','e','r',' ','S','h','e','l','l',' ','F','o','l','d','e','r','s','\0'}; +/* This defaults to L"Documents and Settings" on Windows 2000/XP, but we're + * acting more Windows 9x-like for now. + */ +static const WCHAR szDefaultProfileDirW[] = {'p','r','o','f','i','l','e','s','\0'}; +static const WCHAR AllUsersW[] = {'A','l','l',' ','U','s','e','r','s','\0'}; + +typedef enum _CSIDL_Type { + CSIDL_Type_User, + CSIDL_Type_AllUsers, + CSIDL_Type_CurrVer, + CSIDL_Type_Disallowed, + CSIDL_Type_NonExistent, + CSIDL_Type_WindowsPath, + CSIDL_Type_SystemPath, +} CSIDL_Type; + +typedef struct +{ + CSIDL_Type type; + LPCWSTR szValueName; + LPCWSTR szDefaultPath; /* fallback string or resource ID */ +} CSIDL_DATA; + +static const CSIDL_DATA CSIDL_Data[] = +{ + { /* 0x00 - CSIDL_DESKTOP */ + CSIDL_Type_User, + DesktopW, + MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY) + }, + { /* 0x01 - CSIDL_INTERNET */ + CSIDL_Type_Disallowed, + NULL, + NULL + }, + { /* 0x02 - CSIDL_PROGRAMS */ + CSIDL_Type_User, + ProgramsW, + MAKEINTRESOURCEW(IDS_PROGRAMS) + }, + { /* 0x03 - CSIDL_CONTROLS (.CPL files) */ + CSIDL_Type_SystemPath, + NULL, + NULL + }, + { /* 0x04 - CSIDL_PRINTERS */ + CSIDL_Type_SystemPath, + NULL, + NULL + }, + { /* 0x05 - CSIDL_PERSONAL */ + CSIDL_Type_User, + PersonalW, + MAKEINTRESOURCEW(IDS_PERSONAL) + }, + { /* 0x06 - CSIDL_FAVORITES */ + CSIDL_Type_User, + FavoritesW, + MAKEINTRESOURCEW(IDS_FAVORITES) + }, + { /* 0x07 - CSIDL_STARTUP */ + CSIDL_Type_User, + StartUpW, + MAKEINTRESOURCEW(IDS_STARTUP) + }, + { /* 0x08 - CSIDL_RECENT */ + CSIDL_Type_User, + RecentW, + MAKEINTRESOURCEW(IDS_RECENT) + }, + { /* 0x09 - CSIDL_SENDTO */ + CSIDL_Type_User, + SendToW, + MAKEINTRESOURCEW(IDS_SENDTO) + }, + { /* 0x0a - CSIDL_BITBUCKET - Recycle Bin */ + CSIDL_Type_Disallowed, + NULL, + NULL, + }, + { /* 0x0b - CSIDL_STARTMENU */ + CSIDL_Type_User, + Start_MenuW, + MAKEINTRESOURCEW(IDS_STARTMENU) + }, + { /* 0x0c - CSIDL_MYDOCUMENTS */ + CSIDL_Type_Disallowed, /* matches WinXP--can't get its path */ + NULL, + NULL + }, + { /* 0x0d - CSIDL_MYMUSIC */ + CSIDL_Type_User, + My_MusicW, + MAKEINTRESOURCEW(IDS_MYMUSIC) + }, + { /* 0x0e - CSIDL_MYVIDEO */ + CSIDL_Type_User, + My_VideoW, + MAKEINTRESOURCEW(IDS_MYVIDEO) + }, + { /* 0x0f - unassigned */ + CSIDL_Type_Disallowed, + NULL, + NULL, + }, + { /* 0x10 - CSIDL_DESKTOPDIRECTORY */ + CSIDL_Type_User, + DesktopW, + MAKEINTRESOURCEW(IDS_DESKTOPDIRECTORY) + }, + { /* 0x11 - CSIDL_DRIVES */ + CSIDL_Type_Disallowed, + NULL, + NULL, + }, + { /* 0x12 - CSIDL_NETWORK */ + CSIDL_Type_Disallowed, + NULL, + NULL, + }, + { /* 0x13 - CSIDL_NETHOOD */ + CSIDL_Type_User, + NetHoodW, + MAKEINTRESOURCEW(IDS_NETHOOD) + }, + { /* 0x14 - CSIDL_FONTS */ + CSIDL_Type_WindowsPath, + FontsW, + FontsW + }, + { /* 0x15 - CSIDL_TEMPLATES */ + CSIDL_Type_User, + TemplatesW, + MAKEINTRESOURCEW(IDS_TEMPLATES) + }, + { /* 0x16 - CSIDL_COMMON_STARTMENU */ + CSIDL_Type_AllUsers, + Common_Start_MenuW, + MAKEINTRESOURCEW(IDS_STARTMENU) + }, + { /* 0x17 - CSIDL_COMMON_PROGRAMS */ + CSIDL_Type_AllUsers, + Common_ProgramsW, + MAKEINTRESOURCEW(IDS_PROGRAMS) + }, + { /* 0x18 - CSIDL_COMMON_STARTUP */ + CSIDL_Type_AllUsers, + Common_StartUpW, + MAKEINTRESOURCEW(IDS_STARTUP) + }, + { /* 0x19 - CSIDL_COMMON_DESKTOPDIRECTORY */ + CSIDL_Type_AllUsers, + Common_DesktopW, + MAKEINTRESOURCEW(IDS_DESKTOP) + }, + { /* 0x1a - CSIDL_APPDATA */ + CSIDL_Type_User, + AppDataW, + MAKEINTRESOURCEW(IDS_APPDATA) + }, + { /* 0x1b - CSIDL_PRINTHOOD */ + CSIDL_Type_User, + PrintHoodW, + MAKEINTRESOURCEW(IDS_PRINTHOOD) + }, + { /* 0x1c - CSIDL_LOCAL_APPDATA */ + CSIDL_Type_User, + Local_AppDataW, + MAKEINTRESOURCEW(IDS_LOCAL_APPDATA) + }, + { /* 0x1d - CSIDL_ALTSTARTUP */ + CSIDL_Type_NonExistent, + NULL, + NULL + }, + { /* 0x1e - CSIDL_COMMON_ALTSTARTUP */ + CSIDL_Type_NonExistent, + NULL, + NULL + }, + { /* 0x1f - CSIDL_COMMON_FAVORITES */ + CSIDL_Type_AllUsers, + FavoritesW, + MAKEINTRESOURCEW(IDS_FAVORITES) + }, + { /* 0x20 - CSIDL_INTERNET_CACHE */ + CSIDL_Type_User, + CacheW, + MAKEINTRESOURCEW(IDS_INTERNET_CACHE) + }, + { /* 0x21 - CSIDL_COOKIES */ + CSIDL_Type_User, + CookiesW, + MAKEINTRESOURCEW(IDS_COOKIES) + }, + { /* 0x22 - CSIDL_HISTORY */ + CSIDL_Type_User, + HistoryW, + MAKEINTRESOURCEW(IDS_HISTORY) + }, + { /* 0x23 - CSIDL_COMMON_APPDATA */ + CSIDL_Type_AllUsers, + Common_AppDataW, + MAKEINTRESOURCEW(IDS_APPDATA) + }, + { /* 0x24 - CSIDL_WINDOWS */ + CSIDL_Type_WindowsPath, + NULL, + NULL + }, + { /* 0x25 - CSIDL_SYSTEM */ + CSIDL_Type_SystemPath, + NULL, + NULL + }, + { /* 0x26 - CSIDL_PROGRAM_FILES */ + CSIDL_Type_CurrVer, + ProgramFilesDirW, + MAKEINTRESOURCEW(IDS_PROGRAM_FILES) + }, + { /* 0x27 - CSIDL_MYPICTURES */ + CSIDL_Type_User, + My_PicturesW, + MAKEINTRESOURCEW(IDS_MYPICTURES) + }, + { /* 0x28 - CSIDL_PROFILE */ + CSIDL_Type_User, + NULL, + NULL + }, + { /* 0x29 - CSIDL_SYSTEMX86 */ + CSIDL_Type_NonExistent, + NULL, + NULL + }, + { /* 0x2a - CSIDL_PROGRAM_FILESX86 */ + CSIDL_Type_NonExistent, + NULL, + NULL + }, + { /* 0x2b - CSIDL_PROGRAM_FILES_COMMON */ + CSIDL_Type_CurrVer, + CommonFilesDirW, + MAKEINTRESOURCEW(IDS_PROGRAM_FILES_COMMON) + }, + { /* 0x2c - CSIDL_PROGRAM_FILES_COMMONX86 */ + CSIDL_Type_NonExistent, + NULL, + NULL + }, + { /* 0x2d - CSIDL_COMMON_TEMPLATES */ + CSIDL_Type_AllUsers, + Common_TemplatesW, + MAKEINTRESOURCEW(IDS_TEMPLATES) + }, + { /* 0x2e - CSIDL_COMMON_DOCUMENTS */ + CSIDL_Type_AllUsers, + Common_DocumentsW, + MAKEINTRESOURCEW(IDS_COMMON_DOCUMENTS) + }, + { /* 0x2f - CSIDL_COMMON_ADMINTOOLS */ + CSIDL_Type_AllUsers, + Common_Administrative_ToolsW, + MAKEINTRESOURCEW(IDS_ADMINTOOLS) + }, + { /* 0x30 - CSIDL_ADMINTOOLS */ + CSIDL_Type_User, + Administrative_ToolsW, + MAKEINTRESOURCEW(IDS_ADMINTOOLS) + }, + { /* 0x31 - CSIDL_CONNECTIONS */ + CSIDL_Type_Disallowed, + NULL, + NULL + }, + { /* 0x32 - unassigned */ + CSIDL_Type_Disallowed, + NULL, + NULL + }, + { /* 0x33 - unassigned */ + CSIDL_Type_Disallowed, + NULL, + NULL + }, + { /* 0x34 - unassigned */ + CSIDL_Type_Disallowed, + NULL, + NULL + }, + { /* 0x35 - CSIDL_COMMON_MUSIC */ + CSIDL_Type_AllUsers, + CommonMusicW, + MAKEINTRESOURCEW(IDS_COMMON_MUSIC) + }, + { /* 0x36 - CSIDL_COMMON_PICTURES */ + CSIDL_Type_AllUsers, + CommonPicturesW, + MAKEINTRESOURCEW(IDS_COMMON_PICTURES) + }, + { /* 0x37 - CSIDL_COMMON_VIDEO */ + CSIDL_Type_AllUsers, + CommonVideoW, + MAKEINTRESOURCEW(IDS_COMMON_VIDEO) + }, + { /* 0x38 - CSIDL_RESOURCES */ + CSIDL_Type_WindowsPath, + NULL, + ResourcesW + }, + { /* 0x39 - CSIDL_RESOURCES_LOCALIZED */ + CSIDL_Type_NonExistent, + NULL, + NULL + }, + { /* 0x3a - CSIDL_COMMON_OEM_LINKS */ + CSIDL_Type_NonExistent, + NULL, + NULL + }, + { /* 0x3b - CSIDL_CDBURN_AREA */ + CSIDL_Type_User, + CD_BurningW, + MAKEINTRESOURCEW(IDS_CDBURN_AREA) + }, + { /* 0x3c unassigned */ + CSIDL_Type_Disallowed, + NULL, + NULL + }, + { /* 0x3d - CSIDL_COMPUTERSNEARME */ + CSIDL_Type_Disallowed, /* FIXME */ + NULL, + NULL + }, + { /* 0x3e - CSIDL_PROFILES */ + CSIDL_Type_Disallowed, /* oddly, this matches WinXP */ + NULL, + NULL + } +}; + +/* Gets the value named value from the registry key + * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders + * (or from rootKey\userPrefix\... if userPrefix is not NULL) into path, which + * is assumed to be MAX_PATH WCHARs in length. + * If it exists, expands the value and writes the expanded value to + * rootKey\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders + * Returns successful error code if the value was retrieved from the registry, + * and a failure otherwise. + */ +static HRESULT _SHGetUserShellFolderPath(HKEY rootKey, LPCWSTR userPrefix, + LPCWSTR value, LPWSTR path) +{ + HRESULT hr; + WCHAR shellFolderPath[MAX_PATH], userShellFolderPath[MAX_PATH]; + LPCWSTR pShellFolderPath, pUserShellFolderPath; + DWORD dwDisp, dwType, dwPathLen; + HKEY userShellFolderKey, shellFolderKey; + + TRACE("%p,%s,%s,%p\n",rootKey, debugstr_w(userPrefix), debugstr_w(value), + path); + + if (userPrefix) + { + wcscpy(shellFolderPath, userPrefix); + PathAddBackslashW(shellFolderPath); + wcscat(shellFolderPath, szSHFolders); + pShellFolderPath = shellFolderPath; + wcscpy(userShellFolderPath, userPrefix); + PathAddBackslashW(userShellFolderPath); + wcscat(userShellFolderPath, szSHUserFolders); + pUserShellFolderPath = userShellFolderPath; + } + else + { + pUserShellFolderPath = szSHUserFolders; + pShellFolderPath = szSHFolders; + } + + if (RegCreateKeyExW(rootKey, pShellFolderPath, 0, NULL, 0, KEY_SET_VALUE, + NULL, &shellFolderKey, &dwDisp)) + { + TRACE("Failed to create %s\n", debugstr_w(pShellFolderPath)); + return E_FAIL; + } + if (RegCreateKeyExW(rootKey, pUserShellFolderPath, 0, NULL, 0, + KEY_QUERY_VALUE, NULL, &userShellFolderKey, &dwDisp)) + { + TRACE("Failed to create %s\n", + debugstr_w(pUserShellFolderPath)); + RegCloseKey(shellFolderKey); + return E_FAIL; + } + + dwPathLen = MAX_PATH * sizeof(WCHAR); + + if (!RegQueryValueExW(userShellFolderKey, value, NULL, &dwType, + (LPBYTE)path, &dwPathLen) && (dwType == REG_EXPAND_SZ || dwType == REG_SZ)) + { + LONG ret; + + dwPathLen /= sizeof(WCHAR); + + path[dwPathLen] = '\0'; + if (dwType == REG_EXPAND_SZ && path[0] == '%') + { + WCHAR szTemp[MAX_PATH]; + + dwPathLen = ExpandEnvironmentStringsW(path, szTemp, MAX_PATH); + lstrcpynW(path, szTemp, dwPathLen); + } + + ret = RegSetValueExW(shellFolderKey, value, 0, REG_SZ, (LPBYTE)path, dwPathLen * sizeof(WCHAR)); + if (ret != ERROR_SUCCESS) + hr = HRESULT_FROM_WIN32(ret); + else + hr = S_OK; + } + else + hr = E_FAIL; + + RegCloseKey(shellFolderKey); + RegCloseKey(userShellFolderKey); + TRACE("returning 0x%08x\n", hr); + return hr; +} + +/* Gets a 'semi-expanded' default value of the CSIDL with index folder into + * pszPath, based on the entries in CSIDL_Data. By semi-expanded, I mean: + * - The entry's szDefaultPath may be either a string value or an integer + * resource identifier. In the latter case, the string value of the resource + * is written. + * - Depending on the entry's type, the path may begin with an (unexpanded) + * environment variable name. The caller is responsible for expanding + * environment strings if so desired. + * The types that are prepended with environment variables are: + * CSIDL_Type_User: %USERPROFILE% + * CSIDL_Type_AllUsers: %ALLUSERSPROFILE% + * CSIDL_Type_CurrVer: %SystemDrive% + * (Others might make sense too, but as yet are unneeded.) + */ +static HRESULT _SHGetDefaultValue(BYTE folder, LPWSTR pszPath) +{ + DWORD dwSize; + HRESULT hr; + HKEY hKey; + WCHAR resourcePath[MAX_PATH]; + LPCWSTR pDefaultPath = NULL; + + TRACE("0x%02x,%p\n", folder, pszPath); + + if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0])) + return E_INVALIDARG; + if (!pszPath) + return E_INVALIDARG; + + + if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + /* FIXME assume MAX_PATH size */ + dwSize = MAX_PATH * sizeof(WCHAR); + if (RegQueryValueExW(hKey, CSIDL_Data[folder].szValueName, NULL, NULL, (LPBYTE)pszPath, &dwSize) == ERROR_SUCCESS) + { + RegCloseKey(hKey); + return S_OK; + } + RegCloseKey(hKey); + } + + if (CSIDL_Data[folder].szDefaultPath && + IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath)) + { + if (LoadStringW(shell32_hInstance, + LOWORD(CSIDL_Data[folder].szDefaultPath), resourcePath, MAX_PATH)) + { + hr = S_OK; + pDefaultPath = resourcePath; + } + else + { + FIXME("(%d,%s), LoadString failed, missing translation?\n", folder, + debugstr_w(pszPath)); + hr = E_FAIL; + } + } + else + { + hr = S_OK; + pDefaultPath = CSIDL_Data[folder].szDefaultPath; + } + if (SUCCEEDED(hr)) + { + switch (CSIDL_Data[folder].type) + { + case CSIDL_Type_User: + wcscpy(pszPath, UserProfileW); + break; + case CSIDL_Type_AllUsers: + wcscpy(pszPath, AllUsersProfileW); + break; + case CSIDL_Type_CurrVer: + wcscpy(pszPath, SystemDriveW); + break; + default: + ; /* no corresponding env. var, do nothing */ + } + if (pDefaultPath) + { + PathAddBackslashW(pszPath); + wcscat(pszPath, pDefaultPath); + } + } + TRACE("returning 0x%08x\n", hr); + return hr; +} + +/* Gets the (unexpanded) value of the folder with index folder into pszPath. + * The folder's type is assumed to be CSIDL_Type_CurrVer. Its default value + * can be overridden in the HKLM\\szCurrentVersion key. + * If dwFlags has SHGFP_TYPE_DEFAULT set or if the value isn't overridden in + * the registry, uses _SHGetDefaultValue to get the value. + */ +static HRESULT _SHGetCurrentVersionPath(DWORD dwFlags, BYTE folder, + LPWSTR pszPath) +{ + HRESULT hr; + + TRACE("0x%08x,0x%02x,%p\n", dwFlags, folder, pszPath); + + if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0])) + return E_INVALIDARG; + if (CSIDL_Data[folder].type != CSIDL_Type_CurrVer) + return E_INVALIDARG; + if (!pszPath) + return E_INVALIDARG; + + if (dwFlags & SHGFP_TYPE_DEFAULT) + hr = _SHGetDefaultValue(folder, pszPath); + else + { + HKEY hKey; + DWORD dwDisp; + + if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szCurrentVersion, 0, + NULL, 0, KEY_ALL_ACCESS, NULL, &hKey, &dwDisp)) + hr = E_FAIL; + else + { + DWORD dwType, dwPathLen = MAX_PATH * sizeof(WCHAR); + + if (RegQueryValueExW(hKey, CSIDL_Data[folder].szValueName, NULL, + &dwType, (LPBYTE)pszPath, &dwPathLen) || + (dwType != REG_SZ && dwType != REG_EXPAND_SZ)) + { + hr = _SHGetDefaultValue(folder, pszPath); + dwType = REG_EXPAND_SZ; + RegSetValueExW(hKey, CSIDL_Data[folder].szValueName, 0, dwType, + (LPBYTE)pszPath, (wcslen(pszPath)+1)*sizeof(WCHAR)); + } + else + { + pszPath[dwPathLen / sizeof(WCHAR)] = '\0'; + hr = S_OK; + } + RegCloseKey(hKey); + } + } + TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath)); + return hr; +} + +/* Gets the user's path (unexpanded) for the CSIDL with index folder: + * If SHGFP_TYPE_DEFAULT is set, calls _SHGetDefaultValue for it. Otherwise + * calls _SHGetUserShellFolderPath for it. Where it looks depends on hToken: + * - if hToken is -1, looks in HKEY_USERS\.Default + * - otherwise looks first in HKEY_CURRENT_USER, followed by HKEY_LOCAL_MACHINE + * if HKEY_CURRENT_USER doesn't contain any entries. If both fail, finally + * calls _SHGetDefaultValue for it. + */ +static HRESULT _SHGetUserProfilePath(HANDLE hToken, DWORD dwFlags, BYTE folder, + LPWSTR pszPath) +{ + HRESULT hr; + + TRACE("%p,0x%08x,0x%02x,%p\n", hToken, dwFlags, folder, pszPath); + + if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0])) + return E_INVALIDARG; + + if (CSIDL_Data[folder].type != CSIDL_Type_User) + return E_INVALIDARG; + + if (!pszPath) + return E_INVALIDARG; + + if (dwFlags & SHGFP_TYPE_DEFAULT) + { + hr = _SHGetDefaultValue(folder, pszPath); + } + else + { + LPWSTR userPrefix; + HKEY hRootKey; + + if (hToken == (HANDLE)-1) + { + /* Get the folder of the default user */ + hRootKey = HKEY_USERS; + userPrefix = (LPWSTR)DefaultW; + } + else if(!hToken) + { + /* Get the folder of the current user */ + hRootKey = HKEY_CURRENT_USER; + userPrefix = NULL; + } + else + { + /* Get the folder of the specified user */ + DWORD InfoLength; + PTOKEN_USER UserInfo; + + hRootKey = HKEY_USERS; + + GetTokenInformation(hToken, TokenUser, NULL, 0, &InfoLength); + UserInfo = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), 0, InfoLength); + + if(!GetTokenInformation(hToken, TokenUser, UserInfo, InfoLength, &InfoLength)) + { + WARN("GetTokenInformation failed for %x!\n", hToken); + HeapFree(GetProcessHeap(), 0, UserInfo); + return E_FAIL; + } + + if(!ConvertSidToStringSidW(UserInfo->User.Sid, &userPrefix)) + { + WARN("ConvertSidToStringSidW failed for %x!\n", hToken); + HeapFree(GetProcessHeap(), 0, UserInfo); + return E_FAIL; + } + + HeapFree(GetProcessHeap(), 0, UserInfo); + } + + hr = _SHGetUserShellFolderPath(hRootKey, userPrefix, CSIDL_Data[folder].szValueName, pszPath); + + /* Free the memory allocated by ConvertSidToStringSidW */ + if(hToken && hToken != (HANDLE)-1) + LocalFree(userPrefix); + + if (FAILED(hr) && hRootKey != HKEY_LOCAL_MACHINE) + hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, CSIDL_Data[folder].szValueName, pszPath); + + if (FAILED(hr)) + hr = _SHGetDefaultValue(folder, pszPath); + } + + TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath)); + return hr; +} + +/* Gets the (unexpanded) path for the CSIDL with index folder. If dwFlags has + * SHGFP_TYPE_DEFAULT set, calls _SHGetDefaultValue. Otherwise calls + * _SHGetUserShellFolderPath for it, looking only in HKEY_LOCAL_MACHINE. + * If this fails, falls back to _SHGetDefaultValue. + */ +static HRESULT _SHGetAllUsersProfilePath(DWORD dwFlags, BYTE folder, + LPWSTR pszPath) +{ + HRESULT hr; + + TRACE("0x%08x,0x%02x,%p\n", dwFlags, folder, pszPath); + + if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0])) + return E_INVALIDARG; + if (CSIDL_Data[folder].type != CSIDL_Type_AllUsers) + return E_INVALIDARG; + if (!pszPath) + return E_INVALIDARG; + + if (dwFlags & SHGFP_TYPE_DEFAULT) + hr = _SHGetDefaultValue(folder, pszPath); + else + { + hr = _SHGetUserShellFolderPath(HKEY_LOCAL_MACHINE, NULL, + CSIDL_Data[folder].szValueName, pszPath); + if (FAILED(hr)) + hr = _SHGetDefaultValue(folder, pszPath); + } + TRACE("returning 0x%08x (output path is %s)\n", hr, debugstr_w(pszPath)); + return hr; +} + +/************************************************************************* + * SHGetFolderPathW [SHELL32.@] + * + * Convert nFolder to path. + * + * RETURNS + * Success: S_OK + * Failure: standard HRESULT error codes. + * + * NOTES + * Most values can be overridden in either + * HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders + * or in the same location in HKLM. + * The "Shell Folders" registry key was used in NT4 and earlier systems. + * Beginning with Windows 2000, the "User Shell Folders" key is used, so + * changes made to it are made to the former key too. This synchronization is + * done on-demand: not until someone requests the value of one of these paths + * (by calling one of the SHGet functions) is the value synchronized. + * Furthermore, the HKCU paths take precedence over the HKLM paths. + */ +HRESULT WINAPI SHGetFolderPathW( + HWND hwndOwner, /* [I] owner window */ + int nFolder, /* [I] CSIDL identifying the folder */ + HANDLE hToken, /* [I] access token */ + DWORD dwFlags, /* [I] which path to return */ + LPWSTR pszPath) /* [O] converted path */ +{ + HRESULT hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, NULL, pszPath); + if(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr) + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + return hr; +} + +HRESULT WINAPI SHGetFolderPathAndSubDirA( + HWND hwndOwner, /* [I] owner window */ + int nFolder, /* [I] CSIDL identifying the folder */ + HANDLE hToken, /* [I] access token */ + DWORD dwFlags, /* [I] which path to return */ + LPCSTR pszSubPath, /* [I] sub directory of the specified folder */ + LPSTR pszPath) /* [O] converted path */ +{ + int length; + HRESULT hr = S_OK; + LPWSTR pszSubPathW = NULL; + LPWSTR pszPathW = NULL; + TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW)); + + if(pszPath) { + pszPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); + if(!pszPathW) { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + } + TRACE("%08x,%08x,%s\n",nFolder, dwFlags, debugstr_w(pszSubPathW)); + + /* SHGetFolderPathAndSubDirW does not distinguish if pszSubPath isn't + * set (null), or an empty string.therefore call it without the parameter set + * if pszSubPath is an empty string + */ + if (pszSubPath && pszSubPath[0]) { + length = MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, NULL, 0); + pszSubPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, length * sizeof(WCHAR)); + if(!pszSubPathW) { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + MultiByteToWideChar(CP_ACP, 0, pszSubPath, -1, pszSubPathW, length); + } + + hr = SHGetFolderPathAndSubDirW(hwndOwner, nFolder, hToken, dwFlags, pszSubPathW, pszPathW); + + if (SUCCEEDED(hr) && pszPath) + WideCharToMultiByte(CP_ACP, 0, pszPathW, -1, pszPath, MAX_PATH, NULL, NULL); + +cleanup: + HeapFree(GetProcessHeap(), 0, pszPathW); + HeapFree(GetProcessHeap(), 0, pszSubPathW); + return hr; +} + +HRESULT WINAPI SHGetFolderPathAndSubDirW( + HWND hwndOwner, /* [I] owner window */ + int nFolder, /* [I] CSIDL identifying the folder */ + HANDLE hToken, /* [I] access token */ + DWORD dwFlags, /* [I] which path to return */ + LPCWSTR pszSubPath,/* [I] sub directory of the specified folder */ + LPWSTR pszPath) /* [O] converted path */ +{ + HRESULT hr; + WCHAR szBuildPath[MAX_PATH], szTemp[MAX_PATH]; + DWORD folder = nFolder & CSIDL_FOLDER_MASK; //FIXME + CSIDL_Type type; + int ret; + + TRACE("%p,%p,nFolder=0x%04x,%s\n", hwndOwner,pszPath,nFolder,debugstr_w(pszSubPath)); + + /* Windows always NULL-terminates the resulting path regardless of success + * or failure, so do so first + */ + if (pszPath) + *pszPath = '\0'; + + if (folder >= sizeof(CSIDL_Data) / sizeof(CSIDL_Data[0])) + return E_INVALIDARG; + if ((SHGFP_TYPE_CURRENT != dwFlags) && (SHGFP_TYPE_DEFAULT != dwFlags)) + return E_INVALIDARG; + szTemp[0] = 0; + type = CSIDL_Data[folder].type; + switch (type) + { + case CSIDL_Type_Disallowed: + hr = E_INVALIDARG; + break; + case CSIDL_Type_NonExistent: + hr = S_FALSE; + break; + case CSIDL_Type_WindowsPath: + GetWindowsDirectoryW(szTemp, MAX_PATH); + if (CSIDL_Data[folder].szDefaultPath && + !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) && + *CSIDL_Data[folder].szDefaultPath) + { + PathAddBackslashW(szTemp); + wcscat(szTemp, CSIDL_Data[folder].szDefaultPath); + } + hr = S_OK; + break; + case CSIDL_Type_SystemPath: + GetSystemDirectoryW(szTemp, MAX_PATH); + if (CSIDL_Data[folder].szDefaultPath && + !IS_INTRESOURCE(CSIDL_Data[folder].szDefaultPath) && + *CSIDL_Data[folder].szDefaultPath) + { + PathAddBackslashW(szTemp); + wcscat(szTemp, CSIDL_Data[folder].szDefaultPath); + } + hr = S_OK; + break; + case CSIDL_Type_CurrVer: + hr = _SHGetCurrentVersionPath(dwFlags, folder, szTemp); + break; + case CSIDL_Type_User: + hr = _SHGetUserProfilePath(hToken, dwFlags, folder, szTemp); + break; + case CSIDL_Type_AllUsers: + hr = _SHGetAllUsersProfilePath(dwFlags, folder, szTemp); + break; + default: + FIXME("bogus type %d, please fix\n", type); + hr = E_INVALIDARG; + break; + } + + /* Expand environment strings if necessary */ + if (*szTemp == '%') + { + DWORD ExpandRet = ExpandEnvironmentStringsW(szTemp, szBuildPath, MAX_PATH); + + if (ExpandRet > MAX_PATH) + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + else if (ExpandRet == 0) + hr = HRESULT_FROM_WIN32(GetLastError()); + else + hr = S_OK; + } + else + { + wcscpy(szBuildPath, szTemp); + } + + if (FAILED(hr)) goto end; + + if(pszSubPath) { + /* make sure the new path does not exceed th bufferlength + * rememebr to backslash and the termination */ + if(MAX_PATH < (wcslen(szBuildPath) + wcslen(pszSubPath) + 2)) { + hr = HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE); + goto end; + } + PathAppendW(szBuildPath, pszSubPath); + PathRemoveBackslashW(szBuildPath); + } + /* Copy the path if it's available before we might return */ + if (SUCCEEDED(hr) && pszPath) + wcscpy(pszPath, szBuildPath); + + /* if we don't care about existing directories we are ready */ + if(nFolder & CSIDL_FLAG_DONT_VERIFY) goto end; + + if (PathFileExistsW(szBuildPath)) goto end; + + /* not existing but we are not allowed to create it. The return value + * is verified against shell32 version 6.0. + */ + if (!(nFolder & CSIDL_FLAG_CREATE)) + { + hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); + goto end; + } + + /* create directory/directories */ + ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, NULL); + if (ret && ret != ERROR_ALREADY_EXISTS) + { + ERR("Failed to create directory %s.\n", debugstr_w(szBuildPath)); + hr = E_FAIL; + goto end; + } + + TRACE("Created missing system directory %s\n", debugstr_w(szBuildPath)); +end: + TRACE("returning 0x%08x (final path is %s)\n", hr, debugstr_w(szBuildPath)); + return hr; +} + +/************************************************************************* + * SHGetFolderPathA [SHELL32.@] + * + * See SHGetFolderPathW. + */ +HRESULT WINAPI SHGetFolderPathA( + HWND hwndOwner, + int nFolder, + HANDLE hToken, + DWORD dwFlags, + LPSTR pszPath) +{ + WCHAR szTemp[MAX_PATH]; + HRESULT hr; + + TRACE("%p,%p,nFolder=0x%04x\n",hwndOwner,pszPath,nFolder); + + if (pszPath) + *pszPath = '\0'; + hr = SHGetFolderPathW(hwndOwner, nFolder, hToken, dwFlags, szTemp); + if (SUCCEEDED(hr) && pszPath) + WideCharToMultiByte(CP_ACP, 0, szTemp, -1, pszPath, MAX_PATH, NULL, + NULL); + + return hr; +} + +/* For each folder in folders, if its value has not been set in the registry, + * calls _SHGetUserProfilePath or _SHGetAllUsersProfilePath (depending on the + * folder's type) to get the unexpanded value first. + * Writes the unexpanded value to User Shell Folders, and queries it with + * SHGetFolderPathW to force the creation of the directory if it doesn't + * already exist. SHGetFolderPathW also returns the expanded value, which + * this then writes to Shell Folders. + */ +static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, + LPCWSTR szUserShellFolderPath, LPCWSTR szShellFolderPath, const UINT folders[], + UINT foldersLen) +{ + UINT i; + WCHAR path[MAX_PATH]; + HRESULT hr = S_OK; + HKEY hUserKey = NULL, hKey = NULL; + DWORD dwDisp, dwType, dwPathLen; + LONG ret; + + TRACE("%p,%p,%s,%p,%u\n", hRootKey, hToken, + debugstr_w(szUserShellFolderPath), folders, foldersLen); + + ret = RegCreateKeyExW(hRootKey, szUserShellFolderPath, 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &hUserKey, &dwDisp); + if (ret) + hr = HRESULT_FROM_WIN32(ret); + else + { + ret = RegCreateKeyExW(hRootKey, szShellFolderPath, 0, NULL, 0, + KEY_ALL_ACCESS, NULL, &hKey, &dwDisp); + if (ret) + hr = HRESULT_FROM_WIN32(ret); + } + for (i = 0; SUCCEEDED(hr) && i < foldersLen; i++) + { + dwPathLen = MAX_PATH * sizeof(WCHAR); + if (RegQueryValueExW(hUserKey, CSIDL_Data[folders[i]].szValueName, NULL, + &dwType, (LPBYTE)path, &dwPathLen) || (dwType != REG_SZ && + dwType != REG_EXPAND_SZ)) + { + *path = '\0'; + if (CSIDL_Data[folders[i]].type == CSIDL_Type_User) + _SHGetUserProfilePath(hToken, SHGFP_TYPE_DEFAULT, folders[i], + path); + else if (CSIDL_Data[folders[i]].type == CSIDL_Type_AllUsers) + _SHGetAllUsersProfilePath(SHGFP_TYPE_DEFAULT, folders[i], path); + else if (CSIDL_Data[folders[i]].type == CSIDL_Type_WindowsPath) + GetWindowsDirectoryW(path, MAX_PATH); + else + hr = E_FAIL; + if (*path) + { + ret = RegSetValueExW(hUserKey, + CSIDL_Data[folders[i]].szValueName, 0, REG_EXPAND_SZ, + (LPBYTE)path, (wcslen(path) + 1) * sizeof(WCHAR)); + if (ret) + hr = HRESULT_FROM_WIN32(ret); + else + { + hr = SHGetFolderPathW(NULL, folders[i] | CSIDL_FLAG_CREATE, + hToken, SHGFP_TYPE_DEFAULT, path); + ret = RegSetValueExW(hKey, + CSIDL_Data[folders[i]].szValueName, 0, REG_SZ, + (LPBYTE)path, (wcslen(path) + 1) * sizeof(WCHAR)); + if (ret) + hr = HRESULT_FROM_WIN32(ret); + } + } + } + } + if (hUserKey) + RegCloseKey(hUserKey); + if (hKey) + RegCloseKey(hKey); + + TRACE("returning 0x%08x\n", hr); + return hr; +} + +static HRESULT _SHRegisterUserShellFolders(BOOL bDefault) +{ + static const UINT folders[] = { + CSIDL_PROGRAMS, + CSIDL_PERSONAL, + CSIDL_FAVORITES, + CSIDL_APPDATA, + CSIDL_STARTUP, + CSIDL_RECENT, + CSIDL_SENDTO, + CSIDL_STARTMENU, + CSIDL_MYMUSIC, + CSIDL_MYVIDEO, + CSIDL_DESKTOPDIRECTORY, + CSIDL_NETHOOD, + CSIDL_TEMPLATES, + CSIDL_PRINTHOOD, + CSIDL_LOCAL_APPDATA, + CSIDL_INTERNET_CACHE, + CSIDL_COOKIES, + CSIDL_HISTORY, + CSIDL_MYPICTURES, + CSIDL_FONTS + }; + WCHAR userShellFolderPath[MAX_PATH], shellFolderPath[MAX_PATH]; + LPCWSTR pUserShellFolderPath, pShellFolderPath; + HRESULT hr = S_OK; + HKEY hRootKey; + HANDLE hToken; + + TRACE("%s\n", bDefault ? "TRUE" : "FALSE"); + if (bDefault) + { + hToken = (HANDLE)-1; + hRootKey = HKEY_USERS; + wcscpy(userShellFolderPath, DefaultW); + PathAddBackslashW(userShellFolderPath); + wcscat(userShellFolderPath, szSHUserFolders); + pUserShellFolderPath = userShellFolderPath; + wcscpy(shellFolderPath, DefaultW); + PathAddBackslashW(shellFolderPath); + wcscat(shellFolderPath, szSHFolders); + pShellFolderPath = shellFolderPath; + } + else + { + hToken = NULL; + hRootKey = HKEY_CURRENT_USER; + pUserShellFolderPath = szSHUserFolders; + pShellFolderPath = szSHFolders; + } + + hr = _SHRegisterFolders(hRootKey, hToken, pUserShellFolderPath, + pShellFolderPath, folders, sizeof(folders) / sizeof(folders[0])); + TRACE("returning 0x%08x\n", hr); + return hr; +} + +static HRESULT _SHRegisterCommonShellFolders(void) +{ + static const UINT folders[] = { + CSIDL_COMMON_STARTMENU, + CSIDL_COMMON_PROGRAMS, + CSIDL_COMMON_STARTUP, + CSIDL_COMMON_DESKTOPDIRECTORY, + CSIDL_COMMON_FAVORITES, + CSIDL_COMMON_APPDATA, + CSIDL_COMMON_TEMPLATES, + CSIDL_COMMON_DOCUMENTS, + }; + HRESULT hr; + + TRACE("\n"); + hr = _SHRegisterFolders(HKEY_LOCAL_MACHINE, NULL, szSHUserFolders, + szSHFolders, folders, sizeof(folders) / sizeof(folders[0])); + TRACE("returning 0x%08x\n", hr); + return hr; +} + +/****************************************************************************** + * _SHAppendToUnixPath [Internal] + * + * Helper function for _SHCreateSymbolicLinks. Appends pwszSubPath (or the + * corresponding resource, if IS_INTRESOURCE) to the unix base path 'szBasePath' + * and replaces backslashes with slashes. + * + * PARAMS + * szBasePath [IO] The unix base path, which will be appended to (CP_UNXICP). + * pwszSubPath [I] Sub-path or resource id (use MAKEINTRESOURCEW). + * + * RETURNS + * Success: TRUE, + * Failure: FALSE + */ +static BOOL __inline _SHAppendToUnixPath(char *szBasePath, LPCWSTR pwszSubPath) { + WCHAR wszSubPath[MAX_PATH]; + int cLen = strlen(szBasePath); + char *pBackslash; + + if (IS_INTRESOURCE(pwszSubPath)) { + if (!LoadStringW(shell32_hInstance, LOWORD(pwszSubPath), wszSubPath, MAX_PATH)) { + /* Fall back to hard coded defaults. */ + switch (LOWORD(pwszSubPath)) { + case IDS_PERSONAL: + wcscpy(wszSubPath, PersonalW); + break; + case IDS_MYMUSIC: + wcscpy(wszSubPath, My_MusicW); + break; + case IDS_MYPICTURES: + wcscpy(wszSubPath, My_PicturesW); + break; + case IDS_MYVIDEO: + wcscpy(wszSubPath, My_VideoW); + break; + default: + ERR("LoadString(%d) failed!\n", LOWORD(pwszSubPath)); + return FALSE; + } + } + } else { + wcscpy(wszSubPath, pwszSubPath); + } + + if (szBasePath[cLen-1] != '/') szBasePath[cLen++] = '/'; + + if (!WideCharToMultiByte(CP_ACP, 0, wszSubPath, -1, szBasePath + cLen, + FILENAME_MAX - cLen, NULL, NULL)) + { + return FALSE; + } + + pBackslash = szBasePath + cLen; + while ((pBackslash = strchr(pBackslash, '\\'))) *pBackslash = '/'; + + return TRUE; +} +#if 0 +/****************************************************************************** + * _SHCreateSymbolicLinks [Internal] + * + * Sets up symbol links for various shell folders to point into the users home + * directory. We do an educated guess about what the user would probably want: + * - If there is a 'My Documents' directory in $HOME, the user probably wants + * wine's 'My Documents' to point there. Furthermore, we imply that the user + * is a Windows lover and has no problem with wine creating 'My Pictures', + * 'My Music' and 'My Video' subfolders under '$HOME/My Documents', if those + * do not already exits. We put appropriate symbolic links in place for those, + * too. + * - If there is no 'My Documents' directory in $HOME, we let 'My Documents' + * point directly to $HOME. We assume the user to be a unix hacker who does not + * want wine to create anything anywhere besides the .wine directory. So, if + * there already is a 'My Music' directory in $HOME, we symlink the 'My Music' + * shell folder to it. But if not, we symlink it to $HOME directly. The same + * holds fo 'My Pictures' and 'My Video'. + * - The Desktop shell folder is symlinked to '$HOME/Desktop', if that does + * exists and left alone if not. + * ('My Music',... above in fact means LoadString(IDS_MYMUSIC)) + */ +static void _SHCreateSymbolicLinks(void) +{ + UINT aidsMyStuff[] = { IDS_MYPICTURES, IDS_MYVIDEO, IDS_MYMUSIC }, i; + int acsidlMyStuff[] = { CSIDL_MYPICTURES, CSIDL_MYVIDEO, CSIDL_MYMUSIC }; + WCHAR wszTempPath[MAX_PATH]; + char szPersonalTarget[FILENAME_MAX], *pszPersonal; + char szMyStuffTarget[FILENAME_MAX], *pszMyStuff; + char szDesktopTarget[FILENAME_MAX], *pszDesktop; + struct stat statFolder; + const char *pszHome; + HRESULT hr; + + /* Create all necessary profile sub-dirs up to 'My Documents' and get the unix path. */ + hr = SHGetFolderPathW(NULL, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL, + SHGFP_TYPE_DEFAULT, wszTempPath); + if (FAILED(hr)) return; + pszPersonal = wine_get_unix_file_name(wszTempPath); + if (!pszPersonal) return; + + pszHome = getenv("HOME"); + if (pszHome && !stat(pszHome, &statFolder) && S_ISDIR(statFolder.st_mode)) { + strcpy(szPersonalTarget, pszHome); + if (_SHAppendToUnixPath(szPersonalTarget, MAKEINTRESOURCEW(IDS_PERSONAL)) && + !stat(szPersonalTarget, &statFolder) && S_ISDIR(statFolder.st_mode)) + { + /* '$HOME/My Documents' exists. Create 'My Pictures', 'My Videos' and + * 'My Music' subfolders or fail silently if they already exist. */ + for (i = 0; i < sizeof(aidsMyStuff)/sizeof(aidsMyStuff[0]); i++) { + strcpy(szMyStuffTarget, szPersonalTarget); + if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) + mkdir(szMyStuffTarget); + } + } + else + { + /* '$HOME/My Documents' doesn't exists, but '$HOME' does. */ + strcpy(szPersonalTarget, pszHome); + } + + /* Replace 'My Documents' directory with a symlink of fail silently if not empty. */ + rmdir(pszPersonal); + symlink(szPersonalTarget, pszPersonal); + } + else + { + /* '$HOME' doesn't exist. Create 'My Pictures', 'My Videos' and 'My Music' subdirs + * in '%USERPROFILE%\\My Documents' or fail silently if they already exist. */ + strcpy(szPersonalTarget, pszPersonal); + for (i = 0; i < sizeof(aidsMyStuff)/sizeof(aidsMyStuff[0]); i++) { + strcpy(szMyStuffTarget, szPersonalTarget); + if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i]))) + mkdir(szMyStuffTarget); + } + } + + /* Create symbolic links for 'My Pictures', 'My Video' and 'My Music'. */ + for (i=0; i < sizeof(aidsMyStuff)/sizeof(aidsMyStuff[0]); i++) { + /* Create the current 'My Whatever' folder and get it's unix path. */ + hr = SHGetFolderPathW(NULL, acsidlMyStuff[i]|CSIDL_FLAG_CREATE, NULL, + SHGFP_TYPE_DEFAULT, wszTempPath); + if (FAILED(hr)) continue; + pszMyStuff = wine_get_unix_file_name(wszTempPath); + if (!pszMyStuff) continue; + + strcpy(szMyStuffTarget, szPersonalTarget); + if (_SHAppendToUnixPath(szMyStuffTarget, MAKEINTRESOURCEW(aidsMyStuff[i])) && + !stat(szMyStuffTarget, &statFolder) && S_ISDIR(statFolder.st_mode)) + { + /* If there's a 'My Whatever' directory where 'My Documents' links to, link to it. */ + rmdir(pszMyStuff); + symlink(szMyStuffTarget, pszMyStuff); + } + else + { + /* Else link to where 'My Documents' itself links to. */ + rmdir(pszMyStuff); + symlink(szPersonalTarget, pszMyStuff); + } + HeapFree(GetProcessHeap(), 0, pszMyStuff); + } + + /* Last but not least, the Desktop folder */ + if (pszHome) + strcpy(szDesktopTarget, pszHome); + else + strcpy(szDesktopTarget, pszPersonal); + HeapFree(GetProcessHeap(), 0, pszPersonal); + + if (_SHAppendToUnixPath(szDesktopTarget, DesktopW) && + !stat(szDesktopTarget, &statFolder) && S_ISDIR(statFolder.st_mode)) + { + hr = SHGetFolderPathW(NULL, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, NULL, + SHGFP_TYPE_DEFAULT, wszTempPath); + if (SUCCEEDED(hr) && (pszDesktop = wine_get_unix_file_name(wszTempPath))) + { + rmdir(pszDesktop); + symlink(szDesktopTarget, pszDesktop); + HeapFree(GetProcessHeap(), 0, pszDesktop); + } + } +} +#endif + +/* Register the default values in the registry, as some apps seem to depend + * on their presence. The set registered was taken from Windows XP. + */ +HRESULT SHELL_RegisterShellFolders(void) +{ + HRESULT hr; + + /* Set up '$HOME' targeted symlinks for 'My Documents', 'My Pictures', + * 'My Video', 'My Music' and 'Desktop' in advance, so that the + * _SHRegister*ShellFolders() functions will find everything nice and clean + * and thus will not attempt to create them in the profile directory. */ +#if 0 + _SHCreateSymbolicLinks(); +#endif + + hr = _SHRegisterUserShellFolders(TRUE); + if (SUCCEEDED(hr)) + hr = _SHRegisterUserShellFolders(FALSE); + if (SUCCEEDED(hr)) + hr = _SHRegisterCommonShellFolders(); + return hr; +} + +/************************************************************************* + * SHGetSpecialFolderPathA [SHELL32.@] + */ +BOOL WINAPI SHGetSpecialFolderPathA ( + HWND hwndOwner, + LPSTR szPath, + int nFolder, + BOOL bCreate) +{ + return (SHGetFolderPathA( + hwndOwner, + nFolder + (bCreate ? CSIDL_FLAG_CREATE : 0), + NULL, + 0, + szPath)) == S_OK ? TRUE : FALSE; +} + +/************************************************************************* + * SHGetSpecialFolderPathW + */ +BOOL WINAPI SHGetSpecialFolderPathW ( + HWND hwndOwner, + LPWSTR szPath, + int nFolder, + BOOL bCreate) +{ + return (SHGetFolderPathW( + hwndOwner, + nFolder + (bCreate ? CSIDL_FLAG_CREATE : 0), + NULL, + 0, + szPath)) == S_OK ? TRUE : FALSE; +} + +/************************************************************************* + * SHGetFolderLocation [SHELL32.@] + * + * Gets the folder locations from the registry and creates a pidl. + * + * PARAMS + * hwndOwner [I] + * nFolder [I] CSIDL_xxxxx + * hToken [I] token representing user, or NULL for current user, or -1 for + * default user + * dwReserved [I] must be zero + * ppidl [O] PIDL of a special folder + * + * RETURNS + * Success: S_OK + * Failure: Standard OLE-defined error result, S_FALSE or E_INVALIDARG + * + * NOTES + * Creates missing reg keys and directories. + * Mostly forwards to SHGetFolderPathW, but a few values of nFolder return + * virtual folders that are handled here. + */ +HRESULT WINAPI SHGetFolderLocation( + HWND hwndOwner, + int nFolder, + HANDLE hToken, + DWORD dwReserved, + LPITEMIDLIST *ppidl) +{ + HRESULT hr = E_INVALIDARG; + + TRACE("%p 0x%08x %p 0x%08x %p\n", + hwndOwner, nFolder, hToken, dwReserved, ppidl); + + if (!ppidl) + return E_INVALIDARG; + if (dwReserved) + return E_INVALIDARG; + + /* The virtual folders' locations are not user-dependent */ + *ppidl = NULL; + switch (nFolder) + { + case CSIDL_DESKTOP: + *ppidl = _ILCreateDesktop(); + break; + + case CSIDL_PERSONAL: + *ppidl = _ILCreateMyDocuments(); + break; + + case CSIDL_INTERNET: + *ppidl = _ILCreateIExplore(); + break; + + case CSIDL_CONTROLS: + *ppidl = _ILCreateControlPanel(); + break; + + case CSIDL_PRINTERS: + *ppidl = _ILCreatePrinters(); + break; + + case CSIDL_BITBUCKET: + *ppidl = _ILCreateBitBucket(); + break; + + case CSIDL_DRIVES: + *ppidl = _ILCreateMyComputer(); + break; + + case CSIDL_NETWORK: + *ppidl = _ILCreateNetwork(); + break; + + default: + { + WCHAR szPath[MAX_PATH]; + + hr = SHGetFolderPathW(hwndOwner, nFolder, hToken, + SHGFP_TYPE_CURRENT, szPath); + if (SUCCEEDED(hr)) + { + DWORD attributes=0; + + TRACE("Value=%s\n", debugstr_w(szPath)); + hr = SHILCreateFromPathW(szPath, ppidl, &attributes); + } + else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) + { + /* unlike SHGetFolderPath, SHGetFolderLocation in shell32 + * version 6.0 returns E_FAIL for nonexistent paths + */ + hr = E_FAIL; + } + } + } + if(*ppidl) + hr = NOERROR; + + TRACE("-- (new pidl %p)\n",*ppidl); + return hr; +} + +/************************************************************************* + * SHGetSpecialFolderLocation [SHELL32.@] + * + * NOTES + * In NT5, SHGetSpecialFolderLocation needs the /Recent + * directory. + */ +HRESULT WINAPI SHGetSpecialFolderLocation( + HWND hwndOwner, + INT nFolder, + LPITEMIDLIST * ppidl) +{ + HRESULT hr = E_INVALIDARG; + + TRACE("(%p,0x%x,%p)\n", hwndOwner,nFolder,ppidl); + + if (!ppidl) + return E_INVALIDARG; + + hr = SHGetFolderLocation(hwndOwner, nFolder, NULL, 0, ppidl); + return hr; +} diff --git a/reactos/dll/win32/shell32/shellreg.cpp b/reactos/dll/win32/shell32/shellreg.cpp new file mode 100644 index 00000000000..b63eabc236d --- /dev/null +++ b/reactos/dll/win32/shell32/shellreg.cpp @@ -0,0 +1,144 @@ +/* + * Shell Registry Access + * + * Copyright 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/************************************************************************* + * SHRegOpenKeyA [SHELL32.506] + * + */ +EXTERN_C HRESULT WINAPI SHRegOpenKeyA( + HKEY hKey, + LPSTR lpSubKey, + PHKEY phkResult) +{ + TRACE("(%p, %s, %p)\n", hKey, debugstr_a(lpSubKey), phkResult); + return RegOpenKeyA(hKey, lpSubKey, phkResult); +} + +/************************************************************************* + * SHRegOpenKeyW [SHELL32.507] NT 4.0 + * + */ +EXTERN_C HRESULT WINAPI SHRegOpenKeyW ( + HKEY hkey, + LPCWSTR lpszSubKey, + PHKEY retkey) +{ + WARN("%p %s %p\n",hkey,debugstr_w(lpszSubKey),retkey); + return RegOpenKeyW( hkey, lpszSubKey, retkey ); +} + +/************************************************************************* + * SHRegQueryValueA [SHELL32.508] + * + */ +EXTERN_C HRESULT WINAPI SHRegQueryValueA(HKEY hkey, LPSTR lpSubKey, LPSTR lpValue, LPDWORD lpcbValue) +{ + TRACE("(%p %s %p %p)\n", hkey, debugstr_a(lpSubKey), lpValue, lpcbValue); + return RegQueryValueA(hkey, lpSubKey, lpValue, (LONG*)lpcbValue); +} + +/************************************************************************* + * SHRegQueryValueExA [SHELL32.509] + * + */ +EXTERN_C HRESULT WINAPI SHRegQueryValueExA( + HKEY hkey, + LPSTR lpValueName, + LPDWORD lpReserved, + LPDWORD lpType, + LPBYTE lpData, + LPDWORD lpcbData) +{ + TRACE("%p %s %p %p %p %p\n", hkey, lpValueName, lpReserved, lpType, lpData, lpcbData); + return RegQueryValueExA (hkey, lpValueName, lpReserved, lpType, lpData, lpcbData); +} + +/************************************************************************* + * SHRegQueryValueW [SHELL32.510] NT4.0 + * + */ +EXTERN_C HRESULT WINAPI SHRegQueryValueW( + HKEY hkey, + LPWSTR lpszSubKey, + LPWSTR lpszData, + LPDWORD lpcbData ) +{ + WARN("%p %s %p %p semi-stub\n", + hkey, debugstr_w(lpszSubKey), lpszData, lpcbData); + return RegQueryValueW( hkey, lpszSubKey, lpszData, (LONG*)lpcbData ); +} + +/************************************************************************* + * SHRegQueryValueExW [SHELL32.511] NT4.0 + * + * FIXME + * if the datatype REG_EXPAND_SZ then expand the string and change + * *pdwType to REG_SZ. + */ +EXTERN_C HRESULT WINAPI SHRegQueryValueExW ( + HKEY hkey, + LPWSTR pszValue, + LPDWORD pdwReserved, + LPDWORD pdwType, + LPVOID pvData, + LPDWORD pcbData) +{ + DWORD ret; + WARN("%p %s %p %p %p %p semi-stub\n", + hkey, debugstr_w(pszValue), pdwReserved, pdwType, pvData, pcbData); + ret = RegQueryValueExW ( hkey, pszValue, pdwReserved, pdwType, (LPBYTE)pvData, pcbData); + return ret; +} + +/************************************************************************* + * SHRegDeleteKeyA [SHELL32.?] + */ +HRESULT WINAPI SHRegDeleteKeyA( + HKEY hkey, + LPCSTR pszSubKey) +{ + FIXME("hkey=%p, %s\n", hkey, debugstr_a(pszSubKey)); + return 0; +} + +/************************************************************************* + * SHRegDeleteKeyW [SHELL32.512] + */ +EXTERN_C HRESULT WINAPI SHRegDeleteKeyW( + HKEY hkey, + LPCWSTR pszSubKey) +{ + FIXME("hkey=%p, %s\n", hkey, debugstr_w(pszSubKey)); + return 0; +} + +/************************************************************************* + * SHRegCloseKey [SHELL32.505] NT 4.0 + * + */ +EXTERN_C HRESULT WINAPI SHRegCloseKey (HKEY hkey) +{ + TRACE("%p\n",hkey); + return RegCloseKey( hkey ); +} diff --git a/reactos/dll/win32/shell32/shellstring.cpp b/reactos/dll/win32/shell32/shellstring.cpp new file mode 100644 index 00000000000..b283a00b3fa --- /dev/null +++ b/reactos/dll/win32/shell32/shellstring.cpp @@ -0,0 +1,264 @@ +/* + * Copyright 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/************************* STRRET functions ****************************/ + +BOOL WINAPI StrRetToStrNA(LPSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl) +{ + TRACE("dest=%p len=0x%x strret=%p(%s) pidl=%p\n", + dest,len,src, + (src->uType == STRRET_WSTR) ? "STRRET_WSTR" : + (src->uType == STRRET_CSTR) ? "STRRET_CSTR" : + (src->uType == STRRET_OFFSET) ? "STRRET_OFFSET" : "STRRET_???", + pidl); + + if (!dest) + return FALSE; + + switch (src->uType) + { + case STRRET_WSTR: + WideCharToMultiByte(CP_ACP, 0, src->pOleStr, -1, dest, len, NULL, NULL); + CoTaskMemFree(src->pOleStr); + break; + + case STRRET_CSTR: + lstrcpynA(dest, src->cStr, len); + break; + + case STRRET_OFFSET: + lstrcpynA(dest, ((LPCSTR)&pidl->mkid)+src->uOffset, len); + break; + + default: + FIXME("unknown type!\n"); + if (len) *dest = '\0'; + return FALSE; + } + TRACE("-- %s\n", debugstr_a(dest) ); + return TRUE; +} + +/************************************************************************/ + +BOOL WINAPI StrRetToStrNW(LPWSTR dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl) +{ + TRACE("dest=%p len=0x%x strret=%p(%s) pidl=%p\n", + dest,len,src, + (src->uType == STRRET_WSTR) ? "STRRET_WSTR" : + (src->uType == STRRET_CSTR) ? "STRRET_CSTR" : + (src->uType == STRRET_OFFSET) ? "STRRET_OFFSET" : "STRRET_???", + pidl); + + if (!dest) + return FALSE; + + switch (src->uType) + { + case STRRET_WSTR: + lstrcpynW(dest, src->pOleStr, len); + CoTaskMemFree(src->pOleStr); + break; + + case STRRET_CSTR: + if (!MultiByteToWideChar( CP_ACP, 0, src->cStr, -1, dest, len ) && len) + dest[len-1] = 0; + break; + + case STRRET_OFFSET: + if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->uOffset, -1, dest, len ) && len) + dest[len-1] = 0; + break; + + default: + FIXME("unknown type!\n"); + if (len) *dest = '\0'; + return FALSE; + } + return TRUE; +} + + +/************************************************************************* + * StrRetToStrN [SHELL32.96] + * + * converts a STRRET to a normal string + * + * NOTES + * the pidl is for STRRET OFFSET + */ +EXTERN_C BOOL WINAPI StrRetToStrNAW(LPVOID dest, DWORD len, LPSTRRET src, const ITEMIDLIST *pidl) +{ + if(SHELL_OsIsUnicode()) + return StrRetToStrNW((LPWSTR)dest, len, src, pidl); + else + return StrRetToStrNA((LPSTR)dest, len, src, pidl); +} + +/************************* OLESTR functions ****************************/ + +/************************************************************************ + * StrToOleStr [SHELL32.163] + * + */ +int WINAPI StrToOleStrA (LPWSTR lpWideCharStr, LPCSTR lpMultiByteString) +{ + TRACE("(%p, %p %s)\n", + lpWideCharStr, lpMultiByteString, debugstr_a(lpMultiByteString)); + + return MultiByteToWideChar(0, 0, lpMultiByteString, -1, lpWideCharStr, MAX_PATH); + +} +int WINAPI StrToOleStrW (LPWSTR lpWideCharStr, LPCWSTR lpWString) +{ + TRACE("(%p, %p %s)\n", + lpWideCharStr, lpWString, debugstr_w(lpWString)); + + wcscpy (lpWideCharStr, lpWString ); + return wcslen(lpWideCharStr); +} + +EXTERN_C BOOL WINAPI StrToOleStrAW (LPWSTR lpWideCharStr, LPCVOID lpString) +{ + if (SHELL_OsIsUnicode()) + return StrToOleStrW (lpWideCharStr, (LPCWSTR)lpString); + return StrToOleStrA (lpWideCharStr, (LPCSTR)lpString); +} + +/************************************************************************* + * StrToOleStrN [SHELL32.79] + * lpMulti, nMulti, nWide [IN] + * lpWide [OUT] + */ +BOOL WINAPI StrToOleStrNA (LPWSTR lpWide, INT nWide, LPCSTR lpStrA, INT nStr) +{ + TRACE("(%p, %x, %s, %x)\n", lpWide, nWide, debugstr_an(lpStrA,nStr), nStr); + return MultiByteToWideChar (0, 0, lpStrA, nStr, lpWide, nWide); +} +BOOL WINAPI StrToOleStrNW (LPWSTR lpWide, INT nWide, LPCWSTR lpStrW, INT nStr) +{ + TRACE("(%p, %x, %s, %x)\n", lpWide, nWide, debugstr_wn(lpStrW, nStr), nStr); + + if (lstrcpynW (lpWide, lpStrW, nWide)) + { return wcslen (lpWide); + } + return 0; +} + +EXTERN_C BOOL WINAPI StrToOleStrNAW (LPWSTR lpWide, INT nWide, LPCVOID lpStr, INT nStr) +{ + if (SHELL_OsIsUnicode()) + return StrToOleStrNW (lpWide, nWide, (LPCWSTR)lpStr, nStr); + return StrToOleStrNA (lpWide, nWide, (LPCSTR)lpStr, nStr); +} + +/************************************************************************* + * OleStrToStrN [SHELL32.78] + */ +BOOL WINAPI OleStrToStrNA (LPSTR lpStr, INT nStr, LPCWSTR lpOle, INT nOle) +{ + TRACE("(%p, %x, %s, %x)\n", lpStr, nStr, debugstr_wn(lpOle,nOle), nOle); + return WideCharToMultiByte (0, 0, lpOle, nOle, lpStr, nStr, NULL, NULL); +} + +BOOL WINAPI OleStrToStrNW (LPWSTR lpwStr, INT nwStr, LPCWSTR lpOle, INT nOle) +{ + TRACE("(%p, %x, %s, %x)\n", lpwStr, nwStr, debugstr_wn(lpOle,nOle), nOle); + + if (lstrcpynW ( lpwStr, lpOle, nwStr)) + { return wcslen (lpwStr); + } + return 0; +} + +EXTERN_C BOOL WINAPI OleStrToStrNAW (LPVOID lpOut, INT nOut, LPCVOID lpIn, INT nIn) +{ + if (SHELL_OsIsUnicode()) + return OleStrToStrNW ((LPWSTR)lpOut, nOut, (LPCWSTR)lpIn, nIn); + return OleStrToStrNA ((LPSTR)lpOut, nOut, (LPCWSTR)lpIn, nIn); +} + + +/************************************************************************* + * CheckEscapesA [SHELL32.@] + * + * Checks a string for special characters which are not allowed in a path + * and encloses it in quotes if that is the case. + * + * PARAMS + * string [I/O] string to check and on return eventually quoted + * len [I] length of string + * + * RETURNS + * length of actual string + * + * NOTES + * Not really sure if this function returns actually a value at all. + */ +DWORD WINAPI CheckEscapesA( + LPSTR string, /* [I/O] string to check ??*/ + DWORD len) /* [I] is 0 */ +{ + LPWSTR wString; + DWORD ret = 0; + + TRACE("(%s %d)\n", debugstr_a(string), len); + wString = (LPWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR)); + if (wString) + { + MultiByteToWideChar(CP_ACP, 0, string, len, wString, len); + ret = CheckEscapesW(wString, len); + WideCharToMultiByte(CP_ACP, 0, wString, len, string, len, NULL, NULL); + LocalFree(wString); + } + return ret; +} + +static const WCHAR strEscapedChars[] = {' ','"',',',';','^',0}; + +/************************************************************************* + * CheckEscapesW [SHELL32.@] + * + * See CheckEscapesA. + */ +DWORD WINAPI CheckEscapesW( + LPWSTR string, + DWORD len) +{ + DWORD size = wcslen(string); + LPWSTR s, d; + + TRACE("(%s %d) stub\n", debugstr_w(string), len); + + if (StrPBrkW(string, strEscapedChars) && size + 2 <= len) + { + s = &string[size - 1]; + d = &string[size + 2]; + *d-- = 0; + *d-- = '"'; + for (;d > string;) + *d-- = *s--; + *d = '"'; + return size + 2; + } + return size; +} diff --git a/reactos/dll/win32/shell32/shfldr.h b/reactos/dll/win32/shell32/shfldr.h index 04c02a78433..886f36619b8 100644 --- a/reactos/dll/win32/shell32/shfldr.h +++ b/reactos/dll/win32/shell32/shfldr.h @@ -21,6 +21,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#ifndef _SHFLDR_H_ +#define _SHFLDR_H_ + #define CHARS_IN_GUID 39 typedef struct { @@ -51,9 +54,9 @@ LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path); static int __inline SHELL32_GUIDToStringA (REFGUID guid, LPSTR str) { return sprintf(str, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + guid.Data1, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); } static int __inline SHELL32_GUIDToStringW (REFGUID guid, LPWSTR str) @@ -64,10 +67,12 @@ static int __inline SHELL32_GUIDToStringW (REFGUID guid, LPWSTR str) '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x', '%','0','2','x','%','0','2','x','}',0 }; return swprintf(str, fmtW, - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + guid.Data1, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], + guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]); } void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags); BOOL SHELL_FS_HideExtension(LPWSTR pwszPath); + +#endif // _SHFLDR_H_ diff --git a/reactos/dll/win32/shell32/shfldr_admintools.cpp b/reactos/dll/win32/shell32/shfldr_admintools.cpp new file mode 100644 index 00000000000..8c056c6e0b5 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_admintools.cpp @@ -0,0 +1,584 @@ +/* + * Virtual Admin Tools Folder + * + * Copyright 2008 Johannes Anderwald + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL (shell); + + +/* +This folder should not exist. It is just a file system folder... +*/ + +/* List shortcuts of + * CSIDL_COMMON_ADMINTOOLS + * Note: CSIDL_ADMINTOOLS is ignored, tested with Window XP SP3+ + */ + +/*********************************************************************** + * AdminTools folder implementation + */ + +class CDesktopFolderEnumY : + public IEnumIDListImpl +{ +private: +public: + CDesktopFolderEnumY(); + ~CDesktopFolderEnumY(); + HRESULT WINAPI Initialize(LPWSTR szTarget, DWORD dwFlags); + +BEGIN_COM_MAP(CDesktopFolderEnumY) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) +END_COM_MAP() +}; + +static const shvheader AdminToolsSFHeader[] = { + {IDS_SHV_COLUMN8, 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} +}; + +#define COLUMN_NAME 0 +#define COLUMN_SIZE 1 +#define COLUMN_TYPE 2 +#define COLUMN_DATE 3 + +#define AdminToolsHELLVIEWCOLUMNS (4) + +CDesktopFolderEnumY::CDesktopFolderEnumY() +{ +} + +CDesktopFolderEnumY::~CDesktopFolderEnumY() +{ +} + +HRESULT WINAPI CDesktopFolderEnumY::Initialize(LPWSTR szTarget, DWORD dwFlags) +{ + TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags); + /* enumerate the elements in %windir%\desktop */ + return CreateFolderEnumList(szTarget, dwFlags); +} + +CAdminToolsFolder::CAdminToolsFolder() +{ + pclsid = NULL; + + pidlRoot = NULL; /* absolute pidl */ + szTarget = NULL; + + dwAttributes = 0; /* attributes returned by GetAttributesOf FIXME: use it */ +} + +CAdminToolsFolder::~CAdminToolsFolder() +{ + TRACE ("-- destroying IShellFolder(%p)\n", this); + if (pidlRoot) + SHFree(pidlRoot); + HeapFree(GetProcessHeap(), 0, szTarget); +} + +HRESULT WINAPI CAdminToolsFolder::FinalConstruct() +{ + szTarget = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); + if (szTarget == NULL) + return E_OUTOFMEMORY; + if (!SHGetSpecialFolderPathW(NULL, szTarget, CSIDL_COMMON_ADMINTOOLS, FALSE)) + return E_FAIL; + + pidlRoot = _ILCreateAdminTools(); /* my qualified pidl */ + if (pidlRoot == NULL) + return E_OUTOFMEMORY; + return S_OK; +} + +/************************************************************************** + * ISF_AdminTools_fnParseDisplayName + * + */ +HRESULT WINAPI CAdminToolsFolder::ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, + DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes) +{ + 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; + + MessageBoxW(NULL, lpszDisplayName, L"ParseDisplayName", MB_OK); + + return E_NOTIMPL; +} + +/************************************************************************** + * ISF_AdminTools_fnEnumObjects + */ +HRESULT WINAPI CAdminToolsFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) +{ + CComObject *theEnumerator; + CComPtr 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); + if (theEnumerator == NULL) + return E_OUTOFMEMORY; + hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result); + if (FAILED (hResult)) + { + delete theEnumerator; + return hResult; + } + hResult = theEnumerator->Initialize (szTarget, dwFlags); + if (FAILED (hResult)) + return hResult; + *ppEnumIDList = result.Detach (); + + TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList); + + return S_OK; +} + +/************************************************************************** + * ISF_AdminTools_fnBindToObject + */ +HRESULT WINAPI CAdminToolsFolder::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_AdminTools_fnBindToStorage + */ +HRESULT WINAPI CAdminToolsFolder::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_AdminTools_fnCompareIDs + */ +HRESULT WINAPI CAdminToolsFolder::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_AdminTools_fnCreateViewObject + */ +HRESULT WINAPI CAdminToolsFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) +{ + CComPtr 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_IShellView)) + { + hr = IShellView_Constructor ((IShellFolder *)this, &pShellView); + if (pShellView) + hr = pShellView->QueryInterface(riid, ppvOut); + } + TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut); + return hr; +} + +/************************************************************************** + * ISF_AdminTools_fnGetAttributesOf + */ +HRESULT WINAPI CAdminToolsFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut) +{ + HRESULT hr = S_OK; + static const DWORD dwAdminToolsAttributes = + SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | + SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM; + + 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 &= dwAdminToolsAttributes; + } else { + while (cidl > 0 && *apidl) { + pdump (*apidl); + if (_ILIsAdminTools(*apidl)) { + *rgfInOut &= dwAdminToolsAttributes; + } else { + 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_AdminTools_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 CAdminToolsFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, + REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) +{ + LPITEMIDLIST pidl; + CComPtr pObj; + 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.Detach(); + TRACE ("(%p)->hr=0x%08x\n", this, hr); + return hr; +} + +/************************************************************************** + * ISF_AdminTools_fnGetDisplayNameOf + * + */ +HRESULT WINAPI CAdminToolsFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet) +{ + HRESULT hr = S_OK; + LPWSTR pszPath, pOffset; + + 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; + + ZeroMemory(pszPath, (MAX_PATH +1) * sizeof(WCHAR)); + + if (_ILIsAdminTools (pidl)) + { + if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) && + (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)) + wcscpy(pszPath, szTarget); + else if (!HCR_GetClassNameW(CLSID_AdminFolderShortcut, pszPath, MAX_PATH)) + hr = E_FAIL; + } + else if (_ILIsPidlSimple(pidl)) + { + if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && + (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && + szTarget) + { + wcscpy(pszPath, szTarget); + pOffset = PathAddBackslashW(pszPath); + if (pOffset) + { + if (!_ILSimpleGetTextW(pidl, pOffset, MAX_PATH + 1 - (pOffset - pszPath))) + hr = E_FAIL; + } + else + hr = E_FAIL; + } + else + { + if (_ILSimpleGetTextW(pidl, pszPath, MAX_PATH + 1)) + { + if (SHELL_FS_HideExtension(pszPath)) + PathRemoveExtensionW(pszPath); + } + else + hr = E_FAIL; + } + } + else if (_ILIsSpecialFolder(pidl)) + { + BOOL bSimplePidl = _ILIsPidlSimple(pidl); + + if (bSimplePidl) + { + if (!_ILSimpleGetTextW(pidl, pszPath, MAX_PATH)) + hr = E_FAIL; + } + else if ((dwFlags & SHGDN_FORPARSING) && !bSimplePidl) + { + int len = 0; + + wcscpy(pszPath, szTarget); + PathAddBackslashW(pszPath); + len = wcslen(pszPath); + + if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags | SHGDN_INFOLDER, pszPath + len, MAX_PATH + 1 - len))) + { + CoTaskMemFree(pszPath); + return E_OUTOFMEMORY; + } + + } + } + + if (SUCCEEDED(hr)) + { + strRet->uType = STRRET_WSTR; + strRet->pOleStr = pszPath; + TRACE ("-- (%p)->(%s,0x%08x)\n", this, debugstr_w(strRet->pOleStr), hr); + } + else + CoTaskMemFree(pszPath); + + return hr; +} + +/************************************************************************** + * ISF_AdminTools_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 CAdminToolsFolder::SetNameOf (HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */ + LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut) +{ + FIXME ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", this, hwndOwner, pidl, + debugstr_w (lpName), dwFlags, pPidlOut); + + return E_FAIL; +} + +HRESULT WINAPI CAdminToolsFolder::GetDefaultSearchGUID(GUID *pguid) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CAdminToolsFolder::EnumSearches(IEnumExtraSearch ** ppenum) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CAdminToolsFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay) +{ + if (pSort) + *pSort = 0; + if (pDisplay) + *pDisplay = 0; + + return S_OK; +} +HRESULT WINAPI CAdminToolsFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) +{ + if (!pcsFlags || iColumn >= AdminToolsHELLVIEWCOLUMNS) + return E_INVALIDARG; + *pcsFlags = AdminToolsSFHeader[iColumn].pcsFlags; + return S_OK; + +} + +HRESULT WINAPI CAdminToolsFolder::GetDetailsEx (LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv) +{ + FIXME ("(%p): stub\n", this); + + return E_NOTIMPL; +} + +HRESULT WINAPI CAdminToolsFolder::GetDetailsOf (LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd) +{ + WCHAR buffer[MAX_PATH] = {0}; + HRESULT hr = E_FAIL; + + TRACE("(%p)->(%p %i %p): stub\n", this, pidl, iColumn, psd); + + if (iColumn >= AdminToolsHELLVIEWCOLUMNS) + return E_FAIL; + + psd->fmt = AdminToolsSFHeader[iColumn].fmt; + psd->cxChar = AdminToolsSFHeader[iColumn].cxChar; + if (pidl == NULL) + { + psd->str.uType = STRRET_WSTR; + if (LoadStringW(shell32_hInstance, AdminToolsSFHeader[iColumn].colnameid, buffer, MAX_PATH)) + hr = SHStrDupW(buffer, &psd->str.pOleStr); + + return hr; + } + + psd->str.uType = STRRET_CSTR; + switch (iColumn) + { + case COLUMN_NAME: + psd->str.uType = STRRET_WSTR; + hr = GetDisplayNameOf(pidl, + SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str); + break; + case COLUMN_SIZE: + _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH); + break; + case COLUMN_TYPE: + _ILGetFileType (pidl, psd->str.cStr, MAX_PATH); + break; + case COLUMN_DATE: + _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH); + break; + } + + return hr; +} + +HRESULT WINAPI CAdminToolsFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) +{ + FIXME ("(%p): stub\n", this); + return E_NOTIMPL; +} + +/************************************************************************ + * IPF_AdminTools_GetClassID + */ +HRESULT WINAPI CAdminToolsFolder::GetClassID(CLSID *lpClassId) +{ + TRACE ("(%p)\n", this); + + memcpy(lpClassId, &CLSID_AdminFolderShortcut, sizeof(CLSID)); + + return S_OK; +} + +/************************************************************************ + * IPF_AdminTools_Initialize + * + */ +HRESULT WINAPI CAdminToolsFolder::Initialize(LPCITEMIDLIST pidl) +{ + if (pidlRoot) + SHFree((LPVOID)pidlRoot); + + pidlRoot = ILClone(pidl); + return S_OK; +} + +/************************************************************************** + * IPF_AdminTools_fnGetCurFolder + */ +HRESULT WINAPI CAdminToolsFolder::GetCurFolder(LPITEMIDLIST *pidl) +{ + TRACE ("(%p)->(%p)\n", this, pidl); + + *pidl = ILClone (pidlRoot); + return S_OK; +} diff --git a/reactos/dll/win32/shell32/shfldr_admintools.h b/reactos/dll/win32/shell32/shfldr_admintools.h new file mode 100644 index 00000000000..98f7df361e9 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_admintools.h @@ -0,0 +1,87 @@ +/* + * Virtual Admin Tools Folder + * + * Copyright 2008 Johannes Anderwald + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SHFLDR_ADMINTOOLS_H_ +#define _SHFLDR_ADMINTOOLS_H_ + +class CAdminToolsFolder : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder2 +{ +private: + CLSID *pclsid; + + LPITEMIDLIST pidlRoot; /* absolute pidl */ + LPWSTR szTarget; + + int dwAttributes; /* attributes returned by GetAttributesOf FIXME: use it */ +public: + CAdminToolsFolder(); + ~CAdminToolsFolder(); + HRESULT WINAPI FinalConstruct(); + + // IShellFolder + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + /* ShellFolder2 */ + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + +DECLARE_REGISTRY_RESOURCEID(IDR_ADMINFOLDERSHORTCUT) +DECLARE_NOT_AGGREGATABLE(CAdminToolsFolder) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CAdminToolsFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) +END_COM_MAP() +}; + +#endif // _SHFLDR_ADMINTOOLS_H_ diff --git a/reactos/dll/win32/shell32/shfldr_cpanel.cpp b/reactos/dll/win32/shell32/shfldr_cpanel.cpp new file mode 100644 index 00000000000..bc763831ca4 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_cpanel.cpp @@ -0,0 +1,1082 @@ +/* + * Control panel folder + * + * Copyright 2003 Martin Fuchs + * 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 + */ + +/* +TODO: +1. The selected items list should not be stored in CControlPanelFolder, it should + be a result returned by an internal method. +*/ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/*********************************************************************** +* control panel implementation in shell namespace +*/ + +class CControlPanelEnum : + public IEnumIDListImpl +{ +private: +public: + CControlPanelEnum(); + ~CControlPanelEnum(); + HRESULT WINAPI Initialize(DWORD dwFlags); + BOOL SHELL_RegisterCPanelApp(LPCSTR path); + int SHELL_RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPath); + int SHELL_RegisterCPanelFolders(HKEY hkey_root, LPCSTR szRepPath); + BOOL CreateCPanelEnumList(DWORD dwFlags); + +BEGIN_COM_MAP(CControlPanelEnum) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) +END_COM_MAP() +}; + +/*********************************************************************** +* IShellFolder [ControlPanel] implementation +*/ + +static const shvheader ControlPanelSFHeader[] = { + {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},/*FIXME*/ + {IDS_SHV_COLUMN9, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 200},/*FIXME*/ +}; + +#define CONROLPANELSHELLVIEWCOLUMNS 2 + +CControlPanelEnum::CControlPanelEnum() +{ +} + +CControlPanelEnum::~CControlPanelEnum() +{ +} + +HRESULT WINAPI CControlPanelEnum::Initialize(DWORD dwFlags) +{ + if (CreateCPanelEnumList(dwFlags) == FALSE) + return E_FAIL; + return S_OK; +} + +static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR name, LPCSTR displayName, LPCSTR comment, int iconIdx) +{ + PIDLCPanelStruct *p; + LPITEMIDLIST pidl; + PIDLDATA tmp; + int size0 = (char*)&tmp.u.cpanel.szName - (char*)&tmp.u.cpanel; + int size = size0; + int l; + + tmp.type = PT_CPLAPPLET; + tmp.u.cpanel.dummy = 0; + tmp.u.cpanel.iconIdx = iconIdx; + + l = strlen(name); + size += l + 1; + + tmp.u.cpanel.offsDispName = l+1; + l = strlen(displayName); + size += l + 1; + + tmp.u.cpanel.offsComment = tmp.u.cpanel.offsDispName + 1 + l; + l = strlen(comment); + size += l + 1; + + pidl = (LPITEMIDLIST)SHAlloc(size + 4); + if (!pidl) + return NULL; + + pidl->mkid.cb = size + 2; + memcpy(pidl->mkid.abID, &tmp, 2 + size0); + + p = &((PIDLDATA *)pidl->mkid.abID)->u.cpanel; + strcpy(p->szName, name); + strcpy(p->szName+tmp.u.cpanel.offsDispName, displayName); + strcpy(p->szName+tmp.u.cpanel.offsComment, comment); + + *(WORD*)((char*)pidl + (size + 2)) = 0; + + pcheck(pidl); + + return pidl; +} + +/************************************************************************** + * _ILGetCPanelPointer() + * gets a pointer to the control panel struct stored in the pidl + */ +static PIDLCPanelStruct *_ILGetCPanelPointer(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + + if (pdata && pdata->type == PT_CPLAPPLET) + return (PIDLCPanelStruct *)&(pdata->u.cpanel); + + return NULL; +} + +BOOL CControlPanelEnum::SHELL_RegisterCPanelApp(LPCSTR path) +{ + LPITEMIDLIST pidl; + CPlApplet* applet; + CPanel panel; + CPLINFO info; + unsigned i; + int iconIdx; + + char displayName[MAX_PATH]; + char comment[MAX_PATH]; + + WCHAR wpath[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH); + + panel.first = NULL; + applet = Control_LoadApplet(0, wpath, &panel); + + if (applet) + { + for (i = 0; i < applet->count; ++i) + { + WideCharToMultiByte(CP_ACP, 0, applet->info[i].szName, -1, displayName, MAX_PATH, 0, 0); + WideCharToMultiByte(CP_ACP, 0, applet->info[i].szInfo, -1, comment, MAX_PATH, 0, 0); + + applet->proc(0, CPL_INQUIRE, i, (LPARAM)&info); + + if (info.idIcon > 0) + iconIdx = -info.idIcon; /* negative icon index instead of icon number */ + else + iconIdx = 0; + + pidl = _ILCreateCPanelApplet(path, displayName, comment, iconIdx); + + if (pidl) + AddToEnumList(pidl); + } + Control_UnloadApplet(applet); + } + return TRUE; +} + +int CControlPanelEnum::SHELL_RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPath) +{ + char name[MAX_PATH]; + char value[MAX_PATH]; + HKEY hkey; + + int cnt = 0; + + if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS) + { + int idx = 0; + + for(; ; idx++) + { + DWORD nameLen = MAX_PATH; + DWORD valueLen = MAX_PATH; + + if (RegEnumValueA(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS) + break; + + if (SHELL_RegisterCPanelApp(value)) + ++cnt; + } + RegCloseKey(hkey); + } + + return cnt; +} + +int CControlPanelEnum::SHELL_RegisterCPanelFolders(HKEY hkey_root, LPCSTR szRepPath) +{ + char name[MAX_PATH]; + HKEY hkey; + + int cnt = 0; + + if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS) + { + int idx = 0; + for (; ; idx++) + { + if (RegEnumKeyA(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS) + break; + + if (*name == '{') + { + LPITEMIDLIST pidl = _ILCreateGuidFromStrA(name); + + if (pidl && AddToEnumList(pidl)) + ++cnt; + } + } + + RegCloseKey(hkey); + } + + return cnt; +} + +/************************************************************************** + * CreateCPanelEnumList() + */ +BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags) +{ + CHAR szPath[MAX_PATH]; + WIN32_FIND_DATAA wfd; + HANDLE hFile; + + TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags); + + /* enumerate control panel folders */ + if (dwFlags & SHCONTF_FOLDERS) + SHELL_RegisterCPanelFolders(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace"); + + /* enumerate the control panel applets */ + if (dwFlags & SHCONTF_NONFOLDERS) + { + LPSTR p; + + GetSystemDirectoryA(szPath, MAX_PATH); + p = PathAddBackslashA(szPath); + strcpy(p, "*.cpl"); + + TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n", this, debugstr_a(szPath)); + hFile = FindFirstFileA(szPath, &wfd); + + if (hFile != INVALID_HANDLE_VALUE) + { + do + { + if (!(dwFlags & SHCONTF_INCLUDEHIDDEN) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) + continue; + + if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + strcpy(p, wfd.cFileName); + if (strcmp(wfd.cFileName, "ncpa.cpl")) + SHELL_RegisterCPanelApp(szPath); + } + } while(FindNextFileA(hFile, &wfd)); + FindClose(hFile); + } + + SHELL_RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls"); + SHELL_RegisterRegistryCPanelApps(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls"); + } + return TRUE; +} + +CControlPanelFolder::CControlPanelFolder() +{ + pidlRoot = NULL; /* absolute pidl */ + dwAttributes = 0; /* attributes returned by GetAttributesOf FIXME: use it */ + apidl = NULL; + cidl = 0; +} + +CControlPanelFolder::~CControlPanelFolder() +{ + TRACE("-- destroying IShellFolder(%p)\n", this); + SHFree(pidlRoot); +} + +HRESULT WINAPI CControlPanelFolder::FinalConstruct() +{ + pidlRoot = _ILCreateControlPanel(); /* my qualified pidl */ + if (pidlRoot == NULL) + return E_OUTOFMEMORY; + return S_OK; +} + +/************************************************************************** +* ISF_ControlPanel_fnParseDisplayName +*/ +HRESULT WINAPI CControlPanelFolder::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 (!lpszDisplayName || !ppidl) + return E_INVALIDARG; + + *ppidl = 0; + + 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( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) ) + { + *ppidl = pidlTemp; + return S_OK; + } + + 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(this, + pidlTemp, pdwAttributes); + } + } + + *ppidl = pidlTemp; + + TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr); + + return hr; +} + +/************************************************************************** +* ISF_ControlPanel_fnEnumObjects +*/ +HRESULT WINAPI CControlPanelFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList) +{ + CComObject *theEnumerator; + CComPtr 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); + if (theEnumerator == NULL) + return E_OUTOFMEMORY; + hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result); + if (FAILED (hResult)) + { + delete theEnumerator; + return hResult; + } + hResult = theEnumerator->Initialize (dwFlags); + if (FAILED (hResult)) + return hResult; + *ppEnumIDList = result.Detach (); + + TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList); + + return S_OK; +} + +/************************************************************************** +* ISF_ControlPanel_fnBindToObject +*/ +HRESULT WINAPI CControlPanelFolder::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_ControlPanel_fnBindToStorage +*/ +HRESULT WINAPI CControlPanelFolder::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_ControlPanel_fnCompareIDs +*/ + +HRESULT WINAPI CControlPanelFolder::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_ControlPanel_fnCreateViewObject +*/ +HRESULT WINAPI CControlPanelFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut) +{ + CComPtr pShellView; + HRESULT hr = E_INVALIDARG; + + TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid(&riid), ppvOut); + + if (ppvOut) { + *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_ControlPanel_fnGetAttributesOf +*/ +HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut) +{ + HRESULT hr = S_OK; + + 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; + + 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_ControlPanel_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 CControlPanelFolder::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) { + *ppvOut = NULL; + + if (IsEqualIID(riid, IID_IContextMenu) &&(cidl >= 1)) { + // TODO + // create a seperate item struct + // + pObj = (IContextMenu *)this; + this->apidl = apidl; + cidl = cidl; + pObj->AddRef(); + hr = S_OK; + } 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_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_ControlPanel_fnGetDisplayNameOf +*/ +HRESULT WINAPI CControlPanelFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet) +{ + CHAR szPath[MAX_PATH]; + WCHAR wszPath[MAX_PATH+1]; /* +1 for potential backslash */ + PIDLCPanelStruct* pcpanel; + + *szPath = '\0'; + + TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); + pdump(pidl); + + if (!pidl || !strRet) + return E_INVALIDARG; + + pcpanel = _ILGetCPanelPointer(pidl); + + if (pcpanel) + { + lstrcpyA(szPath, pcpanel->szName+pcpanel->offsDispName); + + if (!(dwFlags & SHGDN_FORPARSING)) + FIXME("retrieve display name from control panel app\n"); + } + /* take names of special folders only if it's only this folder */ + else if (_ILIsSpecialFolder(pidl)) + { + BOOL bSimplePidl = _ILIsPidlSimple(pidl); + + if (bSimplePidl) + { + _ILSimpleGetTextW(pidl, wszPath, MAX_PATH); /* append my own path */ + } + else + { + FIXME("special pidl\n"); + } + + if ((dwFlags & SHGDN_FORPARSING) && !bSimplePidl) + { + /* go deeper if needed */ + int len = 0; + + PathAddBackslashW(wszPath); + len = wcslen(wszPath); + + if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, wszPath + len, MAX_PATH + 1 - len))) + return E_OUTOFMEMORY; + + if (!WideCharToMultiByte(CP_ACP, 0, wszPath, -1, szPath, MAX_PATH, NULL, NULL)) + wszPath[0] = '\0'; + } + else + { + if (bSimplePidl) + { + if (!WideCharToMultiByte(CP_ACP, 0, wszPath, -1, szPath, MAX_PATH, NULL, NULL)) + wszPath[0] = '\0'; + } + } + } + + strRet->uType = STRRET_CSTR; + lstrcpynA(strRet->cStr, szPath, MAX_PATH); + + TRACE("--(%p)->(%s)\n", this, szPath); + return S_OK; +} + +/************************************************************************** +* ISF_ControlPanel_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 CControlPanelFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /*simple pidl */ + LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut) +{ + FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, debugstr_w(lpName), dwFlags, pPidlOut); + return E_FAIL; +} + +HRESULT WINAPI CControlPanelFolder::GetDefaultSearchGUID(GUID *pguid) +{ + FIXME("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CControlPanelFolder::EnumSearches(IEnumExtraSearch **ppenum) +{ + FIXME("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CControlPanelFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) +{ + TRACE("(%p)\n", this); + + if (pSort) *pSort = 0; + if (pDisplay) *pDisplay = 0; + return S_OK; +} + +HRESULT WINAPI CControlPanelFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) +{ + TRACE("(%p)\n", this); + + if (!pcsFlags || iColumn >= CONROLPANELSHELLVIEWCOLUMNS) return E_INVALIDARG; + *pcsFlags = ControlPanelSFHeader[iColumn].pcsFlags; + return S_OK; +} + +HRESULT WINAPI CControlPanelFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv) +{ + FIXME("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CControlPanelFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd) +{ + HRESULT hr; + + TRACE("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd); + + if (!psd || iColumn >= CONROLPANELSHELLVIEWCOLUMNS) + return E_INVALIDARG; + + if (!pidl) { + psd->fmt = ControlPanelSFHeader[iColumn].fmt; + psd->cxChar = ControlPanelSFHeader[iColumn].cxChar; + psd->str.uType = STRRET_CSTR; + LoadStringA(shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid, psd->str.cStr, MAX_PATH); + return S_OK; + } else { + 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: /* comment */ + _ILGetFileType(pidl, psd->str.cStr, MAX_PATH); + break; + } + hr = S_OK; + } + + return hr; +} +HRESULT WINAPI CControlPanelFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) +{ + FIXME("(%p)\n", this); + return E_NOTIMPL; +} + +/************************************************************************ + * ICPanel_PersistFolder2_GetClassID + */ +HRESULT WINAPI CControlPanelFolder::GetClassID(CLSID *lpClassId) +{ + TRACE("(%p)\n", this); + + if (!lpClassId) + return E_POINTER; + *lpClassId = CLSID_ControlPanel; + + return S_OK; +} + +/************************************************************************ + * ICPanel_PersistFolder2_Initialize + * + * NOTES: it makes no sense to change the pidl + */ +HRESULT WINAPI CControlPanelFolder::Initialize(LPCITEMIDLIST pidl) +{ + if (pidlRoot) + SHFree((LPVOID)pidlRoot); + + pidlRoot = ILClone(pidl); + return S_OK; +} + +/************************************************************************** + * IPersistFolder2_fnGetCurFolder + */ +HRESULT WINAPI CControlPanelFolder::GetCurFolder(LPITEMIDLIST * pidl) +{ + TRACE("(%p)->(%p)\n", this, pidl); + + if (!pidl) + return E_POINTER; + *pidl = ILClone(pidlRoot); + return S_OK; +} + +HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST pidl, LPWSTR szIconFile, UINT cchMax, int* piIndex) +{ + PIDLCPanelStruct* pcpanel = _ILGetCPanelPointer(pidl); + + if (!pcpanel) + return E_INVALIDARG; + + MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, szIconFile, cchMax); + *piIndex = (int)pcpanel->iconIdx != -1 ? pcpanel->iconIdx : 0; + + return S_OK; +} + + +/************************************************************************** +* IShellExecuteHookW Implementation +*/ + +HRESULT +ExecuteAppletFromCLSID(LPOLESTR pOleStr) +{ + WCHAR szCmd[MAX_PATH]; + WCHAR szExpCmd[MAX_PATH]; + PROCESS_INFORMATION pi; + STARTUPINFOW si; + WCHAR szBuffer[90] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 }; + DWORD dwType, dwSize; + + wcscpy(&szBuffer[6], pOleStr); + wcscat(szBuffer, L"\\shell\\open\\command"); + + dwSize = sizeof(szCmd); + if (RegGetValueW(HKEY_CLASSES_ROOT, szBuffer, NULL, RRF_RT_REG_SZ, &dwType, (PVOID)szCmd, &dwSize) != ERROR_SUCCESS) + { + ERR("RegGetValueW failed with %u\n", GetLastError()); + return E_FAIL; + } + +#if 0 + if (dwType != RRF_RT_REG_SZ && dwType != RRF_RT_REG_EXPAND_SZ) + return E_FAIL; +#endif + + if (!ExpandEnvironmentStringsW(szCmd, szExpCmd, sizeof(szExpCmd)/sizeof(WCHAR))) + return E_FAIL; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + if (!CreateProcessW(NULL, szExpCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + return E_FAIL; + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return S_OK; +} + + +HRESULT WINAPI CControlPanelFolder::Execute(LPSHELLEXECUTEINFOW psei) +{ + static const WCHAR wCplopen[] = {'c','p','l','o','p','e','n','\0'}; + SHELLEXECUTEINFOW sei_tmp; + PIDLCPanelStruct* pcpanel; + WCHAR path[MAX_PATH]; + WCHAR params[MAX_PATH]; + BOOL ret; + HRESULT hr; + int l; + + TRACE("(%p)->execute(%p)\n", this, psei); + + if (!psei) + return E_INVALIDARG; + + pcpanel = _ILGetCPanelPointer(ILFindLastID((LPCITEMIDLIST)psei->lpIDList)); + + if (!pcpanel) + { + LPOLESTR pOleStr; + + IID * iid = _ILGetGUIDPointer(ILFindLastID((LPCITEMIDLIST)psei->lpIDList)); + if (!iid) + return E_INVALIDARG; + if (StringFromCLSID(*iid, &pOleStr) == S_OK) + { + + hr = ExecuteAppletFromCLSID(pOleStr); + CoTaskMemFree(pOleStr); + return hr; + } + + return E_INVALIDARG; + } + path[0] = '\"'; + /* Return value from MultiByteToWideChar includes terminating NUL, which + * compensates for the starting double quote we just put in */ + l = MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, path+1, MAX_PATH); + + /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */ + path[l++] = '"'; + path[l] = '\0'; + + MultiByteToWideChar(CP_ACP, 0, pcpanel->szName+pcpanel->offsDispName, -1, params, MAX_PATH); + + memcpy(&sei_tmp, psei, sizeof(sei_tmp)); + sei_tmp.lpFile = path; + sei_tmp.lpParameters = params; + sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST; + sei_tmp.lpVerb = wCplopen; + + ret = ShellExecuteExW(&sei_tmp); + if (ret) + return S_OK; + else + return S_FALSE; +} + +/************************************************************************** +* IShellExecuteHookA Implementation +*/ + +HRESULT WINAPI CControlPanelFolder::Execute(LPSHELLEXECUTEINFOA psei) +{ + SHELLEXECUTEINFOA sei_tmp; + PIDLCPanelStruct* pcpanel; + char path[MAX_PATH]; + BOOL ret; + + TRACE("(%p)->execute(%p)\n", this, psei); + + if (!psei) + return E_INVALIDARG; + + pcpanel = _ILGetCPanelPointer(ILFindLastID((LPCITEMIDLIST)psei->lpIDList)); + + if (!pcpanel) + return E_INVALIDARG; + + path[0] = '\"'; + lstrcpyA(path+1, pcpanel->szName); + + /* pass applet name to Control_RunDLL to distinguish between applets in one .cpl file */ + lstrcatA(path, "\" "); + lstrcatA(path, pcpanel->szName+pcpanel->offsDispName); + + memcpy(&sei_tmp, psei, sizeof(sei_tmp)); + sei_tmp.lpFile = path; + sei_tmp.fMask &= ~SEE_MASK_INVOKEIDLIST; + + ret = ShellExecuteExA(&sei_tmp); + if (ret) + return S_OK; + else + return S_FALSE; +} + +/************************************************************************** +* IContextMenu2 Implementation +*/ + +/************************************************************************** +* ICPanel_IContextMenu_QueryContextMenu() +*/ +HRESULT WINAPI CControlPanelFolder::QueryContextMenu( + HMENU hMenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags) +{ + WCHAR szBuffer[30] = {0}; + ULONG Count = 1; + + TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", + this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); + + if (LoadStringW(shell32_hInstance, IDS_OPEN, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_OPEN, MFT_STRING, szBuffer, MFS_DEFAULT); //FIXME identifier + Count++; + } + + if (LoadStringW(shell32_hInstance, IDS_CREATELINK, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + if (Count) + { + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_SEPARATOR, NULL, MFS_ENABLED); + } + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + + _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_CREATELINK, MFT_STRING, szBuffer, MFS_ENABLED); //FIXME identifier + Count++; + } + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count); +} + +/************************************************************************** +* ICPanel_IContextMenu_InvokeCommand() +*/ +HRESULT WINAPI CControlPanelFolder::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) +{ + SHELLEXECUTEINFOW sei; + WCHAR szPath[MAX_PATH]; + char szTarget[MAX_PATH]; + STRRET strret; + WCHAR* pszPath; + INT Length, cLength; + PIDLCPanelStruct *pcpanel; + CComPtr ppf; + CComPtr isl; + HRESULT hResult; + + TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",this,lpcmi,lpcmi->lpVerb, lpcmi->hwnd); + + if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_OPEN)) //FIXME + { + ZeroMemory(&sei, sizeof(sei)); + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_INVOKEIDLIST; + sei.lpIDList = ILCombine(pidlRoot, apidl[0]); + sei.hwnd = lpcmi->hwnd; + sei.nShow = SW_SHOWNORMAL; + sei.lpVerb = L"open"; + + if (ShellExecuteExW(&sei) == FALSE) + return E_FAIL; + } + else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_CREATELINK)) //FIXME + { + if (!SHGetSpecialFolderPathW(NULL, szPath, CSIDL_DESKTOPDIRECTORY, FALSE)) + return E_FAIL; + + pszPath = PathAddBackslashW(szPath); + if (!pszPath) + return E_FAIL; + + if (GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strret) != S_OK) + return E_FAIL; + + Length = MAX_PATH - (pszPath - szPath); + cLength = strlen(strret.cStr); + if (Length < cLength + 5) + { + FIXME("\n"); + return E_FAIL; + } + + if (MultiByteToWideChar(CP_ACP, 0, strret.cStr, cLength + 1, pszPath, Length)) + { + pszPath += cLength; + Length -= cLength; + } + + if (Length > 10) + { + wcscpy(pszPath, L" - "); + cLength = LoadStringW(shell32_hInstance, IDS_LNK_FILE, &pszPath[3], Length - 4) + 3; + if (cLength + 5 > Length) + cLength = Length - 5; + Length -= cLength; + pszPath += cLength; + } + wcscpy(pszPath, L".lnk"); + + pcpanel = _ILGetCPanelPointer(ILFindLastID(apidl[0])); + if (pcpanel) + { + strncpy(szTarget, pcpanel->szName, MAX_PATH); + } + else + { + FIXME("Couldn't retrieve pointer to cpl structure\n"); + return E_FAIL; + } + hResult = ShellLink::_CreatorClass::CreateInstance(NULL, IID_IShellLinkA, (void **)&isl); + if (SUCCEEDED(hResult)) + { + isl->SetPath(szTarget); + if (SUCCEEDED(isl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf))) + ppf->Save(szPath, TRUE); + } + return NOERROR; + } + return S_OK; +} + +/************************************************************************** + * ICPanel_IContextMenu_GetCommandString() + * + */ +HRESULT WINAPI CControlPanelFolder::GetCommandString( + UINT_PTR idCommand, + UINT uFlags, + UINT* lpReserved, + LPSTR lpszName, + UINT uMaxNameLen) +{ + TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); + + FIXME("unknown command string\n"); + return E_FAIL; +} + +/************************************************************************** +* ICPanel_IContextMenu_HandleMenuMsg() +*/ +HRESULT WINAPI CControlPanelFolder::HandleMenuMsg( + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + TRACE("ICPanel_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n",this, uMsg, wParam, lParam); + + return E_NOTIMPL; +} diff --git a/reactos/dll/win32/shell32/shfldr_cpanel.h b/reactos/dll/win32/shell32/shfldr_cpanel.h new file mode 100644 index 00000000000..bcb1f07728f --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_cpanel.h @@ -0,0 +1,107 @@ +/* + * Control panel folder + * + * Copyright 2003 Martin Fuchs + * 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 + */ + +#ifndef _SHFLDR_CPANEL_H_ +#define _SHFLDR_CPANEL_H_ + +class CControlPanelFolder : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder2, + public IShellExecuteHookA, + public IShellExecuteHookW, + public IContextMenu2 +{ +private: + /* both paths are parsible from the desktop */ + LPITEMIDLIST pidlRoot; /* absolute pidl */ + int dwAttributes; /* attributes returned by GetAttributesOf FIXME: use it */ + LPCITEMIDLIST *apidl; + UINT cidl; +public: + CControlPanelFolder(); + ~CControlPanelFolder(); + HRESULT WINAPI FinalConstruct(); + + // IShellFolder + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + /* ShellFolder2 */ + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + + // IShellExecuteHookW + virtual HRESULT WINAPI Execute(LPSHELLEXECUTEINFOW psei); + + // IShellExecuteHookA + virtual HRESULT WINAPI Execute(LPSHELLEXECUTEINFOA psei); + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand,UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen); + + // IContextMenu2 + virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); + +DECLARE_REGISTRY_RESOURCEID(IDR_CONTROLPANEL) +DECLARE_NOT_AGGREGATABLE(CControlPanelFolder) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CControlPanelFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) + COM_INTERFACE_ENTRY_IID(IID_IShellExecuteHookA, IShellExecuteHookA) + COM_INTERFACE_ENTRY_IID(IID_IShellExecuteHookW, IShellExecuteHookW) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2) +END_COM_MAP() +}; + +#endif // _SHFLDR_CPANEL_H_ diff --git a/reactos/dll/win32/shell32/shfldr_desktop.cpp b/reactos/dll/win32/shell32/shfldr_desktop.cpp new file mode 100644 index 00000000000..d55d3259e1f --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_desktop.cpp @@ -0,0 +1,1276 @@ +/* + * 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 + +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 *theEnumerator; + CComPtr 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); + + 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 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 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 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 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; +} diff --git a/reactos/dll/win32/shell32/shfldr_desktop.h b/reactos/dll/win32/shell32/shfldr_desktop.h new file mode 100644 index 00000000000..ab20136ffb7 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_desktop.h @@ -0,0 +1,96 @@ +/* + * 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 + */ + +#ifndef _CDESKTOPFOLDER_H_ +#define _CDESKTOPFOLDER_H_ + +class CDesktopFolder : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder2, + public ISFHelper +{ +private: + /* both paths are parsible from the desktop */ + LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */ + LPITEMIDLIST pidlRoot; /* absolute pidl */ + +// CComPtr fDesktopFolder; +// CComPtr fCommonDesktopFolder; +public: + CDesktopFolder(); + ~CDesktopFolder(); + HRESULT WINAPI FinalConstruct(); + + // *** IShellFolder methods *** + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + // *** ShellFolder2 methods *** + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // *** IPersist methods *** + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // *** IPersistFolder methods *** + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // *** IPersistFolder2 methods *** + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + + // *** ISFHelper methods *** + virtual HRESULT WINAPI GetUniqueName(LPWSTR pwszName, UINT uLen); + virtual HRESULT WINAPI AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut); + virtual HRESULT WINAPI DeleteItems(UINT cidl, LPCITEMIDLIST *apidl); + virtual HRESULT WINAPI CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl); + +DECLARE_REGISTRY_RESOURCEID(IDR_SHELLDESKTOP) +DECLARE_NOT_AGGREGATABLE(CDesktopFolder) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CDesktopFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) + COM_INTERFACE_ENTRY_IID(IID_ISFHelper, ISFHelper) +END_COM_MAP() +}; + +#endif // _CDESKTOPFOLDER_H_ diff --git a/reactos/dll/win32/shell32/shfldr_fonts.cpp b/reactos/dll/win32/shell32/shfldr_fonts.cpp new file mode 100644 index 00000000000..50a849f2d78 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_fonts.cpp @@ -0,0 +1,785 @@ +/* + * Fonts folder + * + * Copyright 2008 Johannes Anderwald + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL (shell); + +/* +This folder should not exist. It is just a file system folder... The \windows\fonts +directory contains a hidden desktop.ini with a UIHandler entry that specifies a class +that lives in fontext.dll. The UI handler creates a custom view for the folder, which +is what we normally see. However, the folder is a perfectly normal CFSFolder. +*/ + +/*********************************************************************** +* IShellFolder implementation +*/ + +class CDesktopFolderEnumZ : + public IEnumIDListImpl +{ +private: +public: + CDesktopFolderEnumZ(); + ~CDesktopFolderEnumZ(); + HRESULT WINAPI Initialize(DWORD dwFlags); + BOOL CreateFontsEnumList(DWORD dwFlags); + +BEGIN_COM_MAP(CDesktopFolderEnumZ) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) +END_COM_MAP() +}; + +static shvheader FontsSFHeader[] = { + {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN_FONTTYPE , SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN12, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15} +}; + +#define COLUMN_NAME 0 +#define COLUMN_TYPE 1 +#define COLUMN_SIZE 2 +#define COLUMN_FILENAME 3 + +#define FontsSHELLVIEWCOLUMNS (4) + +CDesktopFolderEnumZ::CDesktopFolderEnumZ() +{ +} + +CDesktopFolderEnumZ::~CDesktopFolderEnumZ() +{ +} + +HRESULT WINAPI CDesktopFolderEnumZ::Initialize(DWORD dwFlags) +{ + if (CreateFontsEnumList(dwFlags) == FALSE) + return E_FAIL; + return S_OK; +} + +static LPITEMIDLIST _ILCreateFontItem(LPWSTR pszFont, LPWSTR pszFile) +{ + PIDLDATA tmp; + LPITEMIDLIST pidl; + PIDLFontStruct * p; + int size0 = (char*)&tmp.u.cfont.szName-(char*)&tmp.u.cfont; + int size = size0; + + tmp.type = 0x00; + tmp.u.cfont.dummy = 0xFF; + tmp.u.cfont.offsFile = wcslen(pszFont) + 1; + + size += (tmp.u.cfont.offsFile + wcslen(pszFile) + 1) * sizeof(WCHAR); + + pidl = (LPITEMIDLIST)SHAlloc(size + 4); + if (!pidl) + return pidl; + + pidl->mkid.cb = size+2; + memcpy(pidl->mkid.abID, &tmp, 2+size0); + + p = &((PIDLDATA*)pidl->mkid.abID)->u.cfont; + wcscpy(p->szName, pszFont); + wcscpy(p->szName + tmp.u.cfont.offsFile, pszFile); + + *(WORD*)((char*)pidl+(size+2)) = 0; + return pidl; +} + +static PIDLFontStruct * _ILGetFontStruct(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + + if (pdata && pdata->type==0x00) + return (PIDLFontStruct*)&(pdata->u.cfont); + + return NULL; +} + +/************************************************************************** + * CreateFontsEnumListss() + */ +BOOL CDesktopFolderEnumZ::CreateFontsEnumList(DWORD dwFlags) +{ + WCHAR szPath[MAX_PATH]; + WCHAR szName[LF_FACESIZE+20]; + WCHAR szFile[MAX_PATH]; + LPWSTR pszPath; + UINT Length; + LONG ret; + DWORD dwType, dwName, dwFile, dwIndex; + LPITEMIDLIST pidl; + HKEY hKey; + + if (dwFlags & SHCONTF_NONFOLDERS) + { + if (!SHGetSpecialFolderPathW(NULL, szPath, CSIDL_FONTS, FALSE)) + return FALSE; + + pszPath = PathAddBackslashW(szPath); + if (!pszPath) + return FALSE; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0, KEY_READ, &hKey)!= ERROR_SUCCESS) + return FALSE; + + Length = pszPath - szPath; + dwIndex = 0; + do + { + dwName = sizeof(szName)/sizeof(WCHAR); + dwFile = sizeof(szFile)/sizeof(WCHAR); + ret = RegEnumValueW(hKey, dwIndex++, szName, &dwName, NULL, &dwType, (LPBYTE)szFile, &dwFile); + if (ret == ERROR_SUCCESS) + { + szFile[(sizeof(szFile)/sizeof(WCHAR))-1] = L'\0'; + if (dwType == REG_SZ && wcslen(szFile) + Length + 1< (sizeof(szPath)/sizeof(WCHAR))) + { + wcscpy(&szPath[Length], szFile); + pidl = _ILCreateFontItem(szName, szPath); + TRACE("pidl %p name %s path %s\n", pidl, debugstr_w(szName), debugstr_w(szPath)); + if (pidl) + { + if (!AddToEnumList(pidl)) + SHFree(pidl); + } + } + } + }while(ret != ERROR_NO_MORE_ITEMS); + RegCloseKey(hKey); + + } + return TRUE; +} + +CFontsFolder::CFontsFolder() +{ + pidlRoot = NULL; + apidl = NULL; +} + +CFontsFolder::~CFontsFolder() +{ + TRACE("-- destroying IShellFolder(%p)\n", this); + SHFree(pidlRoot); +} + +HRESULT WINAPI CFontsFolder::FinalConstruct() +{ + pidlRoot = _ILCreateFont(); /* my qualified pidl */ + if (pidlRoot == NULL) + return E_OUTOFMEMORY; + return S_OK; +} + +/************************************************************************** +* ISF_Fonts_fnParseDisplayName +*/ +HRESULT WINAPI CFontsFolder::ParseDisplayName(HWND hwndOwner, LPBC pbcReserved, LPOLESTR lpszDisplayName, + DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes) +{ + HRESULT hr = E_UNEXPECTED; + + TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this, + hwndOwner, pbcReserved, lpszDisplayName, debugstr_w (lpszDisplayName), + pchEaten, ppidl, pdwAttributes); + + *ppidl = 0; + if (pchEaten) + *pchEaten = 0; /* strange but like the original */ + + TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr); + + return hr; +} + +/************************************************************************** +* ISF_Fonts_fnEnumObjects +*/ +HRESULT WINAPI CFontsFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) +{ + CComObject *theEnumerator; + CComPtr 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); + if (theEnumerator == NULL) + return E_OUTOFMEMORY; + hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result); + if (FAILED (hResult)) + { + delete theEnumerator; + return hResult; + } + hResult = theEnumerator->Initialize (dwFlags); + if (FAILED (hResult)) + return hResult; + *ppEnumIDList = result.Detach (); + + TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList); + + return S_OK; +} + +/************************************************************************** +* ISF_Fonts_fnBindToObject +*/ +HRESULT WINAPI CFontsFolder::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_Fonts_fnBindToStorage +*/ +HRESULT WINAPI CFontsFolder::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_Fonts_fnCompareIDs +*/ + +HRESULT WINAPI CFontsFolder::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_Fonts_fnCreateViewObject +*/ +HRESULT WINAPI CFontsFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) +{ + CComPtr 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_Fonts_fnGetAttributesOf +*/ +HRESULT WINAPI CFontsFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut) +{ + HRESULT hr = S_OK; + + 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) + { + CComPtr psfParent; + LPCITEMIDLIST rpidl = NULL; + + hr = SHBindToParent(pidlRoot, IID_IShellFolder, (LPVOID *)&psfParent, (LPCITEMIDLIST *)&rpidl); + if (SUCCEEDED(hr)) + SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut); + } + 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_Fonts_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 CFontsFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, + UINT * prgfInOut, LPVOID * ppvOut) +{ + LPITEMIDLIST pidl; + CComPtr pObj; + 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)) + { + pObj = (IContextMenu *)this; + this->apidl = apidl[0]; + hr = S_OK; + } + 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 + hr = E_NOINTERFACE; + + if (SUCCEEDED(hr) && !pObj) + hr = E_OUTOFMEMORY; + + *ppvOut = pObj.Detach(); + TRACE ("(%p)->hr=0x%08x\n", this, hr); + return hr; +} + +/************************************************************************** +* ISF_Fonts_fnGetDisplayNameOf +* +*/ +HRESULT WINAPI CFontsFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet) +{ + PIDLFontStruct * pfont; + + TRACE("ISF_Fonts_fnGetDisplayNameOf (%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); + pdump (pidl); + + if (!strRet) + return E_INVALIDARG; + + pfont = _ILGetFontStruct(pidl); + if (!pfont) + return E_INVALIDARG; + + strRet->pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(pfont->szName)+1) * sizeof(WCHAR)); + if (!strRet->pOleStr) + return E_OUTOFMEMORY; + + wcscpy(strRet->pOleStr, pfont->szName); + strRet->uType = STRRET_WSTR; + + return S_OK; +} + +/************************************************************************** +* ISF_Fonts_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 CFontsFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /*simple pidl */ + LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut) +{ + FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, + hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut); + return E_FAIL; +} + +HRESULT WINAPI CFontsFolder::GetDefaultSearchGUID(GUID *pguid) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CFontsFolder::EnumSearches(IEnumExtraSearch **ppenum) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CFontsFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) +{ + TRACE ("(%p)\n", this); + + if (pSort) + *pSort = 0; + if (pDisplay) + *pDisplay = 0; + + return S_OK; +} + +HRESULT WINAPI CFontsFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) +{ + TRACE ("(%p)\n", this); + + if (!pcsFlags || iColumn >= FontsSHELLVIEWCOLUMNS) + return E_INVALIDARG; + *pcsFlags = FontsSFHeader[iColumn].pcsFlags; + return S_OK; +} + +HRESULT WINAPI CFontsFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CFontsFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd) +{ + WCHAR buffer[MAX_PATH] = {0}; + HRESULT hr = E_FAIL; + PIDLFontStruct * pfont; + HANDLE hFile; + LARGE_INTEGER FileSize; + SHFILEINFOW fi; + + TRACE("(%p, %p, %d, %p)\n", this, pidl, iColumn, psd); + + if (iColumn >= FontsSHELLVIEWCOLUMNS) + return E_FAIL; + + psd->fmt = FontsSFHeader[iColumn].fmt; + psd->cxChar = FontsSFHeader[iColumn].cxChar; + if (pidl == NULL) + { + psd->str.uType = STRRET_WSTR; + if (LoadStringW(shell32_hInstance, FontsSFHeader[iColumn].colnameid, buffer, MAX_PATH)) + hr = SHStrDupW(buffer, &psd->str.pOleStr); + + return hr; + } + + if (iColumn == COLUMN_NAME) + { + psd->str.uType = STRRET_WSTR; + return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str); + } + + psd->str.uType = STRRET_CSTR; + psd->str.cStr[0] = '\0'; + + switch(iColumn) + { + case COLUMN_TYPE: + pfont = _ILGetFontStruct(pidl); + if (pfont) + { + if (SHGetFileInfoW(pfont->szName + pfont->offsFile, 0, &fi, sizeof(fi), SHGFI_TYPENAME)) + { + psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(fi.szTypeName)+1) * sizeof(WCHAR)); + if (!psd->str.pOleStr) + return E_OUTOFMEMORY; + wcscpy(psd->str.pOleStr, fi.szTypeName); + psd->str.uType = STRRET_WSTR; + return S_OK; + } + } + break; + case COLUMN_SIZE: + pfont = _ILGetFontStruct(pidl); + if (pfont) + { + hFile = CreateFileW(pfont->szName + pfont->offsFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + if (GetFileSizeEx(hFile, &FileSize)) + { + if (StrFormatByteSizeW(FileSize.QuadPart, buffer, sizeof(buffer)/sizeof(WCHAR))) + { + psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc(wcslen(buffer) + 1); + if (!psd->str.pOleStr) + return E_OUTOFMEMORY; + wcscpy(psd->str.pOleStr, buffer); + psd->str.uType = STRRET_WSTR; + CloseHandle(hFile); + return S_OK; + } + } + CloseHandle(hFile); + } + } + break; + case COLUMN_FILENAME: + pfont = _ILGetFontStruct(pidl); + if (pfont) + { + psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(pfont->szName + pfont->offsFile) + 1) * sizeof(WCHAR)); + if (psd->str.pOleStr) + { + psd->str.uType = STRRET_WSTR; + wcscpy(psd->str.pOleStr, pfont->szName + pfont->offsFile); + return S_OK; + } + else + return E_OUTOFMEMORY; + } + break; + } + + return E_FAIL; +} + +HRESULT WINAPI CFontsFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) +{ + FIXME ("(%p)\n", this); + + return E_NOTIMPL; +} + +/************************************************************************ + * INPFldr_PersistFolder2_GetClassID + */ +HRESULT WINAPI CFontsFolder::GetClassID(CLSID *lpClassId) +{ + TRACE ("(%p)\n", this); + + if (!lpClassId) + return E_POINTER; + + *lpClassId = CLSID_FontsFolderShortcut; + + return S_OK; +} + +/************************************************************************ + * INPFldr_PersistFolder2_Initialize + * + * NOTES: it makes no sense to change the pidl + */ +HRESULT WINAPI CFontsFolder::Initialize(LPCITEMIDLIST pidl) +{ + TRACE ("(%p)->(%p)\n", this, pidl); + + return E_NOTIMPL; +} + +/************************************************************************** + * IPersistFolder2_fnGetCurFolder + */ +HRESULT WINAPI CFontsFolder::GetCurFolder (LPITEMIDLIST *pidl) +{ + TRACE ("(%p)->(%p)\n", this, pidl); + + if (!pidl) + return E_POINTER; + + *pidl = ILClone (pidlRoot); + + return S_OK; +} + +/************************************************************************** +* IContextMenu2 Implementation +*/ + +/************************************************************************** +* ISF_Fonts_IContextMenu_QueryContextMenu() +*/ +HRESULT WINAPI CFontsFolder::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) +{ + WCHAR szBuffer[30] = {0}; + ULONG Count = 1; + + TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", + this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); + + if (LoadStringW(shell32_hInstance, IDS_OPEN, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_DEFAULT); + Count++; + } + + if (LoadStringW(shell32_hInstance, IDS_PRINT_VERB, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED); + } + + if (LoadStringW(shell32_hInstance, IDS_COPY, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED); + } + + if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED); + } + + if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED); + } + + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count); +} + +/************************************************************************** +* ISF_Fonts_IContextMenu_InvokeCommand() +*/ +HRESULT WINAPI CFontsFolder::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) +{ + SHELLEXECUTEINFOW sei; + PIDLFontStruct * pfont; + SHFILEOPSTRUCTW op; + + TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",this,lpcmi,lpcmi->lpVerb, lpcmi->hwnd); + + if (lpcmi->lpVerb == MAKEINTRESOURCEA(1) || lpcmi->lpVerb == MAKEINTRESOURCEA(2) || lpcmi->lpVerb == MAKEINTRESOURCEA(7)) + { + ZeroMemory(&sei, sizeof(sei)); + sei.cbSize = sizeof(sei); + sei.hwnd = lpcmi->hwnd; + sei.nShow = SW_SHOWNORMAL; + if (lpcmi->lpVerb == MAKEINTRESOURCEA(1)) + sei.lpVerb = L"open"; + else if (lpcmi->lpVerb == MAKEINTRESOURCEA(2)) + sei.lpVerb = L"print"; + else if (lpcmi->lpVerb == MAKEINTRESOURCEA(7)) + sei.lpVerb = L"properties"; + + pfont = _ILGetFontStruct(apidl); + sei.lpFile = pfont->szName + pfont->offsFile; + + if (ShellExecuteExW(&sei) == FALSE) + return E_FAIL; + } + else if (lpcmi->lpVerb == MAKEINTRESOURCEA(4)) + { + FIXME("implement font copying\n"); + return E_NOTIMPL; + } + else if (lpcmi->lpVerb == MAKEINTRESOURCEA(6)) + { + ZeroMemory(&op, sizeof(op)); + op.hwnd = lpcmi->hwnd; + op.wFunc = FO_DELETE; + op.fFlags = FOF_ALLOWUNDO; + pfont = _ILGetFontStruct(apidl); + op.pFrom = pfont->szName + pfont->offsFile; + SHFileOperationW(&op); + } + + return S_OK; +} + +/************************************************************************** + * ISF_Fonts_IContextMenu_GetCommandString() + * + */ +HRESULT WINAPI CFontsFolder::GetCommandString(UINT_PTR idCommand,UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen) +{ + TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); + + return E_FAIL; +} + +/************************************************************************** +* ISF_Fonts_IContextMenu_HandleMenuMsg() +*/ +HRESULT WINAPI CFontsFolder::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TRACE("ISF_Fonts_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n",this, uMsg, wParam, lParam); + + return E_NOTIMPL; +} diff --git a/reactos/dll/win32/shell32/shfldr_fonts.h b/reactos/dll/win32/shell32/shfldr_fonts.h new file mode 100644 index 00000000000..bce7bc3940a --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_fonts.h @@ -0,0 +1,95 @@ +/* + * Fonts folder + * + * Copyright 2008 Johannes Anderwald + * 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 + */ + +#ifndef _SHFLDR_FONTS_H_ +#define _SHFLDR_FONTS_H_ + +class CFontsFolder : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder2, + public IContextMenu2 +{ +private: + /* both paths are parsible from the desktop */ + LPITEMIDLIST pidlRoot; /* absolute pidl */ + LPCITEMIDLIST apidl; /* currently focused font item */ +public: + CFontsFolder(); + ~CFontsFolder(); + HRESULT WINAPI FinalConstruct(); + + // IShellFolder + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + /* ShellFolder2 */ + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand,UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen); + + // IContextMenu2 + virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); + +DECLARE_REGISTRY_RESOURCEID(IDR_FONTSFOLDERSHORTCUT) +DECLARE_NOT_AGGREGATABLE(CFontsFolder) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CFontsFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2) +END_COM_MAP() +}; + +#endif // _SHFLDR_FONTS_H_ diff --git a/reactos/dll/win32/shell32/shfldr_fs.cpp b/reactos/dll/win32/shell32/shfldr_fs.cpp new file mode 100644 index 00000000000..4151ced5e13 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_fs.cpp @@ -0,0 +1,1327 @@ + +/* + * file system folder + * + * Copyright 1997 Marcus Meissner + * Copyright 1998, 1999, 2002 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 + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL (shell); + +/* +CFileSysEnum should do an initial FindFirstFile and do a FindNextFile as each file is +returned by Next. When the enumerator is created, it can do numerous additional operations +including formatting a drive, reconnecting a network share drive, and requesting a disk +be inserted in a removable drive. +*/ + +/*********************************************************************** +* IShellFolder implementation +*/ + +class CFileSysEnum : + public IEnumIDListImpl +{ +private: +public: + CFileSysEnum(); + ~CFileSysEnum(); + HRESULT WINAPI Initialize(LPWSTR sPathTarget, DWORD dwFlags); + +BEGIN_COM_MAP(CFileSysEnum) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) +END_COM_MAP() +}; + +CFileSysEnum::CFileSysEnum() +{ +} + +CFileSysEnum::~CFileSysEnum() +{ +} + +HRESULT WINAPI CFileSysEnum::Initialize(LPWSTR sPathTarget, DWORD dwFlags) +{ + return CreateFolderEnumList(sPathTarget, dwFlags); +} + +/************************************************************************** +* registers clipboardformat once +*/ +void CFSFolder::SF_RegisterClipFmt() +{ + TRACE ("(%p)\n", this); + + if (!cfShellIDList) { + cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST); + } +} + +CFSFolder::CFSFolder() +{ + pclsid = (CLSID *)&CLSID_ShellFSFolder; + sPathTarget = NULL; + pidlRoot = NULL; + cfShellIDList = 0; + fAcceptFmt = FALSE; +} + +CFSFolder::~CFSFolder() +{ + TRACE ("-- destroying IShellFolder(%p)\n", this); + + SHFree (pidlRoot); + SHFree (sPathTarget); +} + + +static const shvheader GenericSFHeader[] = { + {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 GENERICSHELLVIEWCOLUMNS 5 + +/************************************************************************** + * SHELL32_CreatePidlFromBindCtx [internal] + * + * If the caller bound File System Bind Data, assume it is the + * find data for the path. + * This allows binding of paths that don't exist. + */ +LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path) +{ + static WCHAR szfsbc[] = { + 'F','i','l','e',' ','S','y','s','t','e','m',' ', + 'B','i','n','d',' ','D','a','t','a',0 }; + IFileSystemBindData *fsbd = NULL; + LPITEMIDLIST pidl = NULL; + IUnknown *param = NULL; + WIN32_FIND_DATAW wfd; + HRESULT r; + + TRACE("%p %s\n", pbc, debugstr_w(path)); + + if (!pbc) + return NULL; + + /* see if the caller bound File System Bind Data */ + r = pbc->GetObjectParam((LPOLESTR) szfsbc, ¶m ); + if (FAILED(r)) + return NULL; + + r = param->QueryInterface(IID_IFileSystemBindData, + (LPVOID*) &fsbd ); + if (SUCCEEDED(r)) + { + r = fsbd->GetFindData(&wfd ); + if (SUCCEEDED(r)) + { + lstrcpynW( &wfd.cFileName[0], path, MAX_PATH ); + pidl = _ILCreateFromFindDataW( &wfd ); + } + fsbd->Release(); + } + + return pidl; +} + +/************************************************************************** +* IShellFolder_ParseDisplayName {SHELL32} +* +* Parse a display name. +* +* PARAMS +* hwndOwner [in] Parent window for any message's +* pbc [in] optional FileSystemBindData context +* lpszDisplayName [in] Unicode displayname. +* pchEaten [out] (unicode) characters processed +* ppidl [out] complex pidl to item +* pdwAttributes [out] items attributes +* +* NOTES +* Every folder tries to parse only its own (the leftmost) pidl and creates a +* subfolder to evaluate the remaining parts. +* Now we can parse into namespaces implemented by shell extensions +* +* Behaviour on win98: lpszDisplayName=NULL -> crash +* lpszDisplayName="" -> returns mycoputer-pidl +* +* FIXME +* pdwAttributes is not set +* pchEaten is not set like in windows +*/ +HRESULT WINAPI CFSFolder::ParseDisplayName(HWND hwndOwner, + LPBC pbc, + LPOLESTR lpszDisplayName, + DWORD *pchEaten, LPITEMIDLIST *ppidl, + DWORD *pdwAttributes) +{ + HRESULT hr = E_INVALIDARG; + LPCWSTR szNext = NULL; + WCHAR szElement[MAX_PATH]; + WCHAR szPath[MAX_PATH]; + LPITEMIDLIST pidlTemp = NULL; + DWORD len; + + 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 */ + + pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName); + if (!pidlTemp && *lpszDisplayName) + { + /* get the next element */ + szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH); + + /* build the full pathname to the element */ + lstrcpynW(szPath, sPathTarget, MAX_PATH - 1); + PathAddBackslashW(szPath); + len = wcslen(szPath); + lstrcpynW(szPath + len, szElement, MAX_PATH - len); + + /* get the pidl */ + hr = _ILCreateFromPathW(szPath, &pidlTemp); + + if (SUCCEEDED(hr)) { + if (szNext && *szNext) { + /* try to analyse the next element */ + hr = SHELL32_ParseNextElement (this, hwndOwner, pbc, + &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes); + } else { + /* it's the last element */ + if (pdwAttributes && *pdwAttributes) { + hr = SHELL32_GetItemAttributes (this, + pidlTemp, pdwAttributes); + } + } + } + } + + if (SUCCEEDED(hr)) + *ppidl = pidlTemp; + else + *ppidl = NULL; + + TRACE ("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl ? *ppidl : 0, hr); + + return hr; +} + +/************************************************************************** +* IShellFolder_fnEnumObjects +* PARAMETERS +* HWND hwndOwner, //[in ] Parent Window +* DWORD grfFlags, //[in ] SHCONTF enumeration mask +* LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface +*/ +HRESULT WINAPI CFSFolder::EnumObjects (HWND hwndOwner, + DWORD dwFlags, LPENUMIDLIST * ppEnumIDList) +{ + CComObject *theEnumerator; + CComPtr 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); + if (theEnumerator == NULL) + return E_OUTOFMEMORY; + hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result); + if (FAILED (hResult)) + { + delete theEnumerator; + return hResult; + } + hResult = theEnumerator->Initialize (sPathTarget, dwFlags); + if (FAILED (hResult)) + return hResult; + *ppEnumIDList = result.Detach (); + + TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList); + + return S_OK; +} + +/************************************************************************** +* IShellFolder_fnBindToObject +* PARAMETERS +* LPCITEMIDLIST pidl, //[in ] relative pidl to open +* LPBC pbc, //[in ] optional FileSystemBindData context +* REFIID riid, //[in ] Initial Interface +* LPVOID* ppvObject //[out] Interface* +*/ +HRESULT WINAPI CFSFolder::BindToObject(LPCITEMIDLIST pidl, + LPBC pbc, REFIID riid, LPVOID * ppvOut) +{ + TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl, pbc, + shdebugstr_guid (&riid), ppvOut); + + return SHELL32_BindToChild (pidlRoot, sPathTarget, pidl, riid, + ppvOut); +} + +/************************************************************************** +* IShellFolder_fnBindToStorage +* PARAMETERS +* LPCITEMIDLIST pidl, //[in ] complex pidl to store +* LPBC pbc, //[in ] reserved +* REFIID riid, //[in ] Initial storage interface +* LPVOID* ppvObject //[out] Interface* returned +*/ +HRESULT WINAPI CFSFolder::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; +} + +/************************************************************************** +* IShellFolder_fnCompareIDs +*/ + +HRESULT WINAPI CFSFolder::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; +} + +/************************************************************************** +* IShellFolder_fnCreateViewObject +*/ +HRESULT WINAPI CFSFolder::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) { + *ppvOut = NULL; + + if (IsEqualIID (riid, IID_IDropTarget)) { + hr = this->QueryInterface (IID_IDropTarget, ppvOut); + } else if (IsEqualIID (riid, IID_IContextMenu)) { + FIXME ("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; +} + +/************************************************************************** +* IShellFolder_fnGetAttributesOf +* +* PARAMETERS +* UINT cidl, //[in ] num elements in pidl array +* LPCITEMIDLIST* apidl, //[in ] simple pidl array +* ULONG* rgfInOut) //[out] result array +* +*/ +HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl, + LPCITEMIDLIST * apidl, DWORD * rgfInOut) +{ + HRESULT hr = S_OK; + + 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){ + IShellFolder *psfParent = NULL; + LPCITEMIDLIST rpidl = NULL; + + hr = SHBindToParent(pidlRoot, IID_IShellFolder, (LPVOID*)&psfParent, (LPCITEMIDLIST*)&rpidl); + if(SUCCEEDED(hr)) { + SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut); + psfParent->Release(); + } + } + 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; +} + +/************************************************************************** +* IShellFolder_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 +* +* NOTES +* This function gets asked to return "view objects" for one or more (multiple +* select) items: +* The viewobject typically is an COM object with one of the following +* interfaces: +* IExtractIcon,IDataObject,IContextMenu +* In order to support icon positions in the default Listview your DataObject +* must implement the SetData method (in addition to GetData :) - the shell +* passes a barely documented "Icon positions" structure to SetData when the +* drag starts, and GetData's it if the drop is in another explorer window that +* needs the positions. +*/ +HRESULT WINAPI CFSFolder::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) { + *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)){ + if (cidl >= 1) { + hr = IDataObject_Constructor (hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj); + } + else + { + hr = IDataObject_Constructor (hwndOwner, pidlRoot, (LPCITEMIDLIST*)&pidlRoot, 1, (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; +} + +static const WCHAR AdvancedW[] = { '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','\\','A','d','v','a','n','c','e','d',0 }; +static const WCHAR HideFileExtW[] = { 'H','i','d','e','F','i','l','e','E','x', + 't',0 }; +static const WCHAR NeverShowExtW[] = { 'N','e','v','e','r','S','h','o','w','E', + 'x','t',0 }; + +/****************************************************************************** + * SHELL_FS_HideExtension [Internal] + * + * Query the registry if the filename extension of a given path should be + * hidden. + * + * PARAMS + * szPath [I] Relative or absolute path of a file + * + * RETURNS + * TRUE, if the filename's extension should be hidden + * FALSE, otherwise. + */ +BOOL SHELL_FS_HideExtension(LPWSTR szPath) +{ + HKEY hKey; + DWORD dwData; + DWORD dwDataSize = sizeof (DWORD); + BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */ + + if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) { + if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize)) + doHide = dwData; + RegCloseKey (hKey); + } + + if (!doHide) { + LPWSTR ext = PathFindExtensionW(szPath); + + if (*ext != '\0') { + WCHAR classname[MAX_PATH]; + LONG classlen = sizeof(classname); + + if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen)) + if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) { + if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL)) + doHide = TRUE; + RegCloseKey(hKey); + } + } + } + return doHide; +} + +void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags) +{ + /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */ + if (!(dwFlags & SHGDN_FORPARSING) && + ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) { + if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.') + PathRemoveExtensionW(szPath); + } +} + +/************************************************************************** +* IShellFolder_fnGetDisplayNameOf +* Retrieves the display name for the specified file object or subfolder +* +* PARAMETERS +* LPCITEMIDLIST pidl, //[in ] complex pidl to item +* DWORD dwFlags, //[in ] SHGNO formatting flags +* LPSTRRET lpName) //[out] Returned display name +* +* FIXME +* if the name is in the pidl the ret value should be a STRRET_OFFSET +*/ + +HRESULT WINAPI CFSFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, + DWORD dwFlags, LPSTRRET strRet) +{ + LPWSTR pszPath; + + HRESULT hr = S_OK; + int len = 0; + + TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); + pdump (pidl); + + if (!pidl || !strRet) + return E_INVALIDARG; + + pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); + if (!pszPath) + return E_OUTOFMEMORY; + + if (_ILIsDesktop(pidl)) { /* empty pidl */ + if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && + (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER)) + { + if (sPathTarget) + lstrcpynW(pszPath, sPathTarget, MAX_PATH); + } else { + /* pidl has to contain exactly one non null SHITEMID */ + hr = E_INVALIDARG; + } + } else if (_ILIsPidlSimple(pidl)) { + if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) && + (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) && + sPathTarget) + { + lstrcpynW(pszPath, sPathTarget, MAX_PATH); + PathAddBackslashW(pszPath); + len = wcslen(pszPath); + } + _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len); + if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags); + } else { + 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)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr)); + return hr; +} + +/************************************************************************** +* IShellFolder_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 CFSFolder::SetNameOf (HWND hwndOwner, + LPCITEMIDLIST pidl, + LPCOLESTR lpName, + DWORD dwFlags, + LPITEMIDLIST * pPidlOut) +{ + 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); + + /* 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); + } + } + + TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest)); + if (!memcmp(szSrc, szDest, (wcslen(szDest)+1) * sizeof(WCHAR))) + { + /* src and destination is the same */ + HRESULT hr = S_OK; + if (pPidlOut) + hr = _ILCreateFromPathW(szDest, pPidlOut); + + return hr; + } + + + if (MoveFileW (szSrc, szDest)) { + HRESULT 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 CFSFolder::GetDefaultSearchGUID(GUID * pguid) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CFSFolder::EnumSearches(IEnumExtraSearch ** ppenum) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CFSFolder::GetDefaultColumn(DWORD dwRes, + ULONG * pSort, ULONG * pDisplay) +{ + TRACE ("(%p)\n", this); + + if (pSort) + *pSort = 0; + if (pDisplay) + *pDisplay = 0; + + return S_OK; +} + +HRESULT WINAPI CFSFolder::GetDefaultColumnState(UINT iColumn, + DWORD * pcsFlags) +{ + TRACE ("(%p)\n", this); + + if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS) + return E_INVALIDARG; + + *pcsFlags = GenericSFHeader[iColumn].pcsFlags; + + return S_OK; +} + +HRESULT WINAPI CFSFolder::GetDetailsEx(LPCITEMIDLIST pidl, + const SHCOLUMNID * pscid, VARIANT * pv) +{ + FIXME ("(%p)\n", this); + + return E_NOTIMPL; +} + +HRESULT WINAPI CFSFolder::GetDetailsOf(LPCITEMIDLIST pidl, + UINT iColumn, SHELLDETAILS * psd) +{ + HRESULT hr = E_FAIL; + + TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd); + + if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS) + return E_INVALIDARG; + + if (!pidl) { + /* the header titles */ + psd->fmt = GenericSFHeader[iColumn].fmt; + psd->cxChar = GenericSFHeader[iColumn].cxChar; + psd->str.uType = STRRET_CSTR; + LoadStringA (shell32_hInstance, GenericSFHeader[iColumn].colnameid, + psd->str.cStr, MAX_PATH); + return S_OK; + } else { + hr = S_OK; + psd->str.uType = STRRET_CSTR; + /* the data from the pidl */ + 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 CFSFolder::MapColumnToSCID (UINT column, + SHCOLUMNID * pscid) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +/**************************************************************************** + * ISFHelper for IShellFolder implementation + */ + +/**************************************************************************** + * ISFHelper_fnAddFolder + * + * creates a unique folder name + */ + +HRESULT WINAPI CFSFolder::GetUniqueName(LPWSTR pwszName, UINT uLen) +{ + 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; + } + } + + penum->Release(); + } + return hr; +} + +/**************************************************************************** + * ISFHelper_fnAddFolder + * + * adds a new folder. + */ + +HRESULT WINAPI CFSFolder::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); + } else { + WCHAR wszText[128 + MAX_PATH]; + WCHAR wszTempText[128]; + WCHAR wszCaption[256]; + + /* Cannot Create folder because of permissions */ + LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText, + sizeof (wszTempText)); + LoadStringW (shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption, + sizeof (wszCaption)); + swprintf (wszText, wszTempText, wszNewDir); + MessageBoxW (hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION); + } + + return hres; +} + +/**************************************************************************** + * build_paths_list + * + * Builds a list of paths like the one used in SHFileOperation from a table of + * PIDLs relative to the given base folder + */ +WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls) +{ + WCHAR *wszPathsList; + WCHAR *wszListPos; + int iPathLen; + int i; + + iPathLen = wcslen(wszBasePath); + wszPathsList = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, MAX_PATH*sizeof(WCHAR)*cidl+1); + wszListPos = wszPathsList; + + for (i = 0; i < cidl; i++) { + if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i])) + continue; + + lstrcpynW(wszListPos, wszBasePath, MAX_PATH); + /* FIXME: abort if path too long */ + _ILSimpleGetTextW(pidls[i], wszListPos+iPathLen, MAX_PATH-iPathLen); + wszListPos += wcslen(wszListPos)+1; + } + *wszListPos=0; + return wszPathsList; +} + +/**************************************************************************** + * ISFHelper_fnDeleteItems + * + * deletes items in folder + */ +HRESULT WINAPI CFSFolder::DeleteItems(UINT cidl, LPCITEMIDLIST * apidl) +{ + UINT i; + SHFILEOPSTRUCTW op; + WCHAR wszPath[MAX_PATH]; + WCHAR *wszPathsList; + HRESULT ret; + WCHAR *wszCurrentPath; + + TRACE ("(%p)(%u %p)\n", this, cidl, apidl); + if (cidl==0) return S_OK; + + 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; +} + +/**************************************************************************** + * ISFHelper_fnCopyItems + * + * copies items to this folder + */ +HRESULT WINAPI CFSFolder::CopyItems(IShellFolder * pSFFrom, UINT cidl, + LPCITEMIDLIST * apidl) +{ + IPersistFolder2 *ppf2 = NULL; + WCHAR szSrcPath[MAX_PATH]; + WCHAR szTargetPath[MAX_PATH]; + SHFILEOPSTRUCTW op; + LPITEMIDLIST pidl; + LPWSTR pszSrc, pszTarget, pszSrcList, pszTargetList, pszFileName; + int res, length; + HRESULT hr; + STRRET strRet; + + TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom, cidl, apidl); + + hr = pSFFrom->QueryInterface (IID_IPersistFolder2, (LPVOID *) & ppf2); + if (SUCCEEDED(hr)) + { + if (FAILED(ppf2->GetCurFolder(&pidl))) + { + ppf2->Release(); + return E_FAIL; + } + ppf2->Release(); + + 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); + ppf2->Release (); + 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; +} + +/************************************************************************ + * IFSFldr_PersistFolder3_GetClassID + */ +HRESULT WINAPI CFSFolder::GetClassID(CLSID * lpClassId) +{ + TRACE ("(%p)\n", this); + + if (!lpClassId) + return E_POINTER; + *lpClassId = *pclsid; + + return S_OK; +} + +/************************************************************************ + * IFSFldr_PersistFolder3_Initialize + * + * NOTES + * sPathTarget is not set. Don't know how to handle in a non rooted environment. + */ +HRESULT WINAPI CFSFolder::Initialize (LPCITEMIDLIST pidl) +{ + WCHAR wszTemp[MAX_PATH]; + + TRACE ("(%p)->(%p)\n", this, pidl); + + SHFree (pidlRoot); /* free the old pidl */ + pidlRoot = ILClone (pidl); /* set my pidl */ + + SHFree (sPathTarget); + sPathTarget = NULL; + + /* set my path */ + if (SHGetPathFromIDListW (pidl, wszTemp)) { + int len = wcslen(wszTemp); + sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); + if (!sPathTarget) + return E_OUTOFMEMORY; + memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); + } + + TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget)); + return S_OK; +} + +/************************************************************************** + * IFSFldr_PersistFolder3_GetCurFolder + */ +HRESULT WINAPI CFSFolder::GetCurFolder(LPITEMIDLIST * pidl) +{ + TRACE ("(%p)->(%p)\n", this, pidl); + + if (!pidl) return E_POINTER; + *pidl = ILClone (pidlRoot); + return S_OK; +} + +/************************************************************************** + * IFSFldr_PersistFolder3_InitializeEx + * + * FIXME: error handling + */ +HRESULT WINAPI CFSFolder::InitializeEx(IBindCtx * pbc, LPCITEMIDLIST pidlRootx, + const PERSIST_FOLDER_TARGET_INFO * ppfti) +{ + WCHAR wszTemp[MAX_PATH]; + + TRACE ("(%p)->(%p,%p,%p)\n", this, pbc, pidlRootx, ppfti); + if (ppfti) + TRACE ("--%p %s %s 0x%08x 0x%08x\n", + ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName), + debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes, + ppfti->csidl); + + pdump (pidlRootx); + if (ppfti && ppfti->pidlTargetFolder) + pdump (ppfti->pidlTargetFolder); + + if (pidlRoot) + __SHFreeAndNil (&pidlRoot); /* free the old */ + if (sPathTarget) + __SHFreeAndNil (&sPathTarget); + + /* + * Root path and pidl + */ + pidlRoot = ILClone (pidlRootx); + + /* + * the target folder is spezified in csidl OR pidlTargetFolder OR + * szTargetParsingName + */ + if (ppfti) { + if (ppfti->csidl != -1) { + if (SHGetSpecialFolderPathW (0, wszTemp, ppfti->csidl, + ppfti->csidl & CSIDL_FLAG_CREATE)) { + int len = wcslen(wszTemp); + sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); + if (!sPathTarget) + return E_OUTOFMEMORY; + memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); + } + } else if (ppfti->szTargetParsingName[0]) { + int len = wcslen(ppfti->szTargetParsingName); + sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); + if (!sPathTarget) + return E_OUTOFMEMORY; + memcpy(sPathTarget, ppfti->szTargetParsingName, + (len + 1) * sizeof(WCHAR)); + } else if (ppfti->pidlTargetFolder) { + if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) { + int len = wcslen(wszTemp); + sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); + if (!sPathTarget) + return E_OUTOFMEMORY; + memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); + } + } + } + + TRACE ("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget)); + pdump (pidlRoot); + return (sPathTarget) ? S_OK : E_FAIL; +} + +HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti) +{ + FIXME ("(%p)->(%p)\n", this, ppfti); + ZeroMemory (ppfti, sizeof (*ppfti)); + return E_NOTIMPL; +} + +/**************************************************************************** + * ISFDropTarget implementation + */ +BOOL CFSFolder::QueryDrop (DWORD dwKeyState, + LPDWORD pdwEffect) +{ + DWORD dwEffect = *pdwEffect; + + *pdwEffect = DROPEFFECT_NONE; + + if (fAcceptFmt) { /* Does our interpretation of the keystate ... */ + *pdwEffect = KeyStateToDropEffect (dwKeyState); + + /* ... matches the desired effect ? */ + if (dwEffect & *pdwEffect) { + return TRUE; + } + } + return FALSE; +} + +HRESULT WINAPI CFSFolder::DragEnter (IDataObject * pDataObject, + DWORD dwKeyState, POINTL pt, DWORD * pdwEffect) +{ + FORMATETC fmt; + + TRACE ("(%p)->(DataObject=%p)\n", this, pDataObject); + + InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL); + + fAcceptFmt = (S_OK == pDataObject->QueryGetData(&fmt)) ? + TRUE : FALSE; + + QueryDrop(dwKeyState, pdwEffect); + + return S_OK; +} + +HRESULT WINAPI CFSFolder::DragOver (DWORD dwKeyState, POINTL pt, + DWORD * pdwEffect) +{ + TRACE ("(%p)\n", this); + + if (!pdwEffect) + return E_INVALIDARG; + + QueryDrop(dwKeyState, pdwEffect); + + return S_OK; +} + +HRESULT WINAPI CFSFolder::DragLeave () +{ + TRACE ("(%p)\n", this); + + fAcceptFmt = FALSE; + + return S_OK; +} + +HRESULT WINAPI CFSFolder::Drop (IDataObject * pDataObject, + DWORD dwKeyState, POINTL pt, DWORD * pdwEffect) +{ + FIXME ("(%p) object dropped\n", this); + + return E_NOTIMPL; +} diff --git a/reactos/dll/win32/shell32/shfldr_fs.h b/reactos/dll/win32/shell32/shfldr_fs.h new file mode 100644 index 00000000000..6523659b602 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_fs.h @@ -0,0 +1,112 @@ +/* + * file system 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 + */ + +#ifndef _CFSFOLDER_H_ +#define _CFSFOLDER_H_ + +class CFSFolder : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder3, + public IDropTarget, + public ISFHelper +{ +private: + CLSID *pclsid; + + /* both paths are parsible from the desktop */ + LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */ + + LPITEMIDLIST pidlRoot; /* absolute pidl */ + + UINT cfShellIDList; /* clipboardformat for IDropTarget */ + BOOL fAcceptFmt; /* flag for pending Drop */ +public: + CFSFolder(); + ~CFSFolder(); + void SF_RegisterClipFmt(); + BOOL QueryDrop (DWORD dwKeyState, LPDWORD pdwEffect); + + // IShellFolder + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + /* ShellFolder2 */ + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + + // IPersistFolder3 + virtual HRESULT WINAPI InitializeEx(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *ppfti); + virtual HRESULT WINAPI GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO *ppfti); + + // IDropTarget + virtual HRESULT WINAPI DragEnter(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); + virtual HRESULT WINAPI DragOver(DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); + virtual HRESULT WINAPI DragLeave(); + virtual HRESULT WINAPI Drop(IDataObject *pDataObject, DWORD dwKeyState, POINTL pt, DWORD *pdwEffect); + + // ISFHelper + virtual HRESULT WINAPI GetUniqueName(LPWSTR pwszName, UINT uLen); + virtual HRESULT WINAPI AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut); + virtual HRESULT WINAPI DeleteItems(UINT cidl, LPCITEMIDLIST *apidl); + virtual HRESULT WINAPI CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl); + +DECLARE_REGISTRY_RESOURCEID(IDR_SHELLFSFOLDER) +DECLARE_NOT_AGGREGATABLE(CFSFolder) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CFSFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder3, IPersistFolder3) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) + COM_INTERFACE_ENTRY_IID(IID_ISFHelper, ISFHelper) +END_COM_MAP() +}; + +#endif // _CFSFOLDER_H_ diff --git a/reactos/dll/win32/shell32/shfldr_mycomp.cpp b/reactos/dll/win32/shell32/shfldr_mycomp.cpp new file mode 100644 index 00000000000..58f7607f8b5 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_mycomp.cpp @@ -0,0 +1,876 @@ +/* + * 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 + +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 *theEnumerator; + CComPtr 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); + + 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; +} diff --git a/reactos/dll/win32/shell32/shfldr_mycomp.h b/reactos/dll/win32/shell32/shfldr_mycomp.h new file mode 100644 index 00000000000..cdc892c83eb --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_mycomp.h @@ -0,0 +1,85 @@ +/* + * 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 + */ + +#ifndef _CDRIVESFOLDER_H_ +#define _CDRIVESFOLDER_H_ + +class CDrivesFolder : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder2 +{ +private: + /* both paths are parsible from the desktop */ + LPITEMIDLIST pidlRoot; /* absolute pidl */ + LPWSTR sName; +public: + CDrivesFolder(); + ~CDrivesFolder(); + HRESULT WINAPI FinalConstruct(); + + // IShellFolder + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + /* ShellFolder2 */ + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + +DECLARE_REGISTRY_RESOURCEID(IDR_MYCOMPUTER) +DECLARE_NOT_AGGREGATABLE(CDrivesFolder) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CDrivesFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) +END_COM_MAP() +}; + +#endif // _CDRIVESFOLDER_H_ diff --git a/reactos/dll/win32/shell32/shfldr_mydocuments.cpp b/reactos/dll/win32/shell32/shfldr_mydocuments.cpp new file mode 100644 index 00000000000..9de26e02ee5 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_mydocuments.cpp @@ -0,0 +1,686 @@ +/* + * Virtual MyDocuments Folder + * + * Copyright 2007 Johannes Anderwald + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL (mydocs); + +/* +CFileSysEnumX should not exist. CMyDocsFolder should aggregate a CFSFolder which always +maps the contents of CSIDL_PERSONAL. Therefore, CMyDocsFolder::EnumObjects simply calls +CFSFolder::EnumObjects. +*/ + +/*********************************************************************** +* MyDocumentsfolder implementation +*/ + +class CFileSysEnumX : + public IEnumIDListImpl +{ +private: +public: + CFileSysEnumX(); + ~CFileSysEnumX(); + HRESULT WINAPI Initialize(DWORD dwFlags); + +BEGIN_COM_MAP(CFileSysEnumX) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) +END_COM_MAP() +}; + +static const shvheader MyDocumentsSFHeader[] = { + {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 MYDOCUMENTSSHELLVIEWCOLUMNS 5 + +CFileSysEnumX::CFileSysEnumX() +{ +} + +CFileSysEnumX::~CFileSysEnumX() +{ +} + +HRESULT WINAPI CFileSysEnumX::Initialize(DWORD dwFlags) +{ + WCHAR szPath[MAX_PATH]; + + if (SHGetSpecialFolderPathW(0, szPath, CSIDL_PERSONAL, FALSE) == FALSE) + return E_FAIL; + return CreateFolderEnumList(szPath, dwFlags); +} + +CMyDocsFolder::CMyDocsFolder() +{ + pidlRoot = NULL; + sPathTarget = NULL; +} + +CMyDocsFolder::~CMyDocsFolder() +{ + TRACE ("-- destroying IShellFolder(%p)\n", this); + SHFree(pidlRoot); + HeapFree(GetProcessHeap(), 0, sPathTarget); +} + +HRESULT WINAPI CMyDocsFolder::FinalConstruct() +{ + WCHAR szMyPath[MAX_PATH]; + + if (!SHGetSpecialFolderPathW(0, szMyPath, CSIDL_PERSONAL, TRUE)) + return E_UNEXPECTED; + + pidlRoot = _ILCreateMyDocuments(); /* my qualified pidl */ + sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR)); + wcscpy(sPathTarget, szMyPath); + + return S_OK; +} + +HRESULT WINAPI CMyDocsFolder::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 (!lpszDisplayName || !ppidl) + return E_INVALIDARG; + + *ppidl = 0; + + 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( (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 = _ILCreateMyDocuments(); + + 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(this, + pidlTemp, pdwAttributes); + } + } + + *ppidl = pidlTemp; + + TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr); + + return hr; +} + +/************************************************************************** + * ISF_MyDocuments_fnEnumObjects + */ +HRESULT WINAPI CMyDocsFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) +{ + CComObject *theEnumerator; + CComPtr 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); + if (theEnumerator == NULL) + return E_OUTOFMEMORY; + hResult = theEnumerator->QueryInterface (IID_IEnumIDList, (void **)&result); + if (FAILED (hResult)) + { + delete theEnumerator; + return hResult; + } + hResult = theEnumerator->Initialize (dwFlags); + if (FAILED (hResult)) + return hResult; + *ppEnumIDList = result.Detach (); + + TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList); + + return S_OK; +} + +/************************************************************************** + * ISF_MyDocuments_fnBindToObject + */ +HRESULT WINAPI CMyDocsFolder::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_MyDocuments_fnBindToStorage + */ +HRESULT WINAPI CMyDocsFolder::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_MyDocuments_fnCompareIDs + */ +HRESULT WINAPI CMyDocsFolder::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_MyDocuments_fnCreateViewObject + */ +HRESULT WINAPI CMyDocsFolder::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_MyDocuments_fnGetAttributesOf + */ +HRESULT WINAPI CMyDocsFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut) +{ + HRESULT hr = S_OK; + static const DWORD dwMyDocumentsAttributes = + 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 &= dwMyDocumentsAttributes; + } else { + while (cidl > 0 && *apidl) { + pdump (*apidl); + if (_ILIsMyDocuments(*apidl)) { + *rgfInOut &= dwMyDocumentsAttributes; + } else { + 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_MyDocuments_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 CMyDocsFolder::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; +} + +HRESULT WINAPI CMyDocsFolder::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; + + ZeroMemory(pszPath, (MAX_PATH +1) * sizeof(WCHAR)); + + if (_ILIsMyDocuments (pidl)) + { + if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) && + (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)) + wcscpy(pszPath, sPathTarget); + else + HCR_GetClassNameW(CLSID_MyDocuments, pszPath, MAX_PATH); + TRACE("CP\n"); + } + 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_MyDocuments)) + { + 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); + TRACE("CP\n"); + } + else + { + /* parsing name like ::{...} */ + pszPath[0] = ':'; + pszPath[1] = ':'; + SHELL32_GUIDToStringW (*clsid, &pszPath[2]); + TRACE("CP\n"); + } + } + else + { + /* user friendly name */ + HCR_GetClassNameW (*clsid, pszPath, MAX_PATH); + TRACE("CP\n"); + } + } + 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); + TRACE("CP %s\n", debugstr_w(pszPath)); + } + + if (!_ILIsDesktop(pidl)) + { + PathAddBackslashW(pszPath); + cLen = wcslen(pszPath); + _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen); + if (!_ILIsFolder(pidl)) + { + SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags); + TRACE("CP\n"); + } + } + } + } + else + { + /* a complex pidl, let the subfolder do the work */ + hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags, + pszPath, MAX_PATH); + TRACE("CP\n"); + } + + if (SUCCEEDED(hr)) + { + strRet->uType = STRRET_WSTR; + strRet->pOleStr = pszPath; + } + else + CoTaskMemFree(pszPath); + + TRACE ("-- (%p)->(%s,0x%08x)\n", this, debugstr_w(strRet->pOleStr), hr); + return hr; +} + +HRESULT WINAPI CMyDocsFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */ + LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut) +{ + FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, + debugstr_w (lpName), dwFlags, pPidlOut); + + return E_FAIL; +} + +HRESULT WINAPI CMyDocsFolder::GetDefaultSearchGUID(GUID *pguid) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CMyDocsFolder::EnumSearches(IEnumExtraSearch **ppenum) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CMyDocsFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) +{ + TRACE ("(%p)\n", this); + + if (pSort) + *pSort = 0; + if (pDisplay) + *pDisplay = 0; + + return S_OK; +} + +HRESULT WINAPI CMyDocsFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) +{ + TRACE ("(%p)\n", this); + + if (!pcsFlags || iColumn >= MYDOCUMENTSSHELLVIEWCOLUMNS) + return E_INVALIDARG; + + *pcsFlags = MyDocumentsSFHeader[iColumn].pcsFlags; + + return S_OK; +} + +HRESULT WINAPI CMyDocsFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv) +{ + FIXME ("(%p)\n", this); + + return E_NOTIMPL; +} + +HRESULT WINAPI CMyDocsFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd) +{ + HRESULT hr = S_OK; + + TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd); + + if (!psd || iColumn >= MYDOCUMENTSSHELLVIEWCOLUMNS) + return E_INVALIDARG; + + if (!pidl) + { + psd->fmt = MyDocumentsSFHeader[iColumn].fmt; + psd->cxChar = MyDocumentsSFHeader[iColumn].cxChar; + psd->str.uType = STRRET_CSTR; + LoadStringA (shell32_hInstance, MyDocumentsSFHeader[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 CMyDocsFolder::MapColumnToSCID (UINT column, SHCOLUMNID *pscid) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CMyDocsFolder::GetClassID(CLSID *lpClassId) +{ + static GUID const CLSID_MyDocuments = + { 0x450d8fba, 0xad25, 0x11d0, {0x98,0xa8,0x08,0x00,0x36,0x1b,0x11,0x03} }; + + TRACE ("(%p)\n", this); + + if (!lpClassId) + return E_POINTER; + + memcpy(lpClassId, &CLSID_MyDocuments, sizeof(GUID)); + + return S_OK; +} + +HRESULT WINAPI CMyDocsFolder::Initialize(LPCITEMIDLIST pidl) +{ + TRACE ("(%p)->(%p)\n", this, pidl); + + return E_NOTIMPL; +} + +HRESULT WINAPI CMyDocsFolder::GetCurFolder(LPITEMIDLIST *pidl) +{ + TRACE ("(%p)->(%p)\n", this, pidl); + + if (!pidl) return E_POINTER; + *pidl = ILClone (pidlRoot); + return S_OK; +} diff --git a/reactos/dll/win32/shell32/shfldr_mydocuments.h b/reactos/dll/win32/shell32/shfldr_mydocuments.h new file mode 100644 index 00000000000..add9965f700 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_mydocuments.h @@ -0,0 +1,84 @@ +/* + * Virtual MyDocuments Folder + * + * Copyright 2007 Johannes Anderwald + * 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 + */ + +#ifndef _SHFLDR_MYDOCUMENTS_H_ +#define _SHFLDR_MYDOCUMENTS_H_ + +class CMyDocsFolder : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder2 +{ +private: + /* both paths are parsible from the MyDocuments */ + LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */ + LPITEMIDLIST pidlRoot; /* absolute pidl */ +public: + CMyDocsFolder(); + ~CMyDocsFolder(); + HRESULT WINAPI FinalConstruct(); + + // IShellFolder + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + /* ShellFolder2 */ + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + +DECLARE_REGISTRY_RESOURCEID(IDR_MYDOCUMENTS) +DECLARE_NOT_AGGREGATABLE(CMyDocsFolder) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CMyDocsFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) +END_COM_MAP() +}; + +#endif // _SHFLDR_MYDOCUMENTS_H_ diff --git a/reactos/dll/win32/shell32/shfldr_netplaces.cpp b/reactos/dll/win32/shell32/shfldr_netplaces.cpp new file mode 100644 index 00000000000..9406b738f52 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_netplaces.cpp @@ -0,0 +1,432 @@ +/* + * Network Places (Neighbourhood) folder + * + * Copyright 1997 Marcus Meissner + * Copyright 1998, 1999, 2002 Juergen Schmied + * Copyright 2003 Mike McCormack for Codeweavers + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL (shell); + +/*********************************************************************** +* IShellFolder implementation +*/ + +static shvheader NetworkPlacesSFHeader[] = { + {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN13, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10}, + {IDS_SHV_COLUMN_WORKGROUP, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_NETWORKLOCATION, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15} +}; + +#define COLUMN_NAME 0 +#define COLUMN_CATEGORY 1 +#define COLUMN_WORKGROUP 2 +#define COLUMN_NETLOCATION 3 + +#define NETWORKPLACESSHELLVIEWCOLUMNS 4 + +CNetFolder::CNetFolder() +{ + pidlRoot = NULL; +} + +CNetFolder::~CNetFolder() +{ + TRACE("-- destroying IShellFolder(%p)\n", this); + SHFree(pidlRoot); +} + +HRESULT WINAPI CNetFolder::FinalConstruct() +{ + pidlRoot = _ILCreateNetHood(); /* my qualified pidl */ + if (pidlRoot == NULL) + return E_OUTOFMEMORY; + return S_OK; +} + +/************************************************************************** +* ISF_NetworkPlaces_fnParseDisplayName +*/ +HRESULT WINAPI CNetFolder::ParseDisplayName(HWND hwndOwner, LPBC pbcReserved, LPOLESTR lpszDisplayName, + DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes) +{ + HRESULT hr = E_UNEXPECTED; + + TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this, + hwndOwner, pbcReserved, lpszDisplayName, debugstr_w (lpszDisplayName), + pchEaten, ppidl, pdwAttributes); + + *ppidl = 0; + if (pchEaten) + *pchEaten = 0; /* strange but like the original */ + + TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr); + + return hr; +} + +/************************************************************************** +* ISF_NetworkPlaces_fnEnumObjects +*/ +HRESULT WINAPI CNetFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) +{ + TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, + hwndOwner, dwFlags, ppEnumIDList); + + *ppEnumIDList = NULL; //IEnumIDList_Constructor(); + + TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList); + return S_FALSE; + // return (*ppEnumIDList) ? S_OK : E_OUTOFMEMORY; +} + +/************************************************************************** +* ISF_NetworkPlaces_fnBindToObject +*/ +HRESULT WINAPI CNetFolder::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_NetworkPlaces_fnBindToStorage +*/ +HRESULT WINAPI CNetFolder::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_NetworkPlaces_fnCompareIDs +*/ + +HRESULT WINAPI CNetFolder::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_NetworkPlaces_fnCreateViewObject +*/ +HRESULT WINAPI CNetFolder::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_NetworkPlaces_fnGetAttributesOf +*/ +HRESULT WINAPI CNetFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut) +{ + static const DWORD dwNethoodAttributes = + SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | + SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE; + HRESULT hr = S_OK; + + 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 = dwNethoodAttributes; + } + 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_NetworkPlaces_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 CNetFolder::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 + hr = E_NOINTERFACE; + + if (SUCCEEDED(hr) && !pObj) + hr = E_OUTOFMEMORY; + + *ppvOut = pObj; + TRACE ("(%p)->hr=0x%08x\n", this, hr); + return hr; +} + +/************************************************************************** +* ISF_NetworkPlaces_fnGetDisplayNameOf +* +*/ +HRESULT WINAPI CNetFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet) +{ + FIXME ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); + pdump (pidl); + + if (!strRet) + return E_INVALIDARG; + + return E_NOTIMPL; +} + +/************************************************************************** +* ISF_NetworkPlaces_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 CNetFolder::SetNameOf (HWND hwndOwner, LPCITEMIDLIST pidl, /*simple pidl */ + LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut) +{ + FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, + hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut); + return E_FAIL; +} + +HRESULT WINAPI CNetFolder::GetDefaultSearchGUID(GUID *pguid) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CNetFolder::EnumSearches(IEnumExtraSearch ** ppenum) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CNetFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay) +{ + TRACE ("(%p)\n", this); + + if (pSort) + *pSort = 0; + if (pDisplay) + *pDisplay = 0; + + return S_OK; +} + +HRESULT WINAPI CNetFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) +{ + TRACE ("(%p)\n", this); + + if (!pcsFlags || iColumn >= NETWORKPLACESSHELLVIEWCOLUMNS) + return E_INVALIDARG; + *pcsFlags = NetworkPlacesSFHeader[iColumn].pcsFlags; + return S_OK; +} + +HRESULT WINAPI CNetFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CNetFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd) +{ + WCHAR buffer[MAX_PATH] = {0}; + HRESULT hr = E_FAIL; + + if (iColumn >= NETWORKPLACESSHELLVIEWCOLUMNS) + return E_FAIL; + + psd->fmt = NetworkPlacesSFHeader[iColumn].fmt; + psd->cxChar = NetworkPlacesSFHeader[iColumn].cxChar; + if (pidl == NULL) + { + psd->str.uType = STRRET_WSTR; + if (LoadStringW(shell32_hInstance, NetworkPlacesSFHeader[iColumn].colnameid, buffer, MAX_PATH)) + hr = SHStrDupW(buffer, &psd->str.pOleStr); + + return hr; + } + + if (iColumn == COLUMN_NAME) + return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str); + + FIXME ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd); + + return E_NOTIMPL; +} + +HRESULT WINAPI CNetFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) +{ + FIXME ("(%p)\n", this); + + return E_NOTIMPL; +} + +/************************************************************************ + * INPFldr_PersistFolder2_GetClassID + */ +HRESULT WINAPI CNetFolder::GetClassID(CLSID *lpClassId) +{ + TRACE ("(%p)\n", this); + + if (!lpClassId) + return E_POINTER; + + *lpClassId = CLSID_NetworkPlaces; + + return S_OK; +} + +/************************************************************************ + * INPFldr_PersistFolder2_Initialize + * + * NOTES: it makes no sense to change the pidl + */ +HRESULT WINAPI CNetFolder::Initialize(LPCITEMIDLIST pidl) +{ + TRACE ("(%p)->(%p)\n", this, pidl); + + return E_NOTIMPL; +} + +/************************************************************************** + * IPersistFolder2_fnGetCurFolder + */ +HRESULT WINAPI CNetFolder::GetCurFolder(LPITEMIDLIST *pidl) +{ + TRACE ("(%p)->(%p)\n", this, pidl); + + if (!pidl) + return E_POINTER; + + *pidl = ILClone (pidlRoot); + + return S_OK; +} diff --git a/reactos/dll/win32/shell32/shfldr_netplaces.h b/reactos/dll/win32/shell32/shfldr_netplaces.h new file mode 100644 index 00000000000..8f9cc477c7c --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_netplaces.h @@ -0,0 +1,85 @@ +/* + * Network Places (Neighbourhood) folder + * + * Copyright 1997 Marcus Meissner + * Copyright 1998, 1999, 2002 Juergen Schmied + * Copyright 2003 Mike McCormack for Codeweavers + * 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 + */ + +#ifndef _SHFLDR_NETPLACES_H_ +#define _SHFLDR_NETPLACES_H_ + +class CNetFolder : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder2 +{ +private: + /* both paths are parsible from the desktop */ + LPITEMIDLIST pidlRoot; /* absolute pidl */ +public: + CNetFolder(); + ~CNetFolder(); + HRESULT WINAPI FinalConstruct(); + + // IShellFolder + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + /* ShellFolder2 */ + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + +DECLARE_REGISTRY_RESOURCEID(IDR_NETWORKPLACES) +DECLARE_NOT_AGGREGATABLE(CNetFolder) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CNetFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) +END_COM_MAP() +}; + +#endif // _SHFLDR_NETPLACES_H_ diff --git a/reactos/dll/win32/shell32/shfldr_printers.cpp b/reactos/dll/win32/shell32/shfldr_printers.cpp new file mode 100644 index 00000000000..05650aa716f --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_printers.cpp @@ -0,0 +1,729 @@ +/* + * Virtual Printers Folder + * + * Copyright 1997 Marcus Meissner + * Copyright 1998, 1999, 2002 Juergen Schmied + * Copyright 2005 Huw Davies + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL (shell); + +/*********************************************************************** + * Printers_IExtractIconW implementation + */ +class IExtractIconWImpl : + public CComObjectRootEx, + public IExtractIconW, + public IExtractIconA +{ +private: + LPITEMIDLIST pidl; +public: + IExtractIconWImpl(); + ~IExtractIconWImpl(); + HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IExtractIconW + virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags); + virtual HRESULT STDMETHODCALLTYPE Extract(LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); + + // IExtractIconA + virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags); + virtual HRESULT STDMETHODCALLTYPE Extract(LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize); + +BEGIN_COM_MAP(IExtractIconWImpl) + COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW) + COM_INTERFACE_ENTRY_IID(IID_IExtractIconA, IExtractIconA) +END_COM_MAP() +}; + +static shvheader PrinterSFHeader[] = { + {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN_DOCUMENTS , SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN_STATUS, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN_LOCATION, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}, + {IDS_SHV_COLUMN_MODEL, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15} +}; + +#define COLUMN_NAME 0 +#define COLUMN_DOCUMENTS 1 +#define COLUMN_STATUS 2 +#define COLUMN_COMMENTS 3 +#define COLUMN_LOCATION 4 +#define COLUMN_MODEL 5 + + +#define PrinterSHELLVIEWCOLUMNS (6) + +IExtractIconWImpl::IExtractIconWImpl() +{ + pidl = NULL; +} + +IExtractIconWImpl::~IExtractIconWImpl() +{ + TRACE(" destroying IExtractIcon(%p)\n", this); + SHFree(pidl); +} + +HRESULT WINAPI IExtractIconWImpl::Initialize(LPCITEMIDLIST pidl) +{ + pidl = ILClone(pidl); + + pdump(pidl); + return S_OK; +} + +/************************************************************************** + * IExtractIconW_GetIconLocation + * + * mapping filetype to icon + */ +HRESULT WINAPI IExtractIconWImpl::GetIconLocation(UINT uFlags, /* GIL_ flags */ + LPWSTR szIconFile, + UINT cchMax, + int *piIndex, + UINT *pwFlags) /* returned GIL_ flags */ +{ + TRACE("(%p) (flags=%u %p %u %p %p)\n", this, uFlags, szIconFile, cchMax, piIndex, pwFlags); + + if (pwFlags) + *pwFlags = 0; + + lstrcpynW(szIconFile, swShell32Name, cchMax); + *piIndex = -IDI_SHELL_PRINTERS_FOLDER; /* FIXME: other icons for default, network, print to file */ + + TRACE("-- %s %x\n", debugstr_w(szIconFile), *piIndex); + return NOERROR; +} + +/************************************************************************** + * IExtractIconW_Extract + */ +HRESULT WINAPI IExtractIconWImpl::Extract(LPCWSTR pszFile, + UINT nIconIndex, HICON *phiconLarge, + HICON *phiconSmall, UINT nIconSize) +{ + int index; + + FIXME("(%p) (file=%p index=%d %p %p size=%x) semi-stub\n", this, debugstr_w(pszFile), + (signed)nIconIndex, phiconLarge, phiconSmall, nIconSize); + + index = SIC_GetIconIndex(pszFile, nIconIndex, 0); + + if (phiconLarge) + *phiconLarge = ImageList_GetIcon(ShellBigIconList, index, ILD_TRANSPARENT); + + if (phiconSmall) + *phiconSmall = ImageList_GetIcon(ShellSmallIconList, index, ILD_TRANSPARENT); + + return S_OK; +} + +/************************************************************************** + * IExtractIconA_GetIconLocation + */ +HRESULT WINAPI IExtractIconWImpl::GetIconLocation(UINT uFlags, + LPSTR szIconFile, + UINT cchMax, + int * piIndex, + UINT * pwFlags) +{ + HRESULT ret; + LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR)); + + TRACE("(%p) (flags=%u %p %u %p %p)\n", this, uFlags, szIconFile, cchMax, piIndex, pwFlags); + + ret = GetIconLocation(uFlags, lpwstrFile, cchMax, piIndex, pwFlags); + WideCharToMultiByte(CP_ACP, 0, lpwstrFile, -1, szIconFile, cchMax, NULL, NULL); + HeapFree(GetProcessHeap(), 0, lpwstrFile); + + TRACE("-- %s %x\n", szIconFile, *piIndex); + return ret; +} +/************************************************************************** + * IExtractIconA_Extract + */ +HRESULT WINAPI IExtractIconWImpl::Extract(LPCSTR pszFile, + UINT nIconIndex, HICON *phiconLarge, + HICON *phiconSmall, UINT nIconSize) +{ + HRESULT ret; + INT len = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0); + LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + TRACE("(%p) (file=%p index=%u %p %p size=%u)\n", this, pszFile, nIconIndex, phiconLarge, phiconSmall, nIconSize); + + MultiByteToWideChar(CP_ACP, 0, pszFile, -1, lpwstrFile, len); + ret = Extract(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIconSize); + HeapFree(GetProcessHeap(), 0, lpwstrFile); + return ret; +} + +/************************************************************************** + * IExtractIcon_Constructor + */ +static HRESULT WINAPI IEI_Printers_Constructor(LPCITEMIDLIST pidl, REFIID riid, IUnknown **ppv) +{ + CComObject *theExtractor; + CComPtr result; + HRESULT hResult; + + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; + ATLTRY (theExtractor = new CComObject); + if (theExtractor == NULL) + return E_OUTOFMEMORY; + hResult = theExtractor->QueryInterface (riid, (void **)&result); + if (FAILED (hResult)) + { + delete theExtractor; + return hResult; + } + hResult = theExtractor->Initialize (pidl); + if (FAILED (hResult)) + return hResult; + *ppv = result.Detach (); + return S_OK; +} + +/*********************************************************************** + * Printers folder implementation + */ + +class CPrintersEnum : + public IEnumIDListImpl +{ +private: +public: + CPrintersEnum(); + ~CPrintersEnum(); + HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags); + BOOL CreatePrintersEnumList(DWORD dwFlags); + +BEGIN_COM_MAP(CPrintersEnum) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) +END_COM_MAP() +}; + +CPrintersEnum::CPrintersEnum() +{ +} + +CPrintersEnum::~CPrintersEnum() +{ +} + +HRESULT WINAPI CPrintersEnum::Initialize(HWND hwndOwner, DWORD dwFlags) +{ + if (CreatePrintersEnumList(dwFlags) == FALSE) + return E_FAIL; + return S_OK; +} + +static LPITEMIDLIST _ILCreatePrinterItem(PRINTER_INFO_4W *pi) +{ + PIDLDATA tmp; + LPITEMIDLIST pidl; + PIDLPrinterStruct * p; + int size0 = (char*)&tmp.u.cprinter.szName-(char*)&tmp.u.cprinter; + int size = size0; + + tmp.type = 0x00; + tmp.u.cprinter.dummy = 0xFF; + if (pi->pPrinterName) + tmp.u.cprinter.offsServer = wcslen(pi->pPrinterName) + 1; + else + tmp.u.cprinter.offsServer = 1; + + size += tmp.u.cprinter.offsServer * sizeof(WCHAR); + if (pi->pServerName) + size += ( + wcslen(pi->pServerName) + 1) * sizeof(WCHAR); + else + size += sizeof(WCHAR); + + pidl = (LPITEMIDLIST)SHAlloc(size + 4); + if (!pidl) + return pidl; + + pidl->mkid.cb = size+2; + memcpy(pidl->mkid.abID, &tmp, 2+size0); + + p = &((PIDLDATA*)pidl->mkid.abID)->u.cprinter; + + p->Attributes = pi->Attributes; + if (pi->pPrinterName) + wcscpy(p->szName, pi->pPrinterName); + else + p->szName[0] = L'\0'; + + if (pi->pServerName) + wcscpy(p->szName + p->offsServer, pi->pServerName); + else + p->szName[p->offsServer] = L'\0'; + + *(WORD*)((char*)pidl+(size+2)) = 0; + return pidl; +} + +/************************************************************************** + * CreatePrintersEnumList() + */ +BOOL CPrintersEnum::CreatePrintersEnumList(DWORD dwFlags) +{ + BOOL ret = TRUE; + + TRACE("(%p)->(flags=0x%08lx) \n", this, dwFlags); + + /* enumerate the folders */ + if (dwFlags & SHCONTF_NONFOLDERS) + { + DWORD needed = 0, num = 0, i; + PRINTER_INFO_4W *pi; + + EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &needed, &num); + if (!needed) + return ret; + + pi = (PRINTER_INFO_4W *)HeapAlloc(GetProcessHeap(), 0, needed); + if(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, (LPBYTE)pi, needed, &needed, &num)) { + HeapFree(GetProcessHeap(), 0, pi); + return FALSE; + } + + for(i = 0; i < num; i++) { + LPITEMIDLIST pidl = _ILCreatePrinterItem(&pi[i]); + if (pidl) + { + if (!AddToEnumList(pidl)) + SHFree(pidl); + } + } + HeapFree(GetProcessHeap(), 0, pi); + } + return ret; +} + +CPrinterFolder::CPrinterFolder() +{ + pidlRoot = NULL; + dwAttributes = 0; + pclsid = NULL; +} + +CPrinterFolder::~CPrinterFolder() +{ + TRACE("-- destroying IShellFolder(%p)\n", this); + if (pidlRoot) + SHFree(pidlRoot); +} + +HRESULT WINAPI CPrinterFolder::FinalConstruct() +{ + pidlRoot = _ILCreatePrinters(); /* my qualified pidl */ + if (pidlRoot == NULL) + return E_OUTOFMEMORY; + return S_OK; +} + +/************************************************************************** + * ISF_Printers_fnParseDisplayName + * + * This is E_NOTIMPL in Windows too. + */ +HRESULT WINAPI CPrinterFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, + DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes) +{ + 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; + + return E_NOTIMPL; +} + +static PIDLPrinterStruct * _ILGetPrinterStruct(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + + if (pdata && pdata->type==0x00) + return (PIDLPrinterStruct*)&(pdata->u.cfont); + + return NULL; +} + +/************************************************************************** + * ISF_Printers_fnEnumObjects + */ +HRESULT WINAPI CPrinterFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList) +{ + CComObject *theEnumerator; + CComPtr 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); + 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_Printers_fnBindToObject + */ +HRESULT WINAPI CPrinterFolder::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_Printers_fnBindToStorage + */ +HRESULT WINAPI CPrinterFolder::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_Printers_fnCompareIDs + */ +HRESULT WINAPI CPrinterFolder::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_Printers_fnCreateViewObject + */ +HRESULT WINAPI CPrinterFolder::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_Printers_fnGetAttributesOf + */ +HRESULT WINAPI CPrinterFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut) +{ + static const DWORD dwPrintersAttributes = + SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE; + HRESULT hr = S_OK; + + FIXME ("(%p)->(cidl=%d apidl=%p mask=0x%08lx): stub\n", + this, cidl, apidl, *rgfInOut); + + *rgfInOut &= dwPrintersAttributes; + + *rgfInOut &= ~SFGAO_VALIDATE; + + TRACE ("-- result=0x%08x\n", *rgfInOut); + return hr; +} + +/************************************************************************** + * ISF_Printers_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 CPrinterFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, + REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) +{ + 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_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1)) + { + hr = IEI_Printers_Constructor(apidl[0], riid, &pObj); + } + else + hr = E_NOINTERFACE; + + if (SUCCEEDED(hr) && !pObj) + hr = E_OUTOFMEMORY; + + *ppvOut = pObj; + TRACE ("(%p)->hr=0x%08lx\n", this, hr); + return hr; +} + +/************************************************************************** + * ISF_Printers_fnGetDisplayNameOf + * + */ +HRESULT WINAPI CPrinterFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet) +{ + LPWSTR pszName; + PIDLPrinterStruct * p; + + TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", this, pidl, dwFlags, strRet); + pdump (pidl); + + if (!strRet) + { + WARN("no strRet\n"); + return E_INVALIDARG; + } + + if (_ILIsPrinter(pidl)) + { + pszName = (LPWSTR)CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR)); + if (!pszName) + return E_OUTOFMEMORY; + + if (LoadStringW(shell32_hInstance, IDS_PRINTERS, pszName, MAX_PATH)) + { + pszName[MAX_PATH-1] = L'\0'; + strRet->uType = STRRET_WSTR; + strRet->pOleStr = pszName; + return S_OK; + } + CoTaskMemFree(pszName); + return E_FAIL; + } + + p = _ILGetPrinterStruct(pidl); + if (!p) + { + WARN("no printer struct\n"); + return E_INVALIDARG; + } + strRet->pOleStr = (LPWSTR)SHAlloc(p->offsServer * sizeof(WCHAR)); + if (!strRet->pOleStr) + return E_OUTOFMEMORY; + + memcpy((LPVOID)strRet->pOleStr, (LPVOID)p->szName, p->offsServer * sizeof(WCHAR)); + TRACE("ret %s\n", debugstr_w(strRet->pOleStr)); + + return S_OK; +} + +/************************************************************************** + * ISF_Printers_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 CPrinterFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */ + LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut) +{ + FIXME ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", this, hwndOwner, pidl, + debugstr_w (lpName), dwFlags, pPidlOut); + + return E_FAIL; +} + +HRESULT WINAPI CPrinterFolder::GetDefaultSearchGUID(GUID *pguid) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CPrinterFolder::EnumSearches (IEnumExtraSearch **ppenum) +{ + FIXME ("(%p)\n", this); + return E_NOTIMPL; +} + +HRESULT WINAPI CPrinterFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay) +{ + if (pSort) + *pSort = 0; + if (pDisplay) + *pDisplay = 0; + + return S_OK; +} + +HRESULT WINAPI CPrinterFolder::GetDefaultColumnState (UINT iColumn, DWORD *pcsFlags) +{ + if (!pcsFlags || iColumn >= PrinterSHELLVIEWCOLUMNS) + return E_INVALIDARG; + *pcsFlags = PrinterSFHeader[iColumn].pcsFlags; + return S_OK; + +} + +HRESULT WINAPI CPrinterFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv) +{ + FIXME ("(%p): stub\n", this); + + return E_NOTIMPL; +} + +HRESULT WINAPI CPrinterFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd) +{ + WCHAR buffer[MAX_PATH] = {0}; + HRESULT hr = E_FAIL; + + TRACE("(%p)->(%p %i %p): stub\n", this, pidl, iColumn, psd); + + if (iColumn >= PrinterSHELLVIEWCOLUMNS) + return E_FAIL; + + psd->fmt = PrinterSFHeader[iColumn].fmt; + psd->cxChar = PrinterSFHeader[iColumn].cxChar; + if (pidl == NULL) + { + psd->str.uType = STRRET_WSTR; + if (LoadStringW(shell32_hInstance, PrinterSFHeader[iColumn].colnameid, buffer, MAX_PATH)) + hr = SHStrDupW(buffer, &psd->str.pOleStr); + + return hr; + } + + if (iColumn == COLUMN_NAME) + { + psd->str.uType = STRRET_WSTR; + return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str); + } + + psd->str.uType = STRRET_CSTR; + psd->str.cStr[0] = '\0'; + + return E_NOTIMPL; +} + +HRESULT WINAPI CPrinterFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid) +{ + FIXME ("(%p): stub\n", this); + return E_NOTIMPL; +} + +/************************************************************************ + * IPF_Printers_GetClassID + */ +HRESULT WINAPI CPrinterFolder::GetClassID (CLSID *lpClassId) +{ + TRACE ("(%p)\n", this); + + *lpClassId = CLSID_Printers; + + return S_OK; +} + +/************************************************************************ + * IPF_Printers_Initialize + * + */ +HRESULT WINAPI CPrinterFolder::Initialize(LPCITEMIDLIST pidl) +{ + if (pidlRoot) + SHFree((LPVOID)pidlRoot); + + pidlRoot = ILClone(pidl); + return S_OK; +} + +/************************************************************************** + * IPF_Printers_fnGetCurFolder + */ +HRESULT WINAPI CPrinterFolder::GetCurFolder(LPITEMIDLIST * pidl) +{ + TRACE ("(%p)->(%p)\n", this, pidl); + + *pidl = ILClone (pidlRoot); + return S_OK; +} diff --git a/reactos/dll/win32/shell32/shfldr_printers.h b/reactos/dll/win32/shell32/shfldr_printers.h new file mode 100644 index 00000000000..174b698d977 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_printers.h @@ -0,0 +1,88 @@ +/* + * Virtual Printers Folder + * + * Copyright 1997 Marcus Meissner + * Copyright 1998, 1999, 2002 Juergen Schmied + * Copyright 2005 Huw Davies + * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _SHFLDR_PRINTERS_H_ +#define _SHFLDR_PRINTERS_H_ + +class CPrinterFolder : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder2 +{ +private: + CLSID *pclsid; + + LPITEMIDLIST pidlRoot; /* absolute pidl */ + + int dwAttributes; /* attributes returned by GetAttributesOf FIXME: use it */ +public: + CPrinterFolder(); + ~CPrinterFolder(); + HRESULT WINAPI FinalConstruct(); + + // IShellFolder + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + /* ShellFolder2 */ + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + +DECLARE_REGISTRY_RESOURCEID(IDR_PRINTERS) +DECLARE_NOT_AGGREGATABLE(CPrinterFolder) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CPrinterFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) +END_COM_MAP() +}; + +#endif // _SHFLDR_PRINTERS_H_ diff --git a/reactos/dll/win32/shell32/shfldr_recyclebin.cpp b/reactos/dll/win32/shell32/shfldr_recyclebin.cpp new file mode 100644 index 00000000000..6dc121753d0 --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_recyclebin.cpp @@ -0,0 +1,1415 @@ +/* + * Trash virtual folder support. The trashing engine is implemented in trash.c + * + * Copyright (C) 2006 Mikolaj Zalewski + * Copyright (C) 2009 Andrew Hill + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define MAX_PROPERTY_SHEET_PAGE 32 + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(CBitBucket); + +typedef struct +{ + int column_name_id; + const GUID *fmtId; + DWORD pid; + int pcsFlags; + int fmt; + int cxChars; +} columninfo; + +static const columninfo CBitBucketColumns[] = +{ + {IDS_SHV_COLUMN1, &FMTID_Storage, PID_STG_NAME, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30}, + {IDS_SHV_COLUMN_DELFROM, &FMTID_Displaced, PID_DISPLACED_FROM, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30}, + {IDS_SHV_COLUMN_DELDATE, &FMTID_Displaced, PID_DISPLACED_DATE, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20}, + {IDS_SHV_COLUMN2, &FMTID_Storage, PID_STG_SIZE, SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 20}, + {IDS_SHV_COLUMN3, &FMTID_Storage, PID_STG_STORAGETYPE,SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20}, + {IDS_SHV_COLUMN4, &FMTID_Storage, PID_STG_WRITETIME, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20}, +/* {"creation time", &FMTID_Storage, PID_STG_CREATETIME, SHCOLSTATE_TYPE_DATE, LVCFMT_LEFT, 20}, */ +/* {"attribs", &FMTID_Storage, PID_STG_ATTRIBUTES, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 20}, */ +}; + +#define COLUMN_NAME 0 +#define COLUMN_DELFROM 1 +#define COLUMN_DATEDEL 2 +#define COLUMN_SIZE 3 +#define COLUMN_TYPE 4 +#define COLUMN_MTIME 5 + +#define COLUMNS_COUNT 6 + +/* + * Recycle Bin folder + */ + +class CBitBucketEnum : + public IEnumIDListImpl +{ +private: +public: + CBitBucketEnum(); + ~CBitBucketEnum(); + HRESULT WINAPI Initialize(DWORD dwFlags); + static BOOL WINAPI CBEnumBitBucket(IN PVOID Context, IN HANDLE hDeletedFile); + BOOL WINAPI CBEnumBitBucket(IN HANDLE hDeletedFile); + +BEGIN_COM_MAP(CBitBucketEnum) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) +END_COM_MAP() +}; + +class CCBitBucketBackgroundContextMenu : + public CComObjectRootEx, + public IContextMenu2 +{ +private: + INT iIdEmpty; +public: + CCBitBucketBackgroundContextMenu(); + ~CCBitBucketBackgroundContextMenu(); + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand,UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen); + + // IContextMenu2 + virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); + +BEGIN_COM_MAP(CCBitBucketBackgroundContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2) +END_COM_MAP() +}; + +class CCBitBucketItemContextMenu : + public CComObjectRootEx, + public IContextMenu2 +{ +private: + LPITEMIDLIST apidl; +public: + CCBitBucketItemContextMenu(); + ~CCBitBucketItemContextMenu(); + HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand,UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen); + + // IContextMenu2 + virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); + +BEGIN_COM_MAP(CCBitBucketItemContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2) +END_COM_MAP() +}; + +typedef struct +{ + PIDLRecycleStruct *pFileDetails; + HANDLE hDeletedFile; + BOOL bFound; +}SEARCH_CONTEXT, *PSEARCH_CONTEXT; + +typedef struct +{ + DWORD dwNukeOnDelete; + DWORD dwSerial; + DWORD dwMaxCapacity; +}DRIVE_ITEM_CONTEXT, *PDRIVE_ITEM_CONTEXT; + +BOOL WINAPI CBSearchBitBucket(IN PVOID Context, IN HANDLE hDeletedFile) +{ + PSEARCH_CONTEXT pContext = (PSEARCH_CONTEXT)Context; + + PDELETED_FILE_DETAILS_W pFileDetails; + DWORD dwSize; + BOOL ret; + + if (!GetDeletedFileDetailsW(hDeletedFile, + 0, + NULL, + &dwSize) && + GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + ERR("GetDeletedFileDetailsW failed\n"); + return FALSE; + } + + pFileDetails = (DELETED_FILE_DETAILS_W *)SHAlloc(dwSize); + if (!pFileDetails) + { + ERR("No memory\n"); + return FALSE; + } + + if (!GetDeletedFileDetailsW(hDeletedFile, + dwSize, + pFileDetails, + NULL)) + { + ERR("GetDeletedFileDetailsW failed\n"); + SHFree(pFileDetails); + return FALSE; + } + + ret = memcmp(pFileDetails, pContext->pFileDetails, dwSize); + if (!ret) + { + pContext->hDeletedFile = hDeletedFile; + pContext->bFound = TRUE; + } + else + CloseRecycleBinHandle(hDeletedFile); + + SHFree(pFileDetails); + return ret; +} + +static PIDLRecycleStruct * _ILGetRecycleStruct(LPCITEMIDLIST pidl) +{ + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + + if (pdata && pdata->type==0x00) + return (PIDLRecycleStruct*)&(pdata->u.crecycle); + + return NULL; +} + +CBitBucketEnum::CBitBucketEnum() +{ +} + +CBitBucketEnum::~CBitBucketEnum() +{ +} + +HRESULT WINAPI CBitBucketEnum::Initialize(DWORD dwFlags) +{ + static LPCWSTR szDrive = L"C:\\"; + + if (dwFlags & SHCONTF_NONFOLDERS) + { + TRACE("Starting Enumeration\n"); + + if (!EnumerateRecycleBinW(szDrive /* FIXME */ , CBEnumBitBucket, (PVOID)this)) + { + WARN("Error: EnumerateCBitBucketW failed\n"); + return E_FAIL; + } + } + else + { + // do nothing + } + return S_OK; +} + +static LPITEMIDLIST _ILCreateRecycleItem(PDELETED_FILE_DETAILS_W pFileDetails) +{ + PIDLDATA tmp; + LPITEMIDLIST pidl; + PIDLRecycleStruct * p; + int size0 = (char*)&tmp.u.crecycle.szName-(char*)&tmp.u.crecycle; + int size = size0; + + tmp.type = 0x00; + size += (wcslen(pFileDetails->FileName) + 1) * sizeof(WCHAR); + + pidl = (LPITEMIDLIST)SHAlloc(size + 4); + if (!pidl) + return pidl; + + pidl->mkid.cb = size+2; + memcpy(pidl->mkid.abID, &tmp, 2+size0); + + p = &((PIDLDATA*)pidl->mkid.abID)->u.crecycle; + RtlCopyMemory(p, pFileDetails, sizeof(DELETED_FILE_DETAILS_W)); + wcscpy(p->szName, pFileDetails->FileName); + *(WORD*)((char*)pidl+(size+2)) = 0; + return pidl; +} + +BOOL WINAPI CBitBucketEnum::CBEnumBitBucket(IN PVOID Context, IN HANDLE hDeletedFile) +{ + return ((CBitBucketEnum *)Context)->CBEnumBitBucket(hDeletedFile); +} + +BOOL WINAPI CBitBucketEnum::CBEnumBitBucket(IN HANDLE hDeletedFile) +{ + PDELETED_FILE_DETAILS_W pFileDetails; + DWORD dwSize; + LPITEMIDLIST pidl = NULL; + BOOL ret; + + if (!GetDeletedFileDetailsW(hDeletedFile, + 0, + NULL, + &dwSize) && + GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + ERR("GetDeletedFileDetailsW failed\n"); + return FALSE; + } + + pFileDetails = (DELETED_FILE_DETAILS_W *)SHAlloc(dwSize); + if (!pFileDetails) + { + ERR("No memory\n"); + return FALSE; + } + + if (!GetDeletedFileDetailsW(hDeletedFile, + dwSize, + pFileDetails, + NULL)) + { + ERR("GetDeletedFileDetailsW failed\n"); + SHFree(pFileDetails); + return FALSE; + } + + pidl = _ILCreateRecycleItem(pFileDetails); + if (!pidl) + { + SHFree(pFileDetails); + return FALSE; + } + + ret = AddToEnumList(pidl); + + if (!ret) + SHFree(pidl); + SHFree(pFileDetails); + TRACE("Returning %d\n", ret); + CloseRecycleBinHandle(hDeletedFile); + return ret; +} + +/************************************************************************* + * BitBucket context menu + * + */ + +CCBitBucketBackgroundContextMenu::CCBitBucketBackgroundContextMenu() +{ + iIdEmpty = 0; +} + +CCBitBucketBackgroundContextMenu::~CCBitBucketBackgroundContextMenu() +{ +} + +HRESULT WINAPI CCBitBucketBackgroundContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) +{ + WCHAR szBuffer[100]; + MENUITEMINFOW mii; + int id = 1; + + TRACE("%p %p %u %u %u %u\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags ); + + if (!hMenu) + return E_INVALIDARG; + + memset(&mii, 0, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; + mii.fState = MFS_ENABLED; + szBuffer[0] = L'\0'; + LoadStringW(shell32_hInstance, IDS_EMPTY_BITBUCKET, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)); + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + mii.dwTypeData = szBuffer; + mii.cch = wcslen( mii.dwTypeData ); + mii.wID = idCmdFirst + id++; + mii.fType = MFT_STRING; + iIdEmpty = 1; + + if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii)) + return E_FAIL; + + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id); +} + +HRESULT WINAPI CCBitBucketBackgroundContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) +{ + HRESULT hr; + LPSHELLBROWSER lpSB; + LPSHELLVIEW lpSV = NULL; + + TRACE("%p %p verb %p\n", this, lpcmi, lpcmi->lpVerb); + + if (LOWORD(lpcmi->lpVerb) == iIdEmpty) + { + // FIXME + // path & flags + hr = SHEmptyRecycleBinW(lpcmi->hwnd, L"C:\\", 0); + TRACE("result %x\n", hr); + if (hr != S_OK) + return hr; + + lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0); + if (lpSB && SUCCEEDED(lpSB->QueryActiveShellView(&lpSV))) + lpSV->Refresh(); + } + return S_OK; +} + +HRESULT WINAPI CCBitBucketBackgroundContextMenu::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen) +{ + FIXME("%p %lu %u %p %p %u\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); + + return E_NOTIMPL; +} + +HRESULT WINAPI CCBitBucketBackgroundContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TRACE("CBitBucket_IContextMenu2Item_IContextMenu2Folder_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam); + + return E_NOTIMPL; +} + +static HRESULT WINAPI CBitBucketBackgroundContextMenuConstructor(REFIID riid, LPVOID *ppv) +{ + CComObject *theMenu; + CComPtr result; + HRESULT hResult; + + TRACE("%s\n", shdebugstr_guid(&riid)); + + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; + ATLTRY(theMenu = new CComObject); + if (theMenu == NULL) + return E_OUTOFMEMORY; + hResult = theMenu->QueryInterface(riid, (void **)&result); + if (FAILED(hResult)) + { + delete theMenu; + return hResult; + } + *ppv = result.Detach(); + TRACE ("--(%p)\n", *ppv); + return S_OK; +} + +/************************************************************************** +* IContextMenu2 Bitbucket Item Implementation +*/ + +CCBitBucketItemContextMenu::CCBitBucketItemContextMenu() +{ + apidl = NULL; +} + +CCBitBucketItemContextMenu::~CCBitBucketItemContextMenu() +{ + ILFree(apidl); +} + +HRESULT WINAPI CCBitBucketItemContextMenu::Initialize(LPCITEMIDLIST pidl) +{ + apidl = ILClone(pidl); + if (apidl == NULL) + return E_OUTOFMEMORY; + return S_OK; +} + +HRESULT WINAPI CCBitBucketItemContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) +{ + WCHAR szBuffer[30] = {0}; + ULONG Count = 1; + + TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); + + if (LoadStringW(shell32_hInstance, IDS_RESTORE, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED); + Count++; + } + + if (LoadStringW(shell32_hInstance, IDS_CUT, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED); + } + + if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED); + } + + if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, sizeof(szBuffer)/sizeof(WCHAR))) + { + szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_DEFAULT); + } + + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count); +} + +HRESULT WINAPI CCBitBucketItemContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) +{ + SEARCH_CONTEXT Context; + static LPCWSTR szDrive = L"C:\\"; + + TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",this,lpcmi,lpcmi->lpVerb, lpcmi->hwnd); + + if (lpcmi->lpVerb == MAKEINTRESOURCEA(1) || lpcmi->lpVerb == MAKEINTRESOURCEA(5)) + { + Context.pFileDetails = _ILGetRecycleStruct(apidl); + Context.bFound = FALSE; + + EnumerateRecycleBinW(szDrive, CBSearchBitBucket, (PVOID)&Context); + if (!Context.bFound) + return E_FAIL; + + if (lpcmi->lpVerb == MAKEINTRESOURCEA(1)) + { + /* restore file */ + if (RestoreFile(Context.hDeletedFile)) + return S_OK; + else + return E_FAIL; + } + else + { + DeleteFileHandleToRecycleBin(Context.hDeletedFile); + return E_NOTIMPL; + } + } + else if (lpcmi->lpVerb == MAKEINTRESOURCEA(3)) + { + FIXME("implement cut\n"); + return E_NOTIMPL; + } + else if (lpcmi->lpVerb == MAKEINTRESOURCEA(7)) + { + FIXME("implement properties\n"); + return E_NOTIMPL; + } + + return S_OK; +} + +HRESULT WINAPI CCBitBucketItemContextMenu::GetCommandString(UINT_PTR idCommand,UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen) +{ + TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); + + return E_FAIL; +} + +HRESULT WINAPI CCBitBucketItemContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TRACE("CBitBucket_IContextMenu2Item_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n",this, uMsg, wParam, lParam); + + return E_NOTIMPL; +} + +static HRESULT WINAPI CBitBucketItemContextMenuConstructor(REFIID riid, LPCITEMIDLIST pidl, LPVOID *ppv) +{ + CComObject *theMenu; + CComPtr result; + HRESULT hResult; + + TRACE("%s\n", shdebugstr_guid(&riid)); + + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; + ATLTRY(theMenu = new CComObject); + if (theMenu == NULL) + return E_OUTOFMEMORY; + hResult = theMenu->QueryInterface(riid, (void **)&result); + if (FAILED(hResult)) + { + delete theMenu; + return hResult; + } + hResult = theMenu->Initialize(pidl); + if (FAILED(hResult)) + return hResult; + *ppv = result.Detach(); + TRACE ("--(%p)\n", *ppv); + return S_OK; +} + +CBitBucket::CBitBucket() +{ + pidl = NULL; +} + +CBitBucket::~CBitBucket() +{ +/* InterlockedDecrement(&objCount);*/ + SHFree(pidl); +} + +HRESULT WINAPI CBitBucket::ParseDisplayName(HWND hwnd, LPBC pbc, + LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, + ULONG *pdwAttributes) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + + +PDELETED_FILE_DETAILS_W +UnpackDetailsFromPidl(LPCITEMIDLIST pidl) +{ + return (PDELETED_FILE_DETAILS_W)&pidl->mkid.abID; +} + +HRESULT WINAPI CBitBucket::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) +{ + CComObject *theEnumerator; + CComPtr 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); + if (theEnumerator == NULL) + return E_OUTOFMEMORY; + hResult = theEnumerator->QueryInterface(IID_IEnumIDList, (void **)&result); + if (FAILED (hResult)) + { + delete theEnumerator; + return hResult; + } + hResult = theEnumerator->Initialize(dwFlags); + if (FAILED (hResult)) + return hResult; + *ppEnumIDList = result.Detach(); + + TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList); + + return S_OK; +} + +HRESULT WINAPI CBitBucket::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv) +{ + FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl, pbc, debugstr_guid(&riid), ppv); + return E_NOTIMPL; +} + +HRESULT WINAPI CBitBucket::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv) +{ + FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl, pbc, debugstr_guid(&riid), ppv); + return E_NOTIMPL; +} + +HRESULT WINAPI CBitBucket::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + /* TODO */ + TRACE("(%p, %p, %p, %p)\n", this, (void *)lParam, pidl1, pidl2); + if (pidl1->mkid.cb != pidl2->mkid.cb) + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb); + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb)); +} + +HRESULT WINAPI CBitBucket::CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv) +{ + LPSHELLVIEW pShellView; + HRESULT hr = E_NOINTERFACE; + + TRACE("(%p, %p, %s, %p)\n", this, hwndOwner, debugstr_guid(&riid), ppv); + + if (!ppv) + return hr; + + *ppv = NULL; + + if (IsEqualIID (riid, IID_IDropTarget)) + { + WARN ("IDropTarget not implemented\n"); + hr = E_NOTIMPL; + } + else if (IsEqualIID (riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2)) + { + hr = CBitBucketBackgroundContextMenuConstructor(riid, ppv); + } + else if (IsEqualIID (riid, IID_IShellView)) + { + hr = IShellView_Constructor ((IShellFolder *)this, &pShellView); + if (pShellView) + { + hr = pShellView->QueryInterface(riid, ppv); + pShellView->Release(); + } + } + else + return hr; + TRACE ("-- (%p)->(interface=%p)\n", this, ppv); + return hr; + +} + +HRESULT WINAPI CBitBucket::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, + SFGAOF *rgfInOut) +{ + TRACE("(%p, %d, {%p, ...}, {%x})\n", this, cidl, apidl ? apidl[0] : NULL, (unsigned int)*rgfInOut); + *rgfInOut &= SFGAO_CANMOVE|SFGAO_CANDELETE|SFGAO_HASPROPSHEET|SFGAO_FILESYSTEM | SFGAO_FOLDER; + return S_OK; +} + +HRESULT WINAPI CBitBucket::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, + REFIID riid, UINT *prgfInOut, void **ppv) +{ + IUnknown *pObj = NULL; + HRESULT hr = E_INVALIDARG; + + TRACE ("(%p)->(%p,%u,apidl=%p, %p %p)\n", this, + hwndOwner, cidl, apidl, prgfInOut, ppv); + + if (!ppv) + return hr; + + *ppv = NULL; + + if ((IsEqualIID (riid, IID_IContextMenu) || IsEqualIID(riid, IID_IContextMenu2)) && (cidl >= 1)) + { + hr = CBitBucketItemContextMenuConstructor(riid, apidl[0], (void **)&pObj); + } + else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1)) + { + hr = this->QueryInterface(IID_IDropTarget, (LPVOID *) & pObj); + } + else + hr = E_NOINTERFACE; + + if (SUCCEEDED(hr) && !pObj) + hr = E_OUTOFMEMORY; + + *ppv = pObj; + TRACE ("(%p)->hr=0x%08x\n", this, hr); + return hr; +} + +HRESULT WINAPI CBitBucket::GetDisplayNameOf(LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET *pName) +{ + PIDLRecycleStruct *pFileDetails; + LPWSTR pFileName; + + TRACE("(%p, %p, %x, %p)\n", this, pidl, (unsigned int)uFlags, pName); + + + if (_ILIsBitBucket (pidl)) + { + WCHAR pszPath[100]; + + if (HCR_GetClassNameW(CLSID_RecycleBin, pszPath, MAX_PATH)) + { + pName->uType = STRRET_WSTR; + pName->pOleStr = StrDupW(pszPath); + return S_OK; + } + } + + pFileDetails = _ILGetRecycleStruct(pidl); + if (!pFileDetails) + { + pName->cStr[0] = 0; + pName->uType = STRRET_CSTR; + return E_INVALIDARG; + } + + pFileName = wcsrchr(pFileDetails->szName, L'\\'); + if (!pFileName) + { + pName->cStr[0] = 0; + pName->uType = STRRET_CSTR; + return E_UNEXPECTED; + } + + pName->pOleStr = StrDupW(pFileName + 1); + if (pName->pOleStr == NULL) + return E_OUTOFMEMORY; + + pName->uType = STRRET_WSTR; + return S_OK; +} + +HRESULT WINAPI CBitBucket::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName, + SHGDNF uFlags, LPITEMIDLIST *ppidlOut) +{ + TRACE("\n"); + return E_FAIL; /* not supported */ +} + +HRESULT WINAPI CBitBucket::GetDefaultSearchGUID(GUID *pguid) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +HRESULT WINAPI CBitBucket::EnumSearches(IEnumExtraSearch **ppEnum) +{ + FIXME("stub\n"); + *ppEnum = NULL; + return E_NOTIMPL; +} + +HRESULT WINAPI CBitBucket::GetDefaultColumn(DWORD dwReserved, ULONG *pSort, ULONG *pDisplay) +{ + TRACE("(%p, %x, %p, %p)\n", this, (unsigned int)dwReserved, pSort, pDisplay); + *pSort = 0; + *pDisplay = 0; + return S_OK; +} + +HRESULT WINAPI CBitBucket::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags) +{ + TRACE("(%p, %d, %p)\n", this, iColumn, pcsFlags); + if (iColumn >= COLUMNS_COUNT) + return E_INVALIDARG; + *pcsFlags = CBitBucketColumns[iColumn].pcsFlags; + return S_OK; +} + +HRESULT WINAPI CBitBucket::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME * ft) +{ + FILETIME lft; + SYSTEMTIME time; + int ret; + + FileTimeToLocalFileTime(ft, &lft); + FileTimeToSystemTime(&lft, &time); + + ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size); + if (ret>0 && ret= COLUMNS_COUNT) + return E_FAIL; + pDetails->fmt = CBitBucketColumns[iColumn].fmt; + pDetails->cxChar = CBitBucketColumns[iColumn].cxChars; + if (pidl == NULL) + { + pDetails->str.uType = STRRET_WSTR; + LoadStringW(shell32_hInstance, CBitBucketColumns[iColumn].column_name_id, buffer, MAX_PATH); + return SHStrDupW(buffer, &pDetails->str.pOleStr); + } + + if (iColumn == COLUMN_NAME) + return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str); + + pFileDetails = _ILGetRecycleStruct(pidl); + switch (iColumn) + { + case COLUMN_DATEDEL: + FormatDateTime(buffer, MAX_PATH, &pFileDetails->DeletionTime); + break; + case COLUMN_DELFROM: + pszBackslash = wcsrchr(pFileDetails->szName, L'\\'); + Length = (pszBackslash - pFileDetails->szName); + memcpy((LPVOID)buffer, pFileDetails->szName, Length * sizeof(WCHAR)); + buffer[Length] = L'\0'; + break; + case COLUMN_SIZE: + StrFormatKBSizeW(pFileDetails->FileSize.QuadPart, buffer, MAX_PATH); + break; + case COLUMN_MTIME: + FormatDateTime(buffer, MAX_PATH, &pFileDetails->LastModification); + break; + case COLUMN_TYPE: + szTypeName[0] = L'\0'; + wcscpy(buffer,PathFindExtensionW(pFileDetails->szName)); + if (!( HCR_MapTypeToValueW(buffer, buffer, sizeof(buffer)/sizeof(WCHAR), TRUE) && + HCR_MapTypeToValueW(buffer, szTypeName, sizeof(szTypeName)/sizeof(WCHAR), FALSE ))) + { + wcscpy (szTypeName, PathFindExtensionW(pFileDetails->szName)); + wcscat(szTypeName, L"-"); + Length = wcslen(szTypeName); + if (LoadStringW(shell32_hInstance, IDS_SHV_COLUMN1, &szTypeName[Length], (sizeof(szTypeName)/sizeof(WCHAR))- Length)) + szTypeName[(sizeof(szTypeName)/sizeof(WCHAR))-1] = L'\0'; + } + pDetails->str.uType = STRRET_WSTR; + return SHStrDupW(szTypeName, &pDetails->str.pOleStr); + break; + default: + return E_FAIL; + } + + pDetails->str.uType = STRRET_WSTR; + return SHStrDupW(buffer, &pDetails->str.pOleStr); +} + +HRESULT WINAPI CBitBucket::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid) +{ + TRACE("(%p, %d, %p)\n", this, iColumn, pscid); + if (iColumn>=COLUMNS_COUNT) + return E_INVALIDARG; + pscid->fmtid = *CBitBucketColumns[iColumn].fmtId; + pscid->pid = CBitBucketColumns[iColumn].pid; + return S_OK; +} + +HRESULT WINAPI CBitBucket::GetClassID(CLSID *pClassID) +{ + TRACE("(%p, %p)\n", this, pClassID); + if (pClassID == NULL) + return E_INVALIDARG; + memcpy(pClassID, &CLSID_RecycleBin, sizeof(CLSID)); + return S_OK; +} + +HRESULT WINAPI CBitBucket::Initialize(LPCITEMIDLIST pidl) +{ + TRACE("(%p, %p)\n", this, pidl); + + SHFree((LPVOID)this->pidl); + this->pidl = ILClone(pidl); + if (this->pidl == NULL) + return E_OUTOFMEMORY; + return S_OK; +} + +HRESULT WINAPI CBitBucket::GetCurFolder(LPITEMIDLIST *ppidl) +{ + TRACE("\n"); + *ppidl = ILClone(pidl); + return S_OK; +} + +/************************************************************************* + * BitBucket IShellExtInit interface + */ + +HRESULT WINAPI CBitBucket::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID) +{ + TRACE("%p %p %p %p\n", this, pidlFolder, pdtobj, hkeyProgID ); + return S_OK; +} + +void toggleNukeOnDeleteOption(HWND hwndDlg, BOOL bEnable) +{ + if (bEnable) + { + SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_UNCHECKED, 0); + EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE); + SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_CHECKED, 0); + } + else + { + SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_CHECKED, 0); + EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE); + SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_UNCHECKED, 0); + } +} + + +void +InitializeBitBucketDlg(HWND hwndDlg, WCHAR DefaultDrive) +{ + WCHAR CurDrive = L'A'; + WCHAR szDrive[] = L"A:\\"; + DWORD dwDrives; + WCHAR szName[100]; + WCHAR szVolume[100]; + DWORD MaxComponent, Flags; + DWORD dwSerial; + LVCOLUMNW lc; + HWND hDlgCtrl; + LVITEMW li; + INT itemCount; + ULARGE_INTEGER TotalNumberOfFreeBytes, TotalNumberOfBytes, FreeBytesAvailable; + RECT rect; + int columnSize; + int defIndex = 0; + DWORD dwSize; + PDRIVE_ITEM_CONTEXT pItem = NULL, pDefault = NULL, pFirst = NULL; + + hDlgCtrl = GetDlgItem(hwndDlg, 14000); + + if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_LOCATION, szVolume, sizeof(szVolume) / sizeof(WCHAR))) + szVolume[0] = 0; + + GetClientRect(hDlgCtrl, &rect); + + memset(&lc, 0, sizeof(LV_COLUMN) ); + lc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT; + + columnSize = 140; //FIXME + lc.iSubItem = 0; + lc.fmt = LVCFMT_FIXED_WIDTH; + lc.cx = columnSize; + lc.cchTextMax = wcslen(szVolume); + lc.pszText = szVolume; + (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&lc); + + if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_DISKSPACE, szVolume, sizeof(szVolume) / sizeof(WCHAR))) + szVolume[0] = 0; + + lc.iSubItem = 1; + lc.cx = rect.right - rect.left - columnSize; + lc.cchTextMax = wcslen(szVolume); + lc.pszText = szVolume; + (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&lc); + + dwDrives = GetLogicalDrives(); + itemCount = 0; + do + { + if ((dwDrives & 0x1)) + { + UINT Type = GetDriveTypeW(szDrive); + if (Type == DRIVE_FIXED) //FIXME + { + if (!GetVolumeInformationW(szDrive, szName, sizeof(szName) / sizeof(WCHAR), &dwSerial, &MaxComponent, &Flags, NULL, 0)) + { + szName[0] = 0; + dwSerial = -1; + } + + swprintf(szVolume, L"%s (%c)", szName, szDrive[0]); + memset(&li, 0x0, sizeof(LVITEMW)); + li.mask = LVIF_TEXT | LVIF_PARAM; + li.iSubItem = 0; + li.pszText = szVolume; + li.iItem = itemCount; + (void)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li); + if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable , &TotalNumberOfBytes, &TotalNumberOfFreeBytes)) + { + if (StrFormatByteSizeW(TotalNumberOfFreeBytes.QuadPart, szVolume, sizeof(szVolume) / sizeof(WCHAR))) + { + + pItem = (DRIVE_ITEM_CONTEXT *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DRIVE_ITEM_CONTEXT)); + if (pItem) + { + swprintf(szName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\%04X-%04X", LOWORD(dwSerial), HIWORD(dwSerial)); + dwSize = sizeof(DWORD); + RegGetValueW(HKEY_CURRENT_USER, szName, L"MaxCapacity", RRF_RT_DWORD, NULL, &pItem->dwMaxCapacity, &dwSize); + dwSize = sizeof(DWORD); + RegGetValueW(HKEY_CURRENT_USER, szName, L"NukeOnDelete", RRF_RT_DWORD, NULL, &pItem->dwNukeOnDelete, &dwSize); + pItem->dwSerial = dwSerial; + li.mask = LVIF_PARAM; + li.lParam = (LPARAM)pItem; + (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li); + if (CurDrive == DefaultDrive) + { + defIndex = itemCount; + pDefault = pItem; + } + } + if (!pFirst) + pFirst = pItem; + + li.mask = LVIF_TEXT; + li.iSubItem = 1; + li.pszText = szVolume; + li.iItem = itemCount; + (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li); + } + } + itemCount++; + } + } + CurDrive++; + szDrive[0] = CurDrive; + dwDrives = (dwDrives >> 1); + }while(dwDrives); + + if (!pDefault) + pDefault = pFirst; + if (pDefault) + { + toggleNukeOnDeleteOption(hwndDlg, pDefault->dwNukeOnDelete); + SetDlgItemInt(hwndDlg, 14002, pDefault->dwMaxCapacity, FALSE); + } + ZeroMemory(&li, sizeof(li)); + li.mask = LVIF_STATE; + li.stateMask = (UINT)-1; + li.state = LVIS_FOCUSED|LVIS_SELECTED; + li.iItem = defIndex; + (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li); + +} + +static BOOL StoreDriveSettings(HWND hwndDlg) +{ + int iCount, iIndex; + HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000); + LVITEMW li; + PDRIVE_ITEM_CONTEXT pItem; + HKEY hKey, hSubKey; + WCHAR szSerial[20]; + DWORD dwSize; + + + if (RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume", 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) + return FALSE; + + iCount = ListView_GetItemCount(hDlgCtrl); + + ZeroMemory(&li, sizeof(li)); + li.mask = LVIF_PARAM; + + for(iIndex = 0; iIndex < iCount; iIndex++) + { + li.iItem = iIndex; + if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li)) + { + pItem = (PDRIVE_ITEM_CONTEXT)li.lParam; + swprintf(szSerial, L"%04X-%04X", LOWORD(pItem->dwSerial), HIWORD(pItem->dwSerial)); + if (RegCreateKeyExW(hKey, szSerial, 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS) + { + dwSize = sizeof(DWORD); + RegSetValueExW(hSubKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&pItem->dwNukeOnDelete, dwSize); + dwSize = sizeof(DWORD); + RegSetValueExW(hSubKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&pItem->dwMaxCapacity, dwSize); + RegCloseKey(hSubKey); + } + } + } + RegCloseKey(hKey); + return TRUE; + +} + +static VOID FreeDriveItemContext(HWND hwndDlg) +{ + int iCount, iIndex; + HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000); + LVITEMW li; + + iCount = ListView_GetItemCount(hDlgCtrl); + + ZeroMemory(&li, sizeof(li)); + li.mask = LVIF_PARAM; + + for(iIndex = 0; iIndex < iCount; iIndex++) + { + li.iItem = iIndex; + if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li)) + { + HeapFree(GetProcessHeap(), 0, (LPVOID)li.lParam); + } + } +} + +INT +GetDefaultItem(HWND hwndDlg, LVITEMW * li) +{ + HWND hDlgCtrl; + UINT iItemCount, iIndex; + + hDlgCtrl = GetDlgItem(hwndDlg, 14000); + if (!hDlgCtrl) + return -1; + + iItemCount = ListView_GetItemCount(hDlgCtrl); + if (!iItemCount) + return -1; + + ZeroMemory(li, sizeof(LVITEMW)); + li->mask = LVIF_PARAM | LVIF_STATE; + li->stateMask = (UINT)-1; + for (iIndex = 0; iIndex < iItemCount; iIndex++) + { + li->iItem = iIndex; + if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)li)) + { + if (li->state & LVIS_SELECTED) + return iIndex; + } + } + return -1; + +} + +INT_PTR +CALLBACK +BitBucketDlg( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + LPPSHNOTIFY lppsn; + LPNMLISTVIEW lppl; + LVITEMW li; + PDRIVE_ITEM_CONTEXT pItem; + BOOL bSuccess; + UINT uResult; + PROPSHEETPAGE * page; + DWORD dwStyle; + + switch(uMsg) + { + case WM_INITDIALOG: + page = (PROPSHEETPAGE*)lParam; + InitializeBitBucketDlg(hwndDlg, (WCHAR)page->lParam); + dwStyle = (DWORD) SendDlgItemMessage(hwndDlg, 14000, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0); + dwStyle = dwStyle | LVS_EX_FULLROWSELECT; + SendDlgItemMessage(hwndDlg, 14000, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle); + if (GetDlgCtrlID((HWND)wParam) != 14000) + { + SetFocus(GetDlgItem(hwndDlg, 14000)); + return FALSE; + } + return TRUE; + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case 14001: + toggleNukeOnDeleteOption(hwndDlg, FALSE); + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + break; + case 14003: + toggleNukeOnDeleteOption(hwndDlg, TRUE); + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + break; + case 14004: + PropSheet_Changed(GetParent(hwndDlg), hwndDlg); + break; + } + break; + case WM_NOTIFY: + lppsn = (LPPSHNOTIFY) lParam; + lppl = (LPNMLISTVIEW) lParam; + if (lppsn->hdr.code == PSN_APPLY) + { + if (GetDefaultItem(hwndDlg, &li) > -1) + { + pItem = (PDRIVE_ITEM_CONTEXT)li.lParam; + if (pItem) + { + uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE); + if (bSuccess) + pItem->dwMaxCapacity = uResult; + if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) + pItem->dwNukeOnDelete = TRUE; + else + pItem->dwNukeOnDelete = FALSE; + } + } + if (StoreDriveSettings(hwndDlg)) + { + SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR ); + return TRUE; + } + } + else if (lppl->hdr.code == LVN_ITEMCHANGING) + { + ZeroMemory(&li, sizeof(li)); + li.mask = LVIF_PARAM; + li.iItem = lppl->iItem; + if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&li)) + return TRUE; + + pItem = (PDRIVE_ITEM_CONTEXT)li.lParam; + if (!pItem) + return TRUE; + + if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED)) + { + /* new focused item */ + toggleNukeOnDeleteOption(lppl->hdr.hwndFrom, pItem->dwNukeOnDelete); + SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE); + } + else if ((lppl->uOldState & LVIS_FOCUSED) && !(lppl->uNewState & LVIS_FOCUSED)) + { + /* kill focus */ + uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE); + if (bSuccess) + pItem->dwMaxCapacity = uResult; + if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) + pItem->dwNukeOnDelete = TRUE; + else + pItem->dwNukeOnDelete = FALSE; + } + return TRUE; + + } + break; + case WM_DESTROY: + FreeDriveItemContext(hwndDlg); + break; + } + return FALSE; +} + +BOOL SH_ShowRecycleBinProperties(WCHAR sDrive) +{ + HPROPSHEETPAGE hpsp[1]; + PROPSHEETHEADERW psh; + HPROPSHEETPAGE hprop; + + BOOL ret; + + + ZeroMemory(&psh, sizeof(PROPSHEETHEADERW)); + psh.dwSize = sizeof(PROPSHEETHEADERW); + psh.dwFlags = PSP_DEFAULT | PSH_PROPTITLE; + psh.pszCaption = MAKEINTRESOURCEW(IDS_RECYCLEBIN_FOLDER_NAME); + psh.hwndParent = NULL; + psh.phpage = hpsp; + psh.hInstance = shell32_hInstance; + + hprop = SH_CreatePropertySheetPage("BITBUCKET_PROPERTIES_DLG", BitBucketDlg, (LPARAM)sDrive, NULL); + if (!hprop) + { + ERR("Failed to create property sheet\n"); + return FALSE; + } + hpsp[psh.nPages] = hprop; + psh.nPages++; + + + ret = PropertySheetW(&psh); + if (ret < 0) + return FALSE; + else + return TRUE; +} + +BOOL +TRASH_CanTrashFile(LPCWSTR wszPath) +{ + LONG ret; + DWORD dwNukeOnDelete, dwType, VolSerialNumber, MaxComponentLength; + DWORD FileSystemFlags, dwSize, dwDisposition; + HKEY hKey; + WCHAR szBuffer[10]; + WCHAR szKey[150] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\"; + + if (wszPath[1] != L':') + { + /* path is UNC */ + return FALSE; + } + + if (GetDriveTypeW(wszPath) != DRIVE_FIXED) + { + /* no bitbucket on removable media */ + return FALSE; + } + + if (!GetVolumeInformationW(wszPath, NULL, 0, &VolSerialNumber, &MaxComponentLength, &FileSystemFlags, NULL, 0)) + { + ERR("GetVolumeInformationW failed with %u\n", GetLastError()); + return FALSE; + } + + swprintf(szBuffer, L"%04X-%04X", LOWORD(VolSerialNumber), HIWORD(VolSerialNumber)); + wcscat(szKey, szBuffer); + + if (RegCreateKeyExW(HKEY_CURRENT_USER, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) + { + ERR("RegCreateKeyExW failed\n"); + return FALSE; + } + + if (dwDisposition & REG_CREATED_NEW_KEY) + { + /* per default move to bitbucket */ + dwNukeOnDelete = 0; + RegSetValueExW(hKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&dwNukeOnDelete, sizeof(DWORD)); + /* per default unlimited size */ + dwSize = -1; + RegSetValueExW(hKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&dwSize, sizeof(DWORD)); + RegCloseKey(hKey); + return TRUE; + } + else + { + dwSize = sizeof(dwNukeOnDelete); + ret = RegQueryValueExW(hKey, L"NukeOnDelete", NULL, &dwType, (LPBYTE)&dwNukeOnDelete, &dwSize); + if (ret != ERROR_SUCCESS) + { + if (ret == ERROR_FILE_NOT_FOUND) + { + /* restore key and enable bitbucket */ + dwNukeOnDelete = 0; + RegSetValueExW(hKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&dwNukeOnDelete, sizeof(DWORD)); + } + RegCloseKey(hKey); + return TRUE; + } + else if (dwNukeOnDelete) + { + /* do not delete to bitbucket */ + RegCloseKey(hKey); + return FALSE; + } + /* FIXME + * check if bitbucket is full + */ + RegCloseKey(hKey); + return TRUE; + } +} + +BOOL +TRASH_TrashFile(LPCWSTR wszPath) +{ + TRACE("(%s)\n", debugstr_w(wszPath)); + return DeleteFileToRecycleBin(wszPath); +} + +/************************************************************************* + * SHUpdateCBitBucketIcon [SHELL32.@] + * + * Undocumented + */ +EXTERN_C HRESULT WINAPI SHUpdateRecycleBinIcon(void) +{ + FIXME("stub\n"); + + + + return S_OK; +} diff --git a/reactos/dll/win32/shell32/shfldr_recyclebin.h b/reactos/dll/win32/shell32/shfldr_recyclebin.h new file mode 100644 index 00000000000..2a2e5988f1c --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_recyclebin.h @@ -0,0 +1,86 @@ +/* + * Trash virtual folder support. The trashing engine is implemented in trash.c + * + * Copyright (C) 2006 Mikolaj Zalewski + * Copyright (C) 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 + */ + +#ifndef _SHFLDR_RECYCLEBIN_H_ +#define _SHFLDR_RECYCLEBIN_H_ + +class CBitBucket : + public CComCoClass, + public CComObjectRootEx, + public IShellFolder2, + public IPersistFolder2, + public IShellExtInit +{ +private: + LPITEMIDLIST pidl; +public: + CBitBucket(); + ~CBitBucket(); + + // IShellFolder + virtual HRESULT WINAPI ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes); + virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList); + virtual HRESULT WINAPI BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut); + virtual HRESULT WINAPI GetAttributesOf (UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut); + virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut); + virtual HRESULT WINAPI GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet); + virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut); + + /* ShellFolder2 */ + virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid); + virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum); + virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay); + virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags); + virtual HRESULT WINAPI GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv); + virtual HRESULT WINAPI GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd); + virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT WINAPI GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT WINAPI GetCurFolder(LPITEMIDLIST * pidl); + + // IShellExtInit + virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID); + +DECLARE_REGISTRY_RESOURCEID(IDR_RECYCLEBIN) +DECLARE_NOT_AGGREGATABLE(CBitBucket) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CBitBucket) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) + COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit) +END_COM_MAP() +}; + +#endif // _SHFLDR_RECYCLEBIN_H_ diff --git a/reactos/dll/win32/shell32/shfldr_unixfs.cpp b/reactos/dll/win32/shell32/shfldr_unixfs.cpp new file mode 100644 index 00000000000..95e4defc81e --- /dev/null +++ b/reactos/dll/win32/shell32/shfldr_unixfs.cpp @@ -0,0 +1,21 @@ +/* + * 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 */ diff --git a/reactos/dll/win32/shell32/shlexec.cpp b/reactos/dll/win32/shell32/shlexec.cpp new file mode 100644 index 00000000000..d4b30aac5f6 --- /dev/null +++ b/reactos/dll/win32/shell32/shlexec.cpp @@ -0,0 +1,2185 @@ +/* + * 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 +#include + +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\\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\\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(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(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(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(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); +} diff --git a/reactos/dll/win32/shell32/shlfileop.cpp b/reactos/dll/win32/shell32/shlfileop.cpp new file mode 100644 index 00000000000..42e22c78905 --- /dev/null +++ b/reactos/dll/win32/shell32/shlfileop.cpp @@ -0,0 +1,1931 @@ +/* + * 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 + +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); +} diff --git a/reactos/dll/win32/shell32/shlfolder.cpp b/reactos/dll/win32/shell32/shlfolder.cpp new file mode 100644 index 00000000000..9850246bbff --- /dev/null +++ b/reactos/dll/win32/shell32/shlfolder.cpp @@ -0,0 +1,567 @@ +/* + * Shell Folder stuff + * + * Copyright 1997 Marcus Meissner + * Copyright 1998, 1999, 2002 Juergen Schmied + * + * IShellFolder2 and related interfaces + * + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +static const WCHAR wszDotShellClassInfo[] = { + '.','S','h','e','l','l','C','l','a','s','s','I','n','f','o',0}; + +/*************************************************************************** + * SHELL32_GetCustomFolderAttribute (internal function) + * + * Gets a value from the folder's desktop.ini file, if one exists. + * + * PARAMETERS + * pidl [I] Folder containing the desktop.ini file. + * pwszHeading [I] Heading in .ini file. + * pwszAttribute [I] Attribute in .ini file. + * pwszValue [O] Buffer to store value into. + * cchValue [I] Size in characters including NULL of buffer pointed to + * by pwszValue. + * + * RETURNS + * TRUE if returned non-NULL value. + * FALSE otherwise. + */ +static BOOL __inline SHELL32_GetCustomFolderAttributeFromPath( + LPWSTR pwszFolderPath, LPCWSTR pwszHeading, LPCWSTR pwszAttribute, + LPWSTR pwszValue, DWORD cchValue) +{ + static const WCHAR wszDesktopIni[] = + {'d','e','s','k','t','o','p','.','i','n','i',0}; + static const WCHAR wszDefault[] = {0}; + + PathAddBackslashW(pwszFolderPath); + PathAppendW(pwszFolderPath, wszDesktopIni); + return GetPrivateProfileStringW(pwszHeading, pwszAttribute, wszDefault, + pwszValue, cchValue, pwszFolderPath); +} + +BOOL SHELL32_GetCustomFolderAttribute( + LPCITEMIDLIST pidl, LPCWSTR pwszHeading, LPCWSTR pwszAttribute, + LPWSTR pwszValue, DWORD cchValue) +{ + DWORD dwAttrib = FILE_ATTRIBUTE_SYSTEM; + WCHAR wszFolderPath[MAX_PATH]; + + /* Hack around not having system attribute on non-Windows file systems */ + if (0) + dwAttrib = _ILGetFileAttributes(pidl, NULL, 0); + + if (dwAttrib & FILE_ATTRIBUTE_SYSTEM) + { + if (!SHGetPathFromIDListW(pidl, wszFolderPath)) + return FALSE; + + return SHELL32_GetCustomFolderAttributeFromPath(wszFolderPath, pwszHeading, + pwszAttribute, pwszValue, cchValue); + } + return FALSE; +} + +/*************************************************************************** + * GetNextElement (internal function) + * + * Gets a part of a string till the first backslash. + * + * PARAMETERS + * pszNext [IN] string to get the element from + * pszOut [IN] pointer to buffer which receives string + * dwOut [IN] length of pszOut + * + * RETURNS + * LPSTR pointer to first, not yet parsed char + */ + +LPCWSTR GetNextElementW (LPCWSTR pszNext, LPWSTR pszOut, DWORD dwOut) +{ + LPCWSTR pszTail = pszNext; + DWORD dwCopy; + + TRACE ("(%s %p 0x%08x)\n", debugstr_w (pszNext), pszOut, dwOut); + + *pszOut = 0x0000; + + if (!pszNext || !*pszNext) + return NULL; + + while (*pszTail && (*pszTail != (WCHAR) '\\')) + pszTail++; + + dwCopy = pszTail - pszNext + 1; + lstrcpynW (pszOut, pszNext, (dwOut < dwCopy) ? dwOut : dwCopy); + + if (*pszTail) + pszTail++; + else + pszTail = NULL; + + TRACE ("--(%s %s 0x%08x %p)\n", debugstr_w (pszNext), debugstr_w (pszOut), dwOut, pszTail); + return pszTail; +} + +HRESULT SHELL32_ParseNextElement (IShellFolder2 * psf, HWND hwndOwner, LPBC pbc, + LPITEMIDLIST * pidlInOut, LPOLESTR szNext, DWORD * pEaten, DWORD * pdwAttributes) +{ + HRESULT hr = E_INVALIDARG; + LPITEMIDLIST pidlOut = NULL, + pidlTemp = NULL; + IShellFolder *psfChild; + + TRACE ("(%p, %p, %p, %s)\n", psf, pbc, pidlInOut ? *pidlInOut : NULL, debugstr_w (szNext)); + + /* get the shellfolder for the child pidl and let it analyse further */ + hr = psf->BindToObject(*pidlInOut, pbc, IID_IShellFolder, (LPVOID *)&psfChild); + + if (SUCCEEDED(hr)) { + hr = psfChild->ParseDisplayName(hwndOwner, pbc, szNext, pEaten, &pidlOut, pdwAttributes); + psfChild->Release(); + + if (SUCCEEDED(hr)) { + pidlTemp = ILCombine (*pidlInOut, pidlOut); + + if (!pidlTemp) + hr = E_OUTOFMEMORY; + } + + if (pidlOut) + ILFree (pidlOut); + } + + ILFree (*pidlInOut); + *pidlInOut = pidlTemp; + + TRACE ("-- pidl=%p ret=0x%08x\n", pidlInOut ? *pidlInOut : NULL, hr); + return hr; +} + +/*********************************************************************** + * SHELL32_CoCreateInitSF + * + * Creates a shell folder and initializes it with a pidl and a root folder + * via IPersistFolder3 or IPersistFolder. + * + * NOTES + * pathRoot can be NULL for Folders being a drive. + * In this case the absolute path is built from pidlChild (eg. C:) + */ +static HRESULT SHELL32_CoCreateInitSF (LPCITEMIDLIST pidlRoot, LPCWSTR pathRoot, + LPCITEMIDLIST pidlChild, REFCLSID clsid, LPVOID * ppvOut) +{ + HRESULT hr; + + TRACE ("%p %s %p\n", pidlRoot, debugstr_w(pathRoot), pidlChild); + + hr = SHCoCreateInstance(NULL, &clsid, NULL, IID_IShellFolder, ppvOut); + if (SUCCEEDED (hr)) + { + LPITEMIDLIST pidlAbsolute = ILCombine (pidlRoot, pidlChild); + IPersistFolder *pPF; + IPersistFolder3 *ppf; + + if (_ILIsFolder(pidlChild) && + SUCCEEDED (((IUnknown *)(*ppvOut))->QueryInterface(IID_IPersistFolder3, (LPVOID *) & ppf))) + { + PERSIST_FOLDER_TARGET_INFO ppfti; + + ZeroMemory (&ppfti, sizeof (ppfti)); + + /* fill the PERSIST_FOLDER_TARGET_INFO */ + ppfti.dwAttributes = -1; + ppfti.csidl = -1; + + /* build path */ + if (pathRoot) + { + lstrcpynW (ppfti.szTargetParsingName, pathRoot, MAX_PATH - 1); + PathAddBackslashW(ppfti.szTargetParsingName); /* FIXME: why have drives a backslash here ? */ + } + + if (pidlChild) + { + int len = wcslen(ppfti.szTargetParsingName); + + if (!_ILSimpleGetTextW(pidlChild, ppfti.szTargetParsingName + len, MAX_PATH - len)) + hr = E_INVALIDARG; + } + + ppf->InitializeEx(NULL, pidlAbsolute, &ppfti); + ppf->Release(); + } + else if (SUCCEEDED ((hr = ((IUnknown *)(*ppvOut))->QueryInterface (IID_IPersistFolder, (LPVOID *) & pPF)))) + { + pPF->Initialize(pidlAbsolute); + pPF->Release(); + } + ILFree (pidlAbsolute); + } + TRACE ("-- (%p) ret=0x%08x\n", *ppvOut, hr); + return hr; +} + +/*********************************************************************** + * SHELL32_BindToChild [Internal] + * + * Common code for IShellFolder_BindToObject. + * + * PARAMS + * pidlRoot [I] The parent shell folder's absolute pidl. + * pathRoot [I] Absolute dos path of the parent shell folder. + * pidlComplete [I] PIDL of the child. Relative to pidlRoot. + * riid [I] GUID of the interface, which ppvOut shall be bound to. + * ppvOut [O] A reference to the child's interface (riid). + * + * NOTES + * pidlComplete has to contain at least one non empty SHITEMID. + * This function makes special assumptions on the shell namespace, which + * means you probably can't use it for your IShellFolder implementation. + */ +HRESULT SHELL32_BindToChild (LPCITEMIDLIST pidlRoot, + LPCWSTR pathRoot, LPCITEMIDLIST pidlComplete, REFIID riid, LPVOID * ppvOut) +{ + GUID const *clsid; + IShellFolder *pSF; + HRESULT hr; + LPITEMIDLIST pidlChild; + + if (!pidlRoot || !ppvOut || !pidlComplete || !pidlComplete->mkid.cb) + return E_INVALIDARG; + + *ppvOut = NULL; + + pidlChild = ILCloneFirst (pidlComplete); + + if ((clsid = _ILGetGUIDPointer (pidlChild))) { + /* virtual folder */ + hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild, *clsid, (LPVOID *)&pSF); + } else { + /* file system folder */ + CLSID clsidFolder = CLSID_ShellFSFolder; + static const WCHAR wszCLSID[] = {'C','L','S','I','D',0}; + WCHAR wszCLSIDValue[CHARS_IN_GUID], wszFolderPath[MAX_PATH], *pwszPathTail = wszFolderPath; + + /* see if folder CLSID should be overridden by desktop.ini file */ + if (pathRoot) { + lstrcpynW(wszFolderPath, pathRoot, MAX_PATH); + pwszPathTail = PathAddBackslashW(wszFolderPath); + } + + _ILSimpleGetTextW(pidlChild,pwszPathTail,MAX_PATH - (int)(pwszPathTail - wszFolderPath)); + + if (SHELL32_GetCustomFolderAttributeFromPath (wszFolderPath, + wszDotShellClassInfo, wszCLSID, wszCLSIDValue, CHARS_IN_GUID)) + CLSIDFromString (wszCLSIDValue, &clsidFolder); + + hr = SHELL32_CoCreateInitSF (pidlRoot, pathRoot, pidlChild, + clsidFolder, (LPVOID *)&pSF); + } + ILFree (pidlChild); + + if (SUCCEEDED (hr)) { + if (_ILIsPidlSimple (pidlComplete)) { + /* no sub folders */ + hr = pSF->QueryInterface(riid, ppvOut); + } else { + /* go deeper */ + hr = pSF->BindToObject(ILGetNext (pidlComplete), NULL, riid, ppvOut); + } + pSF->Release(); + } + + TRACE ("-- returning (%p) %08x\n", *ppvOut, hr); + + return hr; +} + +/*********************************************************************** + * SHELL32_GetDisplayNameOfChild + * + * Retrieves the display name of a child object of a shellfolder. + * + * For a pidl eg. [subpidl1][subpidl2][subpidl3]: + * - it binds to the child shellfolder [subpidl1] + * - asks it for the displayname of [subpidl2][subpidl3] + * + * Is possible the pidl is a simple pidl. In this case it asks the + * subfolder for the displayname of an empty pidl. The subfolder + * returns the own displayname eg. "::{guid}". This is used for + * virtual folders with the registry key WantsFORPARSING set. + */ +HRESULT SHELL32_GetDisplayNameOfChild (IShellFolder2 * psf, + LPCITEMIDLIST pidl, DWORD dwFlags, LPWSTR szOut, DWORD dwOutLen) +{ + LPITEMIDLIST pidlFirst; + HRESULT hr = E_INVALIDARG; + + TRACE ("(%p)->(pidl=%p 0x%08x %p 0x%08x)\n", psf, pidl, dwFlags, szOut, dwOutLen); + pdump (pidl); + + pidlFirst = ILCloneFirst (pidl); + if (pidlFirst) { + IShellFolder2 *psfChild; + + hr = psf->BindToObject(pidlFirst, NULL, IID_IShellFolder, (LPVOID *) & psfChild); + if (SUCCEEDED (hr)) { + STRRET strTemp; + LPITEMIDLIST pidlNext = ILGetNext (pidl); + + hr = psfChild->GetDisplayNameOf(pidlNext, dwFlags, &strTemp); + if (SUCCEEDED (hr)) { + if(!StrRetToStrNW (szOut, dwOutLen, &strTemp, pidlNext)) + hr = E_FAIL; + } + psfChild->Release(); + } + ILFree (pidlFirst); + } else + hr = E_OUTOFMEMORY; + + TRACE ("-- ret=0x%08x %s\n", hr, debugstr_w(szOut)); + + return hr; +} + +/*********************************************************************** + * SHELL32_GetItemAttributes + * + * NOTES + * Observed values: + * folder: 0xE0000177 FILESYSTEM | HASSUBFOLDER | FOLDER + * file: 0x40000177 FILESYSTEM + * drive: 0xf0000144 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR + * mycomputer: 0xb0000154 HASSUBFOLDER | FOLDER | FILESYSANCESTOR + * (seems to be default for shell extensions if no registry entry exists) + * + * win2k: + * folder: 0xF0400177 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR | CANMONIKER + * file: 0x40400177 FILESYSTEM | CANMONIKER + * drive 0xF0400154 FILESYSTEM | HASSUBFOLDER | FOLDER | FILESYSANCESTOR | CANMONIKER | CANRENAME (LABEL) + * + * According to the MSDN documentation this function should not set flags. It claims only to reset flags when necessary. + * However it turns out the native shell32.dll _sets_ flags in several cases - so do we. + */ +HRESULT SHELL32_GetItemAttributes (IShellFolder * psf, LPCITEMIDLIST pidl, LPDWORD pdwAttributes) +{ + DWORD dwAttributes; + BOOL has_guid; + static const DWORD dwSupportedAttr= + SFGAO_CANCOPY | /*0x00000001 */ + SFGAO_CANMOVE | /*0x00000002 */ + SFGAO_CANLINK | /*0x00000004 */ + SFGAO_CANRENAME | /*0x00000010 */ + SFGAO_CANDELETE | /*0x00000020 */ + SFGAO_HASPROPSHEET | /*0x00000040 */ + SFGAO_DROPTARGET | /*0x00000100 */ + SFGAO_LINK | /*0x00010000 */ + SFGAO_READONLY | /*0x00040000 */ + SFGAO_HIDDEN | /*0x00080000 */ + SFGAO_FILESYSANCESTOR | /*0x10000000 */ + SFGAO_FOLDER | /*0x20000000 */ + SFGAO_FILESYSTEM | /*0x40000000 */ + SFGAO_HASSUBFOLDER; /*0x80000000 */ + + TRACE ("0x%08x\n", *pdwAttributes); + + if (*pdwAttributes & ~dwSupportedAttr) + { + WARN ("attributes 0x%08x not implemented\n", (*pdwAttributes & ~dwSupportedAttr)); + *pdwAttributes &= dwSupportedAttr; + } + + has_guid = _ILGetGUIDPointer(pidl) != NULL; + + dwAttributes = *pdwAttributes; + + if (_ILIsDrive (pidl)) { + *pdwAttributes &= SFGAO_HASSUBFOLDER|SFGAO_FILESYSTEM|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR| + SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANRENAME; + } else if (has_guid && HCR_GetFolderAttributes(pidl, &dwAttributes)) { + *pdwAttributes = dwAttributes; + } else if (_ILGetDataPointer (pidl)) { + dwAttributes = _ILGetFileAttributes (pidl, NULL, 0); + + if (!dwAttributes && has_guid) { + WCHAR path[MAX_PATH]; + STRRET strret; + + /* File attributes are not present in the internal PIDL structure, so get them from the file system. */ + + HRESULT hr = psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strret); + + if (SUCCEEDED(hr)) { + hr = StrRetToBufW(&strret, pidl, path, MAX_PATH); + + /* call GetFileAttributes() only for file system paths, not for parsing names like "::{...}" */ + if (SUCCEEDED(hr) && path[0]!=':') + dwAttributes = GetFileAttributesW(path); + } + } + + /* Set common attributes */ + *pdwAttributes |= SFGAO_FILESYSTEM | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANDELETE | + SFGAO_CANRENAME | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANCOPY; + + if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + *pdwAttributes |= (SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR); + *pdwAttributes &= ~SFGAO_CANLINK; + } + else + *pdwAttributes &= ~(SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_FILESYSANCESTOR); + + if (dwAttributes & FILE_ATTRIBUTE_HIDDEN) + *pdwAttributes |= SFGAO_HIDDEN; + else + *pdwAttributes &= ~SFGAO_HIDDEN; + + if (dwAttributes & FILE_ATTRIBUTE_READONLY) + *pdwAttributes |= SFGAO_READONLY; + else + *pdwAttributes &= ~SFGAO_READONLY; + + if (SFGAO_LINK & *pdwAttributes) { + char ext[MAX_PATH]; + + if (!_ILGetExtension(pidl, ext, MAX_PATH) || lstrcmpiA(ext, "lnk")) + *pdwAttributes &= ~SFGAO_LINK; + } + + if (SFGAO_HASSUBFOLDER & *pdwAttributes) + { + IShellFolder *psf2; + if (SUCCEEDED(psf->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID *)&psf2))) + { + IEnumIDList *pEnumIL = NULL; + if (SUCCEEDED(psf2->EnumObjects(0, SHCONTF_FOLDERS, &pEnumIL))) + { + if (pEnumIL->Skip(1) != S_OK) + *pdwAttributes &= ~SFGAO_HASSUBFOLDER; + pEnumIL->Release(); + } + psf2->Release(); + } + } + } else { + *pdwAttributes &= SFGAO_HASSUBFOLDER|SFGAO_FOLDER|SFGAO_FILESYSANCESTOR|SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANRENAME|SFGAO_CANLINK; + } + TRACE ("-- 0x%08x\n", *pdwAttributes); + return S_OK; +} + +/*********************************************************************** + * SHELL32_CompareIDs + */ +HRESULT SHELL32_CompareIDs (IShellFolder * iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + int type1, + type2; + char szTemp1[MAX_PATH]; + char szTemp2[MAX_PATH]; + HRESULT nReturn; + LPITEMIDLIST firstpidl, + nextpidl1, + nextpidl2; + IShellFolder *psf; + + /* test for empty pidls */ + BOOL isEmpty1 = _ILIsDesktop (pidl1); + BOOL isEmpty2 = _ILIsDesktop (pidl2); + + if (isEmpty1 && isEmpty2) + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 0 ); + if (isEmpty1) + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 ); + if (isEmpty2) + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); + + /* test for different types. Sort order is the PT_* constant */ + type1 = _ILGetDataPointer (pidl1)->type; + type2 = _ILGetDataPointer (pidl2)->type; + if (type1 < type2) + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 ); + else if (type1 > type2) + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); + + /* test for name of pidl */ + _ILSimpleGetText (pidl1, szTemp1, MAX_PATH); + _ILSimpleGetText (pidl2, szTemp2, MAX_PATH); + nReturn = lstrcmpiA (szTemp1, szTemp2); + if (nReturn < 0) + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 ); + else if (nReturn > 0) + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); + + /* test of complex pidls */ + firstpidl = ILCloneFirst (pidl1); + nextpidl1 = ILGetNext (pidl1); + nextpidl2 = ILGetNext (pidl2); + + /* optimizing: test special cases and bind not deeper */ + /* the deeper shellfolder would do the same */ + isEmpty1 = _ILIsDesktop (nextpidl1); + isEmpty2 = _ILIsDesktop (nextpidl2); + + if (isEmpty1 && isEmpty2) { + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 0 ); + } else if (isEmpty1) { + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, (WORD)-1 ); + } else if (isEmpty2) { + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ); + /* optimizing end */ + } else if (SUCCEEDED (iface->BindToObject(firstpidl, NULL, IID_IShellFolder, (LPVOID *)&psf))) { + nReturn = psf->CompareIDs(lParam, nextpidl1, nextpidl2); + psf->Release(); + } + ILFree (firstpidl); + return nReturn; +} + +/*********************************************************************** + * SHCreateLinks + * + * Undocumented. + */ +HRESULT WINAPI SHCreateLinks( HWND hWnd, LPCSTR lpszDir, LPDATAOBJECT lpDataObject, + UINT uFlags, LPITEMIDLIST *lppidlLinks) +{ + FIXME("%p %s %p %08x %p\n",hWnd,lpszDir,lpDataObject,uFlags,lppidlLinks); + return E_NOTIMPL; +} + +/*********************************************************************** + * SHOpenFolderAndSelectItems + * + * Unimplemented. + */ +EXTERN_C HRESULT +WINAPI +SHOpenFolderAndSelectItems(LPITEMIDLIST pidlFolder, + UINT cidl, + PCUITEMID_CHILD_ARRAY apidl, + DWORD dwFlags) +{ + FIXME("SHOpenFolderAndSelectItems() stub\n"); + return E_NOTIMPL; +} diff --git a/reactos/dll/win32/shell32/shlfsbind.cpp b/reactos/dll/win32/shell32/shlfsbind.cpp new file mode 100644 index 00000000000..af48a54c553 --- /dev/null +++ b/reactos/dll/win32/shell32/shlfsbind.cpp @@ -0,0 +1,164 @@ +/* + * File System Bind Data object to use as parameter for the bind context to + * IShellFolder_ParseDisplayName + * + * Copyright 2003 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 + * + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(pidl); + +/*********************************************************************** + * IFileSystemBindData implementation + */ +class IFileSystemBindDataImpl : + public CComObjectRootEx, + public IFileSystemBindData +{ +private: + WIN32_FIND_DATAW findFile; +public: + IFileSystemBindDataImpl(); + ~IFileSystemBindDataImpl(); + + // *** IFileSystemBindData methods *** + virtual HRESULT STDMETHODCALLTYPE SetFindData(const WIN32_FIND_DATAW *pfd); + virtual HRESULT STDMETHODCALLTYPE GetFindData(WIN32_FIND_DATAW *pfd); + +DECLARE_NOT_AGGREGATABLE(IFileSystemBindDataImpl) +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(IFileSystemBindDataImpl) + COM_INTERFACE_ENTRY_IID(IID_IFileSystemBindData, IFileSystemBindData) +END_COM_MAP() +}; + +static const WCHAR wFileSystemBindData[] = { + 'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d','D','a','t','a',0}; + +HRESULT WINAPI IFileSystemBindData_Constructor(const WIN32_FIND_DATAW *pfd, LPBC *ppV) +{ + CComPtr fileSystemBindData; + CComPtr bindContext; + BIND_OPTS bindOpts; + HRESULT hResult; + + TRACE("%p, %p\n", pfd, ppV); + + if (ppV == NULL) + return E_INVALIDARG; + + *ppV = NULL; + + hResult = IFileSystemBindDataImpl::_CreatorClass::CreateInstance(NULL, IID_IFileSystemBindData, (void **)&fileSystemBindData); + if (FAILED(hResult)) + return hResult; + hResult = fileSystemBindData->SetFindData(pfd); + if (FAILED(hResult)) + return hResult; + + hResult = CreateBindCtx(0, &bindContext); + if (FAILED(hResult)) + return hResult; + bindOpts.cbStruct = sizeof(BIND_OPTS); + bindOpts.grfFlags = 0; + bindOpts.grfMode = STGM_CREATE; + bindOpts.dwTickCountDeadline = 0; + hResult = bindContext->SetBindOptions(&bindOpts); + if (FAILED(hResult)) + return hResult; + hResult = bindContext->RegisterObjectParam((LPOLESTR)wFileSystemBindData, fileSystemBindData); + if (FAILED(hResult)) + return hResult; + + *ppV = bindContext.Detach(); + + return S_OK; +} + +HRESULT WINAPI FileSystemBindData_GetFindData(LPBC pbc, WIN32_FIND_DATAW *pfd) +{ + CComPtr pUnk; + CComPtr pfsbd; + HRESULT ret; + + TRACE("%p, %p\n", pbc, pfd); + + if (!pfd) + return E_INVALIDARG; + + ret = pbc->GetObjectParam((LPOLESTR)wFileSystemBindData, &pUnk); + if (SUCCEEDED(ret)) + { + ret = pUnk->QueryInterface(IID_IFileSystemBindData, (LPVOID *)&pfsbd); + if (SUCCEEDED(ret)) + ret = pfsbd->GetFindData(pfd); + } + return ret; +} + +HRESULT WINAPI FileSystemBindData_SetFindData(LPBC pbc, const WIN32_FIND_DATAW *pfd) +{ + CComPtr pUnk; + CComPtr pfsbd; + HRESULT ret; + + TRACE("%p, %p\n", pbc, pfd); + + ret = pbc->GetObjectParam((LPOLESTR)wFileSystemBindData, &pUnk); + if (SUCCEEDED(ret)) + { + ret = pUnk->QueryInterface(IID_IFileSystemBindData, (LPVOID *)&pfsbd); + if (SUCCEEDED(ret)) + ret = pfsbd->SetFindData(pfd); + } + return ret; +} + +IFileSystemBindDataImpl::IFileSystemBindDataImpl() +{ + memset(&findFile, 0, sizeof(WIN32_FIND_DATAW)); +} + +IFileSystemBindDataImpl::~IFileSystemBindDataImpl() +{ + TRACE(" destroying ISFBindPidl(%p)\n", this); +} + +HRESULT WINAPI IFileSystemBindDataImpl::GetFindData(WIN32_FIND_DATAW *pfd) +{ + TRACE("(%p), %p\n", this, pfd); + + if (!pfd) + return E_INVALIDARG; + + memcpy(pfd, &findFile, sizeof(WIN32_FIND_DATAW)); + return NOERROR; +} + +HRESULT WINAPI IFileSystemBindDataImpl::SetFindData(const WIN32_FIND_DATAW *pfd) +{ + TRACE("(%p), %p\n", this, pfd); + + if (pfd) + memcpy(&findFile, pfd, sizeof(WIN32_FIND_DATAW)); + else + memset(&findFile, 0, sizeof(WIN32_FIND_DATAW)); + return NOERROR; +} diff --git a/reactos/dll/win32/shell32/shlmenu.cpp b/reactos/dll/win32/shell32/shlmenu.cpp new file mode 100644 index 00000000000..04d95d7aad7 --- /dev/null +++ b/reactos/dll/win32/shell32/shlmenu.cpp @@ -0,0 +1,982 @@ +/* + * see www.geocities.com/SiliconValley/4942/filemenu.html + * + * Copyright 1999, 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 + */ + +#include + +#ifdef FM_SEPARATOR +#undef FM_SEPARATOR +#endif +#define FM_SEPARATOR (LPCWSTR)1 + +static BOOL FileMenu_AppendItemW(HMENU hMenu, LPCWSTR lpText, UINT uID, int icon, + HMENU hMenuPopup, int nItemHeight); + +typedef struct +{ + BOOL bInitialized; + BOOL bFixedItems; + /* create */ + COLORREF crBorderColor; + int nBorderWidth; + HBITMAP hBorderBmp; + + /* insert using pidl */ + LPITEMIDLIST pidl; + UINT uID; + UINT uFlags; + UINT uEnumFlags; + LPFNFMCALLBACK lpfnCallback; +} FMINFO, *LPFMINFO; + +typedef struct +{ int cchItemText; + int iIconIndex; + HMENU hMenu; + WCHAR szItemText[1]; +} FMITEM, * LPFMITEM; + +static BOOL bAbortInit; + +#define CCH_MAXITEMTEXT 256 + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +static LPFMINFO FM_GetMenuInfo(HMENU hmenu) +{ + MENUINFO MenuInfo; + LPFMINFO menudata; + + MenuInfo.cbSize = sizeof(MENUINFO); + MenuInfo.fMask = MIM_MENUDATA; + + if (! GetMenuInfo(hmenu, &MenuInfo)) + return NULL; + + menudata = (LPFMINFO)MenuInfo.dwMenuData; + + if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO))) + { + ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize); + return 0; + } + + return menudata; + +} +/************************************************************************* + * FM_SetMenuParameter [internal] + * + */ +static LPFMINFO FM_SetMenuParameter( + HMENU hmenu, + UINT uID, + LPCITEMIDLIST pidl, + UINT uFlags, + UINT uEnumFlags, + LPFNFMCALLBACK lpfnCallback) +{ + LPFMINFO menudata; + + TRACE("\n"); + + menudata = FM_GetMenuInfo(hmenu); + + SHFree(menudata->pidl); + + menudata->uID = uID; + menudata->pidl = ILClone(pidl); + menudata->uFlags = uFlags; + menudata->uEnumFlags = uEnumFlags; + menudata->lpfnCallback = lpfnCallback; + + return menudata; +} + +/************************************************************************* + * FM_InitMenuPopup [internal] + * + */ +static int FM_InitMenuPopup(HMENU hmenu, LPCITEMIDLIST pAlternatePidl) +{ IShellFolder *lpsf, *lpsf2; + ULONG ulItemAttr = SFGAO_FOLDER; + UINT uID, uEnumFlags; + LPFNFMCALLBACK lpfnCallback; + LPCITEMIDLIST pidl; + WCHAR sTemp[MAX_PATH]; + int NumberOfItems = 0, iIcon; + MENUINFO MenuInfo; + LPFMINFO menudata; + + TRACE("%p %p\n", hmenu, pAlternatePidl); + + MenuInfo.cbSize = sizeof(MENUINFO); + MenuInfo.fMask = MIM_MENUDATA; + + if (! GetMenuInfo(hmenu, &MenuInfo)) + return FALSE; + + menudata = (LPFMINFO)MenuInfo.dwMenuData; + + if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO))) + { + ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize); + return 0; + } + + if (menudata->bInitialized) + return 0; + + pidl = (pAlternatePidl? pAlternatePidl: menudata->pidl); + if (!pidl) + return 0; + + uID = menudata->uID; + uEnumFlags = menudata->uEnumFlags; + lpfnCallback = menudata->lpfnCallback; + menudata->bInitialized = FALSE; + + SetMenuInfo(hmenu, &MenuInfo); + + if (SUCCEEDED (SHGetDesktopFolder(&lpsf))) + { + if (SUCCEEDED(lpsf->BindToObject(pidl, 0, IID_IShellFolder, (LPVOID *)&lpsf2))) + { + IEnumIDList *lpe = NULL; + + if (SUCCEEDED (lpsf2->EnumObjects(0, uEnumFlags, &lpe ))) + { + + LPITEMIDLIST pidlTemp = NULL; + ULONG ulFetched; + + while ((!bAbortInit) && (NOERROR == lpe->Next(1,&pidlTemp,&ulFetched))) + { + if (SUCCEEDED (lpsf->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlTemp, &ulItemAttr))) + { + ILGetDisplayNameExW(NULL, pidlTemp, sTemp, ILGDN_FORPARSING); + if (! (PidlToSicIndex(lpsf, pidlTemp, FALSE, 0, &iIcon))) + iIcon = FM_BLANK_ICON; + if ( SFGAO_FOLDER & ulItemAttr) + { + LPFMINFO lpFmMi; + MENUINFO MenuInfo; + HMENU hMenuPopup = CreatePopupMenu(); + + lpFmMi = (LPFMINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO)); + + lpFmMi->pidl = ILCombine(pidl, pidlTemp); + lpFmMi->uEnumFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS; + + MenuInfo.cbSize = sizeof(MENUINFO); + MenuInfo.fMask = MIM_MENUDATA; + MenuInfo.dwMenuData = (ULONG_PTR) lpFmMi; + SetMenuInfo (hMenuPopup, &MenuInfo); + + FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, hMenuPopup, FM_DEFAULT_HEIGHT); + } + else + { + LPWSTR pExt = PathFindExtensionW(sTemp); + if (pExt) + *pExt = 0; + FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, 0, FM_DEFAULT_HEIGHT); + } + } + + if (lpfnCallback) + { + TRACE("enter callback\n"); + lpfnCallback ( pidl, pidlTemp); + TRACE("leave callback\n"); + } + + NumberOfItems++; + } + lpe->Release(); + } + lpsf2->Release(); + } + lpsf->Release(); + } + + if ( GetMenuItemCount (hmenu) == 0 ) + { + static const WCHAR szEmpty[] = { '(','e','m','p','t','y',')',0 }; + FileMenu_AppendItemW (hmenu, szEmpty, uID, FM_BLANK_ICON, 0, FM_DEFAULT_HEIGHT); + NumberOfItems++; + } + + menudata->bInitialized = TRUE; + SetMenuInfo(hmenu, &MenuInfo); + + return NumberOfItems; +} +/************************************************************************* + * FileMenu_Create [SHELL32.114] + * + * NOTES + * for non-root menus values are + * (ffffffff,00000000,00000000,00000000,00000000) + */ +HMENU WINAPI FileMenu_Create ( + COLORREF crBorderColor, + int nBorderWidth, + HBITMAP hBorderBmp, + int nSelHeight, + UINT uFlags) +{ + MENUINFO MenuInfo; + LPFMINFO menudata; + + HMENU hMenu = CreatePopupMenu(); + + TRACE("0x%08x 0x%08x %p 0x%08x 0x%08x hMenu=%p\n", + crBorderColor, nBorderWidth, hBorderBmp, nSelHeight, uFlags, hMenu); + + menudata = (LPFMINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO)); + menudata->crBorderColor = crBorderColor; + menudata->nBorderWidth = nBorderWidth; + menudata->hBorderBmp = hBorderBmp; + + MenuInfo.cbSize = sizeof(MENUINFO); + MenuInfo.fMask = MIM_MENUDATA; + MenuInfo.dwMenuData = (ULONG_PTR) menudata; + SetMenuInfo (hMenu, &MenuInfo); + + return hMenu; +} + +/************************************************************************* + * FileMenu_Destroy [SHELL32.118] + * + * NOTES + * exported by name + */ +void WINAPI FileMenu_Destroy (HMENU hmenu) +{ + LPFMINFO menudata; + + TRACE("%p\n", hmenu); + + FileMenu_DeleteAllItems (hmenu); + + menudata = FM_GetMenuInfo(hmenu); + + SHFree( menudata->pidl); + HeapFree(GetProcessHeap(), 0, menudata); + + DestroyMenu (hmenu); +} + +/************************************************************************* + * FileMenu_AppendItem [SHELL32.115] + * + */ +static BOOL FileMenu_AppendItemW( + HMENU hMenu, + LPCWSTR lpText, + UINT uID, + int icon, + HMENU hMenuPopup, + int nItemHeight) +{ + MENUITEMINFOW mii; + LPFMITEM myItem; + LPFMINFO menudata; + MENUINFO MenuInfo; + + + TRACE("%p %s 0x%08x 0x%08x %p 0x%08x\n", + hMenu, (lpText!=FM_SEPARATOR) ? debugstr_w(lpText) : NULL, + uID, icon, hMenuPopup, nItemHeight); + + ZeroMemory (&mii, sizeof(MENUITEMINFOW)); + + mii.cbSize = sizeof(MENUITEMINFOW); + + if (lpText != FM_SEPARATOR) + { + int len = strlenW (lpText); + myItem = (LPFMITEM)SHAlloc(sizeof(FMITEM) + len*sizeof(WCHAR)); + wcscpy (myItem->szItemText, lpText); + myItem->cchItemText = len; + myItem->iIconIndex = icon; + myItem->hMenu = hMenu; + mii.fMask = MIIM_DATA; + mii.dwItemData = (ULONG_PTR) myItem; + } + + if ( hMenuPopup ) + { /* sub menu */ + mii.fMask |= MIIM_TYPE | MIIM_SUBMENU; + mii.fType = MFT_OWNERDRAW; + mii.hSubMenu = hMenuPopup; + } + else if (lpText == FM_SEPARATOR ) + { mii.fMask |= MIIM_ID | MIIM_TYPE; + mii.fType = MFT_SEPARATOR; + } + else + { /* normal item */ + mii.fMask |= MIIM_ID | MIIM_TYPE | MIIM_STATE; + mii.fState = MFS_ENABLED | MFS_DEFAULT; + mii.fType = MFT_OWNERDRAW; + } + mii.wID = uID; + + InsertMenuItemW (hMenu, (UINT)-1, TRUE, &mii); + + /* set bFixedItems to true */ + MenuInfo.cbSize = sizeof(MENUINFO); + MenuInfo.fMask = MIM_MENUDATA; + + if (! GetMenuInfo(hMenu, &MenuInfo)) + return FALSE; + + menudata = (LPFMINFO)MenuInfo.dwMenuData; + if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO))) + { + ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize); + return 0; + } + + menudata->bFixedItems = TRUE; + SetMenuInfo(hMenu, &MenuInfo); + + return TRUE; + +} + +/**********************************************************************/ + +EXTERN_C BOOL WINAPI FileMenu_AppendItemAW( + HMENU hMenu, + LPCVOID lpText, + UINT uID, + int icon, + HMENU hMenuPopup, + int nItemHeight) +{ + BOOL ret; + + if (!lpText) return FALSE; + + if (SHELL_OsIsUnicode() || lpText == FM_SEPARATOR) + ret = FileMenu_AppendItemW(hMenu, (LPWSTR)lpText, uID, icon, hMenuPopup, nItemHeight); + else + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, (LPSTR)lpText, -1, NULL, 0 ); + LPWSTR lpszText = (LPWSTR)HeapAlloc ( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + if (!lpszText) return FALSE; + MultiByteToWideChar( CP_ACP, 0, (LPSTR)lpText, -1, lpszText, len ); + ret = FileMenu_AppendItemW(hMenu, lpszText, uID, icon, hMenuPopup, nItemHeight); + HeapFree( GetProcessHeap(), 0, lpszText ); + } + + return ret; +} + +/************************************************************************* + * FileMenu_InsertUsingPidl [SHELL32.110] + * + * NOTES + * uEnumFlags any SHCONTF flag + */ +int WINAPI FileMenu_InsertUsingPidl ( + HMENU hmenu, + UINT uID, + LPCITEMIDLIST pidl, + UINT uFlags, + UINT uEnumFlags, + LPFNFMCALLBACK lpfnCallback) +{ + TRACE("%p 0x%08x %p 0x%08x 0x%08x %p\n", + hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback); + + pdump (pidl); + + bAbortInit = FALSE; + + FM_SetMenuParameter(hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback); + + return FM_InitMenuPopup(hmenu, NULL); +} + +/************************************************************************* + * FileMenu_ReplaceUsingPidl [SHELL32.113] + * + * FIXME: the static items are deleted but won't be refreshed + */ +int WINAPI FileMenu_ReplaceUsingPidl( + HMENU hmenu, + UINT uID, + LPCITEMIDLIST pidl, + UINT uEnumFlags, + LPFNFMCALLBACK lpfnCallback) +{ + TRACE("%p 0x%08x %p 0x%08x %p\n", + hmenu, uID, pidl, uEnumFlags, lpfnCallback); + + FileMenu_DeleteAllItems (hmenu); + + FM_SetMenuParameter(hmenu, uID, pidl, 0, uEnumFlags, lpfnCallback); + + return FM_InitMenuPopup(hmenu, NULL); +} + +/************************************************************************* + * FileMenu_Invalidate [SHELL32.111] + */ +void WINAPI FileMenu_Invalidate (HMENU hMenu) +{ + FIXME("%p\n",hMenu); +} + +/************************************************************************* + * FileMenu_FindSubMenuByPidl [SHELL32.106] + */ +HMENU WINAPI FileMenu_FindSubMenuByPidl( + HMENU hMenu, + LPCITEMIDLIST pidl) +{ + FIXME("%p %p\n",hMenu, pidl); + return 0; +} + +/************************************************************************* + * FileMenu_AppendFilesForPidl [SHELL32.124] + */ +int WINAPI FileMenu_AppendFilesForPidl( + HMENU hmenu, + LPCITEMIDLIST pidl, + BOOL bAddSeparator) +{ + LPFMINFO menudata; + + menudata = FM_GetMenuInfo(hmenu); + + menudata->bInitialized = FALSE; + + FM_InitMenuPopup(hmenu, pidl); + + if (bAddSeparator) + FileMenu_AppendItemW (hmenu, FM_SEPARATOR, 0, 0, 0, FM_DEFAULT_HEIGHT); + + TRACE("%p %p 0x%08x\n",hmenu, pidl,bAddSeparator); + + return 0; +} +/************************************************************************* + * FileMenu_AddFilesForPidl [SHELL32.125] + * + * NOTES + * uEnumFlags any SHCONTF flag + */ +int WINAPI FileMenu_AddFilesForPidl ( + HMENU hmenu, + UINT uReserved, + UINT uID, + LPCITEMIDLIST pidl, + UINT uFlags, + UINT uEnumFlags, + LPFNFMCALLBACK lpfnCallback) +{ + TRACE("%p 0x%08x 0x%08x %p 0x%08x 0x%08x %p\n", + hmenu, uReserved, uID, pidl, uFlags, uEnumFlags, lpfnCallback); + + return FileMenu_InsertUsingPidl ( hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback); + +} + + +/************************************************************************* + * FileMenu_TrackPopupMenuEx [SHELL32.116] + */ +BOOL WINAPI FileMenu_TrackPopupMenuEx ( + HMENU hMenu, + UINT uFlags, + int x, + int y, + HWND hWnd, + LPTPMPARAMS lptpm) +{ + TRACE("%p 0x%08x 0x%x 0x%x %p %p\n", + hMenu, uFlags, x, y, hWnd, lptpm); + return TrackPopupMenuEx(hMenu, uFlags, x, y, hWnd, lptpm); +} + +/************************************************************************* + * FileMenu_GetLastSelectedItemPidls [SHELL32.107] + */ +BOOL WINAPI FileMenu_GetLastSelectedItemPidls( + UINT uReserved, + LPCITEMIDLIST *ppidlFolder, + LPCITEMIDLIST *ppidlItem) +{ + FIXME("0x%08x %p %p\n",uReserved, ppidlFolder, ppidlItem); + return 0; +} + +#define FM_ICON_SIZE 16 +#define FM_Y_SPACE 4 +#define FM_SPACE1 4 +#define FM_SPACE2 2 +#define FM_LEFTBORDER 2 +#define FM_RIGHTBORDER 8 +/************************************************************************* + * FileMenu_MeasureItem [SHELL32.112] + */ +LRESULT WINAPI FileMenu_MeasureItem( + HWND hWnd, + LPMEASUREITEMSTRUCT lpmis) +{ + LPFMITEM pMyItem = (LPFMITEM)(lpmis->itemData); + HDC hdc = GetDC(hWnd); + SIZE size; + LPFMINFO menuinfo; + + TRACE("%p %p %s\n", hWnd, lpmis, debugstr_w(pMyItem->szItemText)); + + GetTextExtentPoint32W(hdc, pMyItem->szItemText, pMyItem->cchItemText, &size); + + lpmis->itemWidth = size.cx + FM_LEFTBORDER + FM_ICON_SIZE + FM_SPACE1 + FM_SPACE2 + FM_RIGHTBORDER; + lpmis->itemHeight = (size.cy > (FM_ICON_SIZE + FM_Y_SPACE)) ? size.cy : (FM_ICON_SIZE + FM_Y_SPACE); + + /* add the menubitmap */ + menuinfo = FM_GetMenuInfo(pMyItem->hMenu); + if (menuinfo->nBorderWidth) + lpmis->itemWidth += menuinfo->nBorderWidth; + + TRACE("-- 0x%04x 0x%04x\n", lpmis->itemWidth, lpmis->itemHeight); + ReleaseDC (hWnd, hdc); + return 0; +} +/************************************************************************* + * FileMenu_DrawItem [SHELL32.105] + */ +LRESULT WINAPI FileMenu_DrawItem( + HWND hWnd, + LPDRAWITEMSTRUCT lpdis) +{ + LPFMITEM pMyItem = (LPFMITEM)(lpdis->itemData); + COLORREF clrPrevText, clrPrevBkgnd; + int xi,yi,xt,yt; + HIMAGELIST hImageList; + RECT TextRect; + LPFMINFO menuinfo; + + TRACE("%p %p %s\n", hWnd, lpdis, debugstr_w(pMyItem->szItemText)); + + if (lpdis->itemState & ODS_SELECTED) + { + clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHTTEXT)); + clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHT)); + } + else + { + clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_MENUTEXT)); + clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_MENU)); + } + + CopyRect(&TextRect, &(lpdis->rcItem)); + + /* add the menubitmap */ + menuinfo = FM_GetMenuInfo(pMyItem->hMenu); + if (menuinfo->nBorderWidth) + TextRect.left += menuinfo->nBorderWidth; + + TextRect.left += FM_LEFTBORDER; + xi = TextRect.left + FM_SPACE1; + yi = TextRect.top + FM_Y_SPACE/2; + TextRect.bottom -= FM_Y_SPACE/2; + + xt = xi + FM_ICON_SIZE + FM_SPACE2; + yt = yi; + + ExtTextOutW (lpdis->hDC, xt , yt, ETO_OPAQUE, &TextRect, pMyItem->szItemText, pMyItem->cchItemText, NULL); + + Shell_GetImageLists(0, &hImageList); + ImageList_Draw(hImageList, pMyItem->iIconIndex, lpdis->hDC, xi, yi, ILD_NORMAL); + + TRACE("-- 0x%04x 0x%04x 0x%04x 0x%04x\n", TextRect.left, TextRect.top, TextRect.right, TextRect.bottom); + + SetTextColor(lpdis->hDC, clrPrevText); + SetBkColor(lpdis->hDC, clrPrevBkgnd); + + return TRUE; +} + +/************************************************************************* + * FileMenu_InitMenuPopup [SHELL32.109] + * + * NOTES + * The filemenu is an ownerdrawn menu. Call this function responding to + * WM_INITPOPUPMENU + * + */ +BOOL WINAPI FileMenu_InitMenuPopup (HMENU hmenu) +{ + FM_InitMenuPopup(hmenu, NULL); + return TRUE; +} + +/************************************************************************* + * FileMenu_HandleMenuChar [SHELL32.108] + */ +LRESULT WINAPI FileMenu_HandleMenuChar( + HMENU hMenu, + WPARAM wParam) +{ + FIXME("%p 0x%08lx\n",hMenu,wParam); + return 0; +} + +/************************************************************************* + * FileMenu_DeleteAllItems [SHELL32.104] + * + * NOTES + * exported by name + */ +BOOL WINAPI FileMenu_DeleteAllItems (HMENU hmenu) +{ + MENUITEMINFOW mii; + LPFMINFO menudata; + + int i; + + TRACE("%p\n", hmenu); + + ZeroMemory ( &mii, sizeof(MENUITEMINFOW)); + mii.cbSize = sizeof(MENUITEMINFOW); + mii.fMask = MIIM_SUBMENU|MIIM_DATA; + + for (i = 0; i < GetMenuItemCount( hmenu ); i++) + { GetMenuItemInfoW(hmenu, i, TRUE, &mii ); + + SHFree((LPFMINFO)mii.dwItemData); + + if (mii.hSubMenu) + FileMenu_Destroy(mii.hSubMenu); + } + + while (DeleteMenu (hmenu, 0, MF_BYPOSITION)){}; + + menudata = FM_GetMenuInfo(hmenu); + + menudata->bInitialized = FALSE; + + return TRUE; +} + +/************************************************************************* + * FileMenu_DeleteItemByCmd [SHELL32.117] + * + */ +BOOL WINAPI FileMenu_DeleteItemByCmd (HMENU hMenu, UINT uID) +{ + MENUITEMINFOW mii; + + TRACE("%p 0x%08x\n", hMenu, uID); + + ZeroMemory ( &mii, sizeof(MENUITEMINFOW)); + mii.cbSize = sizeof(MENUITEMINFOW); + mii.fMask = MIIM_SUBMENU; + + GetMenuItemInfoW(hMenu, uID, FALSE, &mii ); + if ( mii.hSubMenu ) + { + /* FIXME: Do what? */ + } + + DeleteMenu(hMenu, MF_BYCOMMAND, uID); + return TRUE; +} + +/************************************************************************* + * FileMenu_DeleteItemByIndex [SHELL32.140] + */ +BOOL WINAPI FileMenu_DeleteItemByIndex ( HMENU hMenu, UINT uPos) +{ + MENUITEMINFOW mii; + + TRACE("%p 0x%08x\n", hMenu, uPos); + + ZeroMemory ( &mii, sizeof(MENUITEMINFOW)); + mii.cbSize = sizeof(MENUITEMINFOW); + mii.fMask = MIIM_SUBMENU; + + GetMenuItemInfoW(hMenu, uPos, TRUE, &mii ); + if ( mii.hSubMenu ) + { + /* FIXME: Do what? */ + } + + DeleteMenu(hMenu, MF_BYPOSITION, uPos); + return TRUE; +} + +/************************************************************************* + * FileMenu_DeleteItemByFirstID [SHELL32.141] + */ +EXTERN_C BOOL WINAPI FileMenu_DeleteItemByFirstID( + HMENU hMenu, + UINT uID) +{ + TRACE("%p 0x%08x\n", hMenu, uID); + return 0; +} + +/************************************************************************* + * FileMenu_DeleteSeparator [SHELL32.142] + */ +BOOL WINAPI FileMenu_DeleteSeparator(HMENU hMenu) +{ + TRACE("%p\n", hMenu); + return 0; +} + +/************************************************************************* + * FileMenu_EnableItemByCmd [SHELL32.143] + */ +BOOL WINAPI FileMenu_EnableItemByCmd( + HMENU hMenu, + UINT uID, + BOOL bEnable) +{ + TRACE("%p 0x%08x 0x%08x\n", hMenu, uID,bEnable); + return 0; +} + +/************************************************************************* + * FileMenu_GetItemExtent [SHELL32.144] + * + * NOTES + * if the menu is too big, entries are getting cut away!! + */ +DWORD WINAPI FileMenu_GetItemExtent (HMENU hMenu, UINT uPos) +{ RECT rect; + + FIXME("%p 0x%08x\n", hMenu, uPos); + + if (GetMenuItemRect(0, hMenu, uPos, &rect)) + { FIXME("0x%04x 0x%04x 0x%04x 0x%04x\n", + rect.right, rect.left, rect.top, rect.bottom); + return ((rect.right-rect.left)<<16) + (rect.top-rect.bottom); + } + return 0x00100010; /*FIXME*/ +} + +/************************************************************************* + * FileMenu_AbortInitMenu [SHELL32.120] + * + */ +void WINAPI FileMenu_AbortInitMenu (void) +{ TRACE("\n"); + bAbortInit = TRUE; +} + +/************************************************************************* + * SHFind_InitMenuPopup [SHELL32.149] + * + * Get the IContextMenu instance for the submenu of options displayed + * for the Search entry in the Classic style Start menu. + * + * PARAMETERS + * hMenu [in] handle of menu previously created + * hWndParent [in] parent window + * w [in] no pointer (0x209 over here) perhaps menu IDs ??? + * x [in] no pointer (0x226 over here) + * + * RETURNS + * LPXXXXX pointer to struct containing a func addr at offset 8 + * or NULL at failure. + */ +EXTERN_C IContextMenu * WINAPI SHFind_InitMenuPopup (HMENU hMenu, HWND hWndParent, UINT w, UINT x) +{ + FIXME("hmenu=%p hwnd=%p 0x%08x 0x%08x stub\n", + hMenu,hWndParent,w,x); + return NULL; /* this is supposed to be a pointer */ +} + +/************************************************************************* + * _SHIsMenuSeparator (internal) + */ +static BOOL _SHIsMenuSeparator(HMENU hm, int i) +{ + MENUITEMINFOW mii; + + mii.cbSize = sizeof(MENUITEMINFOW); + mii.fMask = MIIM_TYPE; + mii.cch = 0; /* WARNING: We MUST initialize it to 0*/ + if (!GetMenuItemInfoW(hm, i, TRUE, &mii)) + { + return(FALSE); + } + + if (mii.fType & MFT_SEPARATOR) + { + return(TRUE); + } + + return(FALSE); +} + +/************************************************************************* + * Shell_MergeMenus [SHELL32.67] + */ +UINT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags) +{ + int nItem; + HMENU hmSubMenu; + BOOL bAlreadySeparated; + MENUITEMINFOW miiSrc; + WCHAR szName[256]; + UINT uTemp, uIDMax = uIDAdjust; + + TRACE("hmenu1=%p hmenu2=%p 0x%04x 0x%04x 0x%04x 0x%04x\n", + hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags); + + if (!hmDst || !hmSrc) + return uIDMax; + + nItem = GetMenuItemCount(hmDst); + + if (uInsert >= (UINT)nItem) /* insert position inside menu? */ + { + uInsert = (UINT)nItem; /* append on the end */ + bAlreadySeparated = TRUE; + } + else + { + bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert); + } + + if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) + { + /* Add a separator between the menus */ + InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); + bAlreadySeparated = TRUE; + } + + + /* Go through the menu items and clone them*/ + for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--) + { + miiSrc.cbSize = sizeof(MENUITEMINFOW); + miiSrc.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA; + + /* We need to reset this every time through the loop in case menus DON'T have IDs*/ + miiSrc.fType = MFT_STRING; + miiSrc.dwTypeData = szName; + miiSrc.dwItemData = 0; + miiSrc.cch = sizeof(szName)/sizeof(WCHAR); + + if (!GetMenuItemInfoW(hmSrc, nItem, TRUE, &miiSrc)) + { + continue; + } + +/* TRACE("found menu=0x%04x %s id=0x%04x mask=0x%08x smenu=0x%04x\n", hmSrc, debugstr_a(miiSrc.dwTypeData), miiSrc.wID, miiSrc.fMask, miiSrc.hSubMenu); +*/ + if (miiSrc.fType & MFT_SEPARATOR) + { + /* This is a separator; don't put two of them in a row */ + if (bAlreadySeparated) + continue; + bAlreadySeparated = TRUE; + } + else if (miiSrc.hSubMenu) + { + if ((uFlags & MM_SUBMENUSHAVEIDS) != 0 && miiSrc.wID != (UINT)miiSrc.hSubMenu) + { + miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */ + + if (miiSrc.wID > uIDAdjustMax && miiSrc.wID > uIDAdjustMax) /* skip ID's higher uIDAdjustMax */ + continue; + if (uIDMax <= miiSrc.wID) /* remember the highest ID */ + uIDMax = miiSrc.wID + 1; + } + else + { + miiSrc.fMask &= ~MIIM_ID; /* Don't set IDs for submenus that didn't have them already */ + } + hmSubMenu = miiSrc.hSubMenu; + + miiSrc.hSubMenu = CreatePopupMenu(); + + if (!miiSrc.hSubMenu) return(uIDMax); + + uTemp = Shell_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, uIDAdjustMax, uFlags & MM_SUBMENUSHAVEIDS); + + if (uIDMax <= uTemp) + uIDMax = uTemp; + + bAlreadySeparated = FALSE; + } + else /* normal menu item */ + { + miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */ + + if (miiSrc.wID > uIDAdjustMax && miiSrc.wID > uIDAdjustMax) /* skip ID's higher uIDAdjustMax */{ + continue; + } + if (uIDMax <= miiSrc.wID) /* remember the highest ID */ + uIDMax = miiSrc.wID + 1; + + bAlreadySeparated = FALSE; + } + +/* TRACE("inserting menu=0x%04x %s id=0x%04x mask=0x%08x smenu=0x%04x\n", hmDst, debugstr_a(miiSrc.dwTypeData), miiSrc.wID, miiSrc.fMask, miiSrc.hSubMenu); +*/ + if (!InsertMenuItemW(hmDst, uInsert, TRUE, &miiSrc)) + { + return(uIDMax); + } + } + + /* Ensure the correct number of separators at the beginning of the + inserted menu items*/ + if (uInsert == 0) + { + if (bAlreadySeparated) + { + DeleteMenu(hmDst, uInsert, MF_BYPOSITION); + } + } + else + { + if (_SHIsMenuSeparator(hmDst, uInsert-1)) + { + if (bAlreadySeparated) + { + DeleteMenu(hmDst, uInsert, MF_BYPOSITION); + } + } + else + { + if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) + { + /* Add a separator between the menus*/ + InsertMenuW(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); + } + } + } + return(uIDMax); +} diff --git a/reactos/dll/win32/shell32/shlview.cpp b/reactos/dll/win32/shell32/shlview.cpp new file mode 100644 index 00000000000..e25a1be2aa5 --- /dev/null +++ b/reactos/dll/win32/shell32/shlview.cpp @@ -0,0 +1,2745 @@ +/* + * ShellView + * + * Copyright 1998,1999 + * + * 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 + +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, + public CComObjectRootEx, + public IShellView, + public IFolderView, + public IOleCommandTarget, + public IDropTarget, + public IDropSource, + public IViewObject, + public IServiceProvider +{ +private: + CComPtr pSFParent; + CComPtr pSF2Parent; + CComPtr pShellBrowser; + CComPtr 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 pAdvSink; + // for drag and drop + CComPtr pCurDropTarget; /* The sub-item, which is currently dragged over */ + CComPtr 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 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(hWnd); + pThis->AddRef(); + result = CWindowImpl::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 pdt; + SHChangeNotifyEntry ntreg; + CComPtr 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 selection; + CComPtr 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 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 pda; + STGMEDIUM medium; + FORMATETC formatetc; + LPITEMIDLIST * apidl; + LPITEMIDLIST pidl; + CComPtr psfFrom; + CComPtr psfDesktop; + CComPtr psfTarget; + LPIDA lpcida; + CComPtr psfhlpdst; + CComPtr 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 *theView; + CComPtr result; + HRESULT hResult; + + if (newView == NULL) + return E_POINTER; + + *newView = NULL; + ATLTRY (theView = new CComObject); + + 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; +} diff --git a/reactos/dll/win32/shell32/shpolicy.cpp b/reactos/dll/win32/shell32/shpolicy.cpp new file mode 100644 index 00000000000..88e487c5207 --- /dev/null +++ b/reactos/dll/win32/shell32/shpolicy.cpp @@ -0,0 +1,905 @@ +/* + * shpolicy.c - Data for shell/system policies. + * + * Copyright 1999 Ian Schmidt + * + * 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 + * + * NOTES: + * + * Some of these policies can be tweaked via the System Policy + * Editor which came with the Win95 Migration Guide, although + * there doesn't appear to be an updated Win98 version that + * would handle the many new policies introduced since then. + * You could easily write one with the information in + * this file... + * + * Up to date as of SHELL32 v5.00 (W2K) + */ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +#define SHELL_NO_POLICY 0xffffffff + +typedef struct tagPOLICYDAT +{ + RESTRICTIONS policy; /* policy value passed to SHRestricted */ + LPCSTR appstr; /* application str such as "Explorer" */ + LPCSTR keystr; /* name of the actual registry key / policy */ + DWORD cache; /* cached value or 0xffffffff for invalid */ +} POLICYDATA, *LPPOLICYDATA; + +/* registry strings */ +static const CHAR strRegistryPolicyA[] = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies"; +static const WCHAR strRegistryPolicyW[] = {'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', + '\\','P','o','l','i','c','i','e','s',0}; +static const CHAR strPolicyA[] = "Policy"; +static const WCHAR strPolicyW[] = {'P','o','l','i','c','y',0}; + +/* application strings */ + +static const char strExplorer[] = {"Explorer"}; +static const char strActiveDesk[] = {"ActiveDesktop"}; +static const char strWinOldApp[] = {"WinOldApp"}; +static const char strAddRemoveProgs[] = {"AddRemoveProgs"}; + +/* key strings */ + +static const char strNoFileURL[] = {"NoFileUrl"}; +static const char strNoFolderOptions[] = {"NoFolderOptions"}; +static const char strNoChangeStartMenu[] = {"NoChangeStartMenu"}; +static const char strNoWindowsUpdate[] = {"NoWindowsUpdate"}; +static const char strNoSetActiveDesktop[] = {"NoSetActiveDesktop"}; +static const char strNoForgetSoftwareUpdate[] = {"NoForgetSoftwareUpdate"}; +static const char strNoMSAppLogo[] = {"NoMSAppLogo5ChannelNotify"}; +static const char strForceCopyACLW[] = {"ForceCopyACLWithFile"}; +static const char strNoResolveTrk[] = {"NoResolveTrack"}; +static const char strNoResolveSearch[] = {"NoResolveSearch"}; +static const char strNoEditComponent[] = {"NoEditingComponents"}; +static const char strNoMovingBand[] = {"NoMovingBands"}; +static const char strNoCloseDragDrop[] = {"NoCloseDragDropBands"}; +static const char strNoCloseComponent[] = {"NoClosingComponents"}; +static const char strNoDelComponent[] = {"NoDeletingComponents"}; +static const char strNoAddComponent[] = {"NoAddingComponents"}; +static const char strNoComponent[] = {"NoComponents"}; +static const char strNoChangeWallpaper[] = {"NoChangingWallpaper"}; +static const char strNoHTMLWallpaper[] = {"NoHTMLWallpaper"}; +static const char strNoCustomWebView[] = {"NoCustomizeWebView"}; +static const char strClassicShell[] = {"ClassicShell"}; +static const char strClearRecentDocs[] = {"ClearRecentDocsOnExit"}; +static const char strNoFavoritesMenu[] = {"NoFavoritesMenu"}; +static const char strNoActiveDesktopChanges[] = {"NoActiveDesktopChanges"}; +static const char strNoActiveDesktop[] = {"NoActiveDesktop"}; +static const char strNoRecentDocMenu[] = {"NoRecentDocsMenu"}; +static const char strNoRecentDocHistory[] = {"NoRecentDocsHistory"}; +static const char strNoInetIcon[] = {"NoInternetIcon"}; +static const char strNoSettingsWizard[] = {"NoSettingsWizards"}; +static const char strNoLogoff[] = {"NoLogoff"}; +static const char strNoNetConDis[] = {"NoNetConnectDisconnect"}; +static const char strNoViewContextMenu[] = {"NoViewContextMenu"}; +static const char strNoTrayContextMenu[] = {"NoTrayContextMenu"}; +static const char strNoWebMenu[] = {"NoWebMenu"}; +static const char strLnkResolveIgnoreLnkInfo[] = {"LinkResolveIgnoreLinkInfo"}; +static const char strNoCommonGroups[] = {"NoCommonGroups"}; +static const char strEnforceShlExtSecurity[] = {"EnforceShellExtensionSecurity"}; +static const char strNoRealMode[] = {"NoRealMode"}; +static const char strMyDocsOnNet[] = {"MyDocsOnNet"}; +static const char strNoStartMenuSubfolder[] = {"NoStartMenuSubFolders"}; +static const char strNoAddPrinters[] = {"NoAddPrinter"}; +static const char strNoDeletePrinters[] = {"NoDeletePrinter"}; +static const char strNoPrintTab[] = {"NoPrinterTabs"}; +static const char strRestrictRun[] = {"RestrictRun"}; +static const char strNoStartBanner[] = {"NoStartBanner"}; +static const char strNoNetworkNeighborhood[] = {"NoNetHood"}; +static const char strNoDriveTypeAtRun[] = {"NoDriveTypeAutoRun"}; +static const char strNoDrivesAutoRun[] = {"NoDriveAutoRun"}; +static const char strSeparateProcess[] = {"SeparateProcess"}; +static const char strNoDrives[] = {"NoDrives"}; +static const char strNoFind[] = {"NoFind"}; +static const char strNoDesktop[] = {"NoDesktop"}; +static const char strNoSetTaskBar[] = {"NoSetTaskbar"}; +static const char strNoSetFld[] = {"NoSetFolders"}; +static const char strNoFileMenu[] = {"NoFileMenu"}; +static const char strNoSaveSetting[] = {"NoSaveSettings"}; +static const char strNoClose[] = {"NoClose"}; +static const char strNoRun[] = {"NoRun"}; + +/* policy data array */ +static POLICYDATA sh32_policy_table[] = +{ + { + REST_NORUN, + strExplorer, + strNoRun, + SHELL_NO_POLICY + }, + { + REST_NOCLOSE, + strExplorer, + strNoClose, + SHELL_NO_POLICY + }, + { + REST_NOSAVESET, + strExplorer, + strNoSaveSetting, + SHELL_NO_POLICY + }, + { + REST_NOFILEMENU, + strExplorer, + strNoFileMenu, + SHELL_NO_POLICY + }, + { + REST_NOSETFOLDERS, + strExplorer, + strNoSetFld, + SHELL_NO_POLICY + }, + { + REST_NOSETTASKBAR, + strExplorer, + strNoSetTaskBar, + SHELL_NO_POLICY + }, + { + REST_NODESKTOP, + strExplorer, + strNoDesktop, + SHELL_NO_POLICY + }, + { + REST_NOFIND, + strExplorer, + strNoFind, + SHELL_NO_POLICY + }, + { + REST_NODRIVES, + strExplorer, + strNoDrives, + SHELL_NO_POLICY + }, + { + REST_NODRIVEAUTORUN, + strExplorer, + strNoDrivesAutoRun, + SHELL_NO_POLICY + }, + { + REST_NODRIVETYPEAUTORUN, + strExplorer, + strNoDriveTypeAtRun, + SHELL_NO_POLICY + }, + { + REST_NONETHOOD, + strExplorer, + strNoNetworkNeighborhood, + SHELL_NO_POLICY + }, + { + REST_STARTBANNER, + strExplorer, + strNoStartBanner, + SHELL_NO_POLICY + }, + { + REST_RESTRICTRUN, + strExplorer, + strRestrictRun, + SHELL_NO_POLICY + }, + { + REST_NOPRINTERTABS, + strExplorer, + strNoPrintTab, + SHELL_NO_POLICY + }, + { + REST_NOPRINTERDELETE, + strExplorer, + strNoDeletePrinters, + SHELL_NO_POLICY + }, + { + REST_NOPRINTERADD, + strExplorer, + strNoAddPrinters, + SHELL_NO_POLICY + }, + { + REST_NOSTARTMENUSUBFOLDERS, + strExplorer, + strNoStartMenuSubfolder, + SHELL_NO_POLICY + }, + { + REST_MYDOCSONNET, + strExplorer, + strMyDocsOnNet, + SHELL_NO_POLICY + }, + { + REST_NOEXITTODOS, + strWinOldApp, + strNoRealMode, + SHELL_NO_POLICY + }, + { + REST_ENFORCESHELLEXTSECURITY, + strExplorer, + strEnforceShlExtSecurity, + SHELL_NO_POLICY + }, + { + REST_LINKRESOLVEIGNORELINKINFO, + strExplorer, + strLnkResolveIgnoreLnkInfo, + SHELL_NO_POLICY + }, + { + REST_NOCOMMONGROUPS, + strExplorer, + strNoCommonGroups, + SHELL_NO_POLICY + }, + { + REST_SEPARATEDESKTOPPROCESS, + strExplorer, + strSeparateProcess, + SHELL_NO_POLICY + }, + { + REST_NOWEB, + strExplorer, + strNoWebMenu, + SHELL_NO_POLICY + }, + { + REST_NOTRAYCONTEXTMENU, + strExplorer, + strNoTrayContextMenu, + SHELL_NO_POLICY + }, + { + REST_NOVIEWCONTEXTMENU, + strExplorer, + strNoViewContextMenu, + SHELL_NO_POLICY + }, + { + REST_NONETCONNECTDISCONNECT, + strExplorer, + strNoNetConDis, + SHELL_NO_POLICY + }, + { + REST_STARTMENULOGOFF, + strExplorer, + strNoLogoff, + SHELL_NO_POLICY + }, + { + REST_NOSETTINGSASSIST, + strExplorer, + strNoSettingsWizard, + SHELL_NO_POLICY + }, + { + REST_NOINTERNETICON, + strExplorer, + strNoInetIcon, + SHELL_NO_POLICY + }, + { + REST_NORECENTDOCSHISTORY, + strExplorer, + strNoRecentDocHistory, + SHELL_NO_POLICY + }, + { + REST_NORECENTDOCSMENU, + strExplorer, + strNoRecentDocMenu, + SHELL_NO_POLICY + }, + { + REST_NOACTIVEDESKTOP, + strExplorer, + strNoActiveDesktop, + SHELL_NO_POLICY + }, + { + REST_NOACTIVEDESKTOPCHANGES, + strExplorer, + strNoActiveDesktopChanges, + SHELL_NO_POLICY + }, + { + REST_NOFAVORITESMENU, + strExplorer, + strNoFavoritesMenu, + SHELL_NO_POLICY + }, + { + REST_CLEARRECENTDOCSONEXIT, + strExplorer, + strClearRecentDocs, + SHELL_NO_POLICY + }, + { + REST_CLASSICSHELL, + strExplorer, + strClassicShell, + SHELL_NO_POLICY + }, + { + REST_NOCUSTOMIZEWEBVIEW, + strExplorer, + strNoCustomWebView, + SHELL_NO_POLICY + }, + { + REST_NOHTMLWALLPAPER, + strActiveDesk, + strNoHTMLWallpaper, + SHELL_NO_POLICY + }, + { + REST_NOCHANGINGWALLPAPER, + strActiveDesk, + strNoChangeWallpaper, + SHELL_NO_POLICY + }, + { + REST_NODESKCOMP, + strActiveDesk, + strNoComponent, + SHELL_NO_POLICY + }, + { + REST_NOADDDESKCOMP, + strActiveDesk, + strNoAddComponent, + SHELL_NO_POLICY + }, + { + REST_NODELDESKCOMP, + strActiveDesk, + strNoDelComponent, + SHELL_NO_POLICY + }, + { + REST_NOCLOSEDESKCOMP, + strActiveDesk, + strNoCloseComponent, + SHELL_NO_POLICY + }, + { + REST_NOCLOSE_DRAGDROPBAND, + strActiveDesk, + strNoCloseDragDrop, + SHELL_NO_POLICY + }, + { + REST_NOMOVINGBAND, + strActiveDesk, + strNoMovingBand, + SHELL_NO_POLICY + }, + { + REST_NOEDITDESKCOMP, + strActiveDesk, + strNoEditComponent, + SHELL_NO_POLICY + }, + { + REST_NORESOLVESEARCH, + strExplorer, + strNoResolveSearch, + SHELL_NO_POLICY + }, + { + REST_NORESOLVETRACK, + strExplorer, + strNoResolveTrk, + SHELL_NO_POLICY + }, + { + REST_FORCECOPYACLWITHFILE, + strExplorer, + strForceCopyACLW, + SHELL_NO_POLICY + }, +#if (NTDDI_VERSION < NTDDI_LONGHORN) + { + REST_NOLOGO3CHANNELNOTIFY, + strExplorer, + strNoMSAppLogo, + SHELL_NO_POLICY + }, +#endif + { + REST_NOFORGETSOFTWAREUPDATE, + strExplorer, + strNoForgetSoftwareUpdate, + SHELL_NO_POLICY + }, + { + REST_NOSETACTIVEDESKTOP, + strExplorer, + strNoSetActiveDesktop, + SHELL_NO_POLICY + }, + { + REST_NOUPDATEWINDOWS, + strExplorer, + strNoWindowsUpdate, + SHELL_NO_POLICY + }, + { + REST_NOCHANGESTARMENU, + strExplorer, + strNoChangeStartMenu, + SHELL_NO_POLICY + }, + { + REST_NOFOLDEROPTIONS, + strExplorer, + strNoFolderOptions, + SHELL_NO_POLICY + }, + { + REST_HASFINDCOMPUTERS, + strExplorer, + "FindComputers", + SHELL_NO_POLICY + }, + { + REST_INTELLIMENUS, + strExplorer, + "IntelliMenus", + SHELL_NO_POLICY + }, + { + REST_RUNDLGMEMCHECKBOX, + strExplorer, + "MemCheckBoxInRunDlg", + SHELL_NO_POLICY + }, + { + REST_ARP_ShowPostSetup, + strAddRemoveProgs, + "ShowPostSetup", + SHELL_NO_POLICY + }, + { + REST_NOCSC, + strExplorer, + "NoSyncAll", + SHELL_NO_POLICY + }, + { + REST_NOCONTROLPANEL, + strExplorer, + "NoControlPanel", + SHELL_NO_POLICY + }, + { + REST_ENUMWORKGROUP, + strExplorer, + "EnumWorkgroup", + SHELL_NO_POLICY + }, + { + REST_ARP_NOARP, + strAddRemoveProgs, + "NoAddRemovePrograms", + SHELL_NO_POLICY + }, + { + REST_ARP_NOREMOVEPAGE, + strAddRemoveProgs, + "NoRemovePage", + SHELL_NO_POLICY + }, + { + REST_ARP_NOADDPAGE, + strAddRemoveProgs, + "NoAddPage", + SHELL_NO_POLICY + }, + { + REST_ARP_NOWINSETUPPAGE, + strAddRemoveProgs, + "NoWindowsSetupPage", + SHELL_NO_POLICY + }, + { + REST_GREYMSIADS, + strExplorer, + "", + SHELL_NO_POLICY + }, + { + REST_NOCHANGEMAPPEDDRIVELABEL, + strExplorer, + "NoChangeMappedDriveLabel", + SHELL_NO_POLICY + }, + { + REST_NOCHANGEMAPPEDDRIVECOMMENT, + strExplorer, + "NoChangeMappedDriveComment", + SHELL_NO_POLICY + }, + { + REST_MaxRecentDocs, + strExplorer, + "MaxRecentDocs", + SHELL_NO_POLICY + }, + { + REST_NONETWORKCONNECTIONS, + strExplorer, + "NoNetworkConnections", + SHELL_NO_POLICY + }, + { + REST_FORCESTARTMENULOGOFF, + strExplorer, + "ForceStartMenuLogoff", + SHELL_NO_POLICY + }, + { + REST_NOWEBVIEW, + strExplorer, + "NoWebView", + SHELL_NO_POLICY + }, + { + REST_NOCUSTOMIZETHISFOLDER, + strExplorer, + "NoCustomizeThisFolder", + SHELL_NO_POLICY + }, + { + REST_NOENCRYPTION, + strExplorer, + "NoEncryption", + SHELL_NO_POLICY + }, + { + REST_ALLOWFRENCHENCRYPTION, + strExplorer, + "AllowFrenchEncryption", + SHELL_NO_POLICY + }, + { + REST_DONTSHOWSUPERHIDDEN, + strExplorer, + "DontShowSuperHidden", + SHELL_NO_POLICY + }, + { + REST_NOSHELLSEARCHBUTTON, + strExplorer, + "NoShellSearchButton", + SHELL_NO_POLICY + }, + { + REST_NOHARDWARETAB, + strExplorer, + "NoHardwareTab", + SHELL_NO_POLICY + }, + { + REST_NORUNASINSTALLPROMPT, + strExplorer, + "NoRunasInstallPrompt", + SHELL_NO_POLICY + }, + { + REST_PROMPTRUNASINSTALLNETPATH, + strExplorer, + "PromptRunasInstallNetPath", + SHELL_NO_POLICY + }, + { + REST_NOMANAGEMYCOMPUTERVERB, + strExplorer, + "NoManageMyComputerVerb", + SHELL_NO_POLICY + }, + { + REST_NORECENTDOCSNETHOOD, + strExplorer, + "NoRecentDocsNetHood", + SHELL_NO_POLICY + }, + { + REST_DISALLOWRUN, + strExplorer, + "DisallowRun", + SHELL_NO_POLICY + }, + { + REST_NOWELCOMESCREEN, + strExplorer, + "NoWelcomeScreen", + SHELL_NO_POLICY + }, + { + REST_RESTRICTCPL, + strExplorer, + "RestrictCpl", + SHELL_NO_POLICY + }, + { + REST_DISALLOWCPL, + strExplorer, + "DisallowCpl", + SHELL_NO_POLICY + }, + { + REST_NOSMBALLOONTIP, + strExplorer, + "NoSMBalloonTip", + SHELL_NO_POLICY + }, + { + REST_NOSMHELP, + strExplorer, + "NoSMHelp", + SHELL_NO_POLICY + }, + { + REST_NOWINKEYS, + strExplorer, + "NoWinKeys", + SHELL_NO_POLICY + }, + { + REST_NOENCRYPTONMOVE, + strExplorer, + "NoEncryptOnMove", + SHELL_NO_POLICY + }, + { + REST_NOLOCALMACHINERUN, + strExplorer, + "DisableLocalMachineRun", + SHELL_NO_POLICY + }, + { + REST_NOCURRENTUSERRUN, + strExplorer, + "DisableCurrentUserRun", + SHELL_NO_POLICY + }, + { + REST_NOLOCALMACHINERUNONCE, + strExplorer, + "DisableLocalMachineRunOnce", + SHELL_NO_POLICY + }, + { + REST_NOCURRENTUSERRUNONCE, + strExplorer, + "DisableCurrentUserRunOnce", + SHELL_NO_POLICY + }, + { + REST_FORCEACTIVEDESKTOPON, + strExplorer, + "ForceActiveDesktopOn", + SHELL_NO_POLICY + }, + { + REST_NOCOMPUTERSNEARME, + strExplorer, + "NoComputersNearMe", + SHELL_NO_POLICY + }, + { + REST_NOVIEWONDRIVE, + strExplorer, + "NoViewOnDrive", + SHELL_NO_POLICY + }, + { + REST_NONETCRAWL, + strExplorer, + "NoNetCrawl", + SHELL_NO_POLICY + }, + { + REST_NOSHAREDDOCUMENTS, + strExplorer, + "NoSharedDocs", + SHELL_NO_POLICY + }, + { + REST_NOSMMYDOCS, + strExplorer, + "NoSMMyDocs", + SHELL_NO_POLICY + }, +/* 0x4000050 - 0x4000060 */ + { + REST_NONLEGACYSHELLMODE, + strExplorer, + "NoneLegacyShellMode", + SHELL_NO_POLICY + }, + { + REST_STARTRUNNOHOMEPATH, + strExplorer, + "StartRunNoHOMEPATH", + SHELL_NO_POLICY + }, +/* 0x4000061 - 0x4000086 */ + { + REST_NODISCONNECT, + strExplorer, + "NoDisconnect", + SHELL_NO_POLICY + }, + { + REST_NOSECURITY, + strExplorer, + "NoNTSecurity", + SHELL_NO_POLICY + }, + { + REST_NOFILEASSOCIATE, + strExplorer, + "NoFileAssociate", + SHELL_NO_POLICY + }, + { + (RESTRICTIONS)0x50000024, + strExplorer, + strNoFileURL, + SHELL_NO_POLICY + }, + { + (RESTRICTIONS)0, + 0, + 0, + SHELL_NO_POLICY + } +}; + +/************************************************************************* + * SHRestricted [SHELL32.100] + * + * Get the value associated with a policy Id. + * + * PARAMS + * pol [I] Policy Id + * + * RETURNS + * The queried value for the policy. + * + * NOTES + * Exported by ordinal. + * This function caches the retrieved values to prevent unnecessary registry access, + * if SHInitRestricted() was previously called. + * + * REFERENCES + * a: MS System Policy Editor. + * b: 98Lite 2.0 (which uses many of these policy keys) http://www.98lite.net/ + * c: 'The Windows 95 Registry', by John Woram, 1996 MIS: Press + */ +DWORD WINAPI SHRestricted (RESTRICTIONS policy) +{ + char regstr[256]; + HKEY xhkey; + DWORD retval, datsize = 4; + LPPOLICYDATA p; + + TRACE("(%08x)\n", policy); + + /* scan to see if we know this policy ID */ + for (p = sh32_policy_table; p->policy; p++) + { + if (policy == p->policy) + { + break; + } + } + + if (p->policy == 0) + { + /* we don't know this policy, return 0 */ + TRACE("unknown policy: (%08x)\n", policy); + return 0; + } + + /* we have a known policy */ + + /* first check if this policy has been cached, return it if so */ + if (p->cache != SHELL_NO_POLICY) + { + return p->cache; + } + + lstrcpyA(regstr, strRegistryPolicyA); + lstrcatA(regstr, p->appstr); + + /* return 0 and don't set the cache if any registry errors occur */ + retval = 0; + if (RegOpenKeyA(HKEY_CURRENT_USER, regstr, &xhkey) == ERROR_SUCCESS) + { + if (RegQueryValueExA(xhkey, p->keystr, NULL, NULL, (LPBYTE)&retval, &datsize) == ERROR_SUCCESS) + { + p->cache = retval; + } + RegCloseKey(xhkey); + } + return retval; +} + +/************************************************************************* + * SHInitRestricted [SHELL32.244] + * + * Initialise the policy cache to speed up calls to SHRestricted(). + * + * PARAMS + * unused [I] Reserved. + * inpRegKey [I] Registry key to scan. + * + * RETURNS + * Success: -1. The policy cache is initialised. + * Failure: 0, if inpRegKey is any value other than NULL, "Policy", or + * "Software\Microsoft\Windows\CurrentVersion\Policies". + * + * NOTES + * Exported by ordinal. Introduced in Win98. + */ +BOOL WINAPI SHInitRestricted(LPCVOID unused, LPCVOID inpRegKey) +{ + TRACE("(%p, %p)\n", unused, inpRegKey); + + /* first check - if input is non-NULL and points to the secret + key string, then pass. Otherwise return 0. + */ + if (inpRegKey != NULL) + { + if (SHELL_OsIsUnicode()) + { + if (lstrcmpiW((LPCWSTR)inpRegKey, strRegistryPolicyW) && + lstrcmpiW((LPCWSTR)inpRegKey, strPolicyW)) + /* doesn't match, fail */ + return 0; + } + else + { + if (lstrcmpiA((LPCSTR)inpRegKey, strRegistryPolicyA) && + lstrcmpiA((LPCSTR)inpRegKey, strPolicyA)) + /* doesn't match, fail */ + return 0; + } + } + + return TRUE; +} diff --git a/reactos/dll/win32/shell32/shresdef.h b/reactos/dll/win32/shell32/shresdef.h index 507d26b11ee..67459e7869c 100644 --- a/reactos/dll/win32/shell32/shresdef.h +++ b/reactos/dll/win32/shell32/shresdef.h @@ -155,31 +155,31 @@ #define IDS_FIND_VERB 304 #define IDS_PRINT_VERB 305 -#define IDS_FILE_FOLDER 307 -#define IDS_CREATELINK 308 -#define IDS_INSTALLNEWFONT 309 -#define IDS_SHV_COLUMN_FONTTYPE 310 -#define IDS_SHV_COLUMN12 311 -#define IDS_SHV_COLUMN13 312 -#define IDS_SHV_COLUMN_WORKGROUP 313 -#define IDS_SHV_NETWORKLOCATION 314 -#define IDS_COPY 315 -#define IDS_DELETE 316 -#define IDS_PROPERTIES 317 -#define IDS_SHV_COLUMN_DOCUMENTS 318 -#define IDS_SHV_COLUMN_STATUS 319 -#define IDS_SHV_COLUMN_COMMENTS 320 -#define IDS_SHV_COLUMN_LOCATION 321 -#define IDS_SHV_COLUMN_MODEL 322 -#define IDS_CUT 323 -#define IDS_RESTORE 324 -#define IDS_DEFAULT_CLUSTER_SIZE 325 -#define IDS_ADMINISTRATIVETOOLS 326 -#define IDS_FORMATDRIVE 327 -#define IDS_RENAME 328 -#define IDS_INSERT 329 -#define IDS_DESCRIPTION 330 -#define IDS_COPY_OF 331 +#define IDS_FILE_FOLDER 308 +#define IDS_CREATELINK 309 +#define IDS_INSTALLNEWFONT 310 +#define IDS_SHV_COLUMN_FONTTYPE 311 +#define IDS_SHV_COLUMN12 312 +#define IDS_SHV_COLUMN13 313 +#define IDS_SHV_COLUMN_WORKGROUP 314 +#define IDS_SHV_NETWORKLOCATION 315 +#define IDS_COPY 316 +#define IDS_DELETE 317 +#define IDS_PROPERTIES 318 +#define IDS_SHV_COLUMN_DOCUMENTS 319 +#define IDS_SHV_COLUMN_STATUS 320 +#define IDS_SHV_COLUMN_COMMENTS 321 +#define IDS_SHV_COLUMN_LOCATION 322 +#define IDS_SHV_COLUMN_MODEL 323 +#define IDS_CUT 324 +#define IDS_RESTORE 325 +#define IDS_DEFAULT_CLUSTER_SIZE 326 +#define IDS_ADMINISTRATIVETOOLS 327 +#define IDS_FORMATDRIVE 328 +#define IDS_RENAME 329 +#define IDS_INSERT 330 +#define IDS_DESCRIPTION 331 +#define IDS_COPY_OF 332 /* Note: this string is referenced from the registry */ #define IDS_RECYCLEBIN_FOLDER_NAME 8964 @@ -451,4 +451,24 @@ FIXME: Need to add them, but for now just let them use the same: searching.avi #define FCIDM_TB_REPORTVIEW 0xA004 #define FCIDM_TB_DESKTOP 0xA005 /* FIXME */ +/* .rgs files */ +#define IDR_ADMINFOLDERSHORTCUT 128 +#define IDR_AUTOCOMPLETE 129 +#define IDR_CONTROLPANEL 130 +#define IDR_DRAGDROPHELPER 131 +#define IDR_FOLDEROPTIONS 132 +#define IDR_FOLDERSHORTCUT 133 +#define IDR_FONTSFOLDERSHORTCUT 134 +#define IDR_MENUBANDSITE 135 +#define IDR_MYCOMPUTER 136 +#define IDR_MYDOCUMENTS 137 +#define IDR_NETWORKPLACES 138 +#define IDR_NEWMENU 139 +#define IDR_PRINTERS 140 +#define IDR_RECYCLEBIN 141 +#define IDR_SHELLDESKTOP 142 +#define IDR_SHELLFSFOLDER 143 +#define IDR_SHELLLINK 144 +#define IDR_STARTMENU 145 + #endif diff --git a/reactos/dll/win32/shell32/shv_def_cmenu.cpp b/reactos/dll/win32/shell32/shv_def_cmenu.cpp new file mode 100644 index 00000000000..b50c1c1cb2f --- /dev/null +++ b/reactos/dll/win32/shell32/shv_def_cmenu.cpp @@ -0,0 +1,1739 @@ +/* + * PROJECT: shell32 + * LICENSE: GPL - See COPYING in the top level directory + * FILE: dll/win32/shell32/shv_item_new.c + * PURPOSE: provides default context menu implementation + * PROGRAMMERS: Johannes Anderwald (janderwald@reactos.org) + */ + +/* +TODO: +1. In DoStaticShellExtensions, check for "Explore" and "Open" verbs, and for BrowserFlags or + ExplorerFlags under those entries. These flags indicate if we should browse to the new item + instead of attempting to open it. +2. The code in NotifyShellViewWindow to deliver commands to the view is broken. It is an excellent + example of the wrong way to do it. +*/ + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(dmenu); + +typedef struct _DynamicShellEntry_ +{ + UINT iIdCmdFirst; + UINT NumIds; + CLSID ClassID; + IContextMenu * CMenu; + struct _DynamicShellEntry_ * Next; +}DynamicShellEntry, *PDynamicShellEntry; + +typedef struct _StaticShellEntry_ +{ + LPWSTR szVerb; + LPWSTR szClass; + struct _StaticShellEntry_ * Next; +}StaticShellEntry, *PStaticShellEntry; + +WCHAR *build_paths_list(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls); + +class IDefaultContextMenuImpl : + public CComObjectRootEx, + public IContextMenu2 +{ +private: + DEFCONTEXTMENU dcm; + IDataObject * pDataObj; + DWORD bGroupPolicyActive; + PDynamicShellEntry dhead; /* first dynamic shell extension entry */ + UINT iIdSHEFirst; /* first used id */ + UINT iIdSHELast; /* last used id */ + PStaticShellEntry shead; /* first static shell extension entry */ + UINT iIdSCMFirst; /* first static used id */ + UINT iIdSCMLast; /* last static used id */ +public: + IDefaultContextMenuImpl(); + ~IDefaultContextMenuImpl(); + HRESULT WINAPI Initialize(const DEFCONTEXTMENU *pdcm); + void SH_AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass); + void SH_AddStaticEntryForKey(HKEY hKey, const WCHAR *szClass); + void SH_AddStaticEntryForFileClass(const WCHAR *szExt); + BOOL IsShellExtensionAlreadyLoaded(const CLSID *szClass); + HRESULT SH_LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *szClass, BOOL bExternalInit); + UINT EnumerateDynamicContextHandlerForKey(HKEY hRootKey); + UINT InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast); + UINT BuildBackgroundContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags); + UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT indexMenu); + UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags); + HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi, BOOL bCopy); + HRESULT DoRename(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoProperties(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoFormat(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi); + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand,UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen); + + // IContextMenu2 + virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); + +BEGIN_COM_MAP(IDefaultContextMenuImpl) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2) +END_COM_MAP() +}; + +IDefaultContextMenuImpl::IDefaultContextMenuImpl() +{ + memset (&dcm, 0, sizeof(dcm)); + pDataObj = NULL; + bGroupPolicyActive = 0; + dhead = NULL; + iIdSHEFirst = 0; + iIdSHELast = 0; + shead = NULL; + iIdSCMFirst = 0; + iIdSCMLast = 0; +} + +IDefaultContextMenuImpl::~IDefaultContextMenuImpl() +{ + PDynamicShellEntry dEntry, dNext; + PStaticShellEntry sEntry, sNext; + + /* free dynamic shell extension entries */ + dEntry = dhead; + while (dEntry) + { + dNext = dEntry->Next; + dEntry->CMenu->Release(); + HeapFree(GetProcessHeap(), 0, dEntry); + dEntry = dNext; + } + /* free static shell extension entries */ + sEntry = shead; + while (sEntry) + { + sNext = sEntry->Next; + HeapFree(GetProcessHeap(), 0, sEntry->szClass); + HeapFree(GetProcessHeap(), 0, sEntry->szVerb); + HeapFree(GetProcessHeap(), 0, sEntry); + sEntry = sNext; + } +} + +HRESULT WINAPI IDefaultContextMenuImpl::Initialize(const DEFCONTEXTMENU *pdcm) +{ + IDataObject *newDataObj; + + TRACE("cidl %u\n", dcm.cidl); + if (SUCCEEDED(SHCreateDataObject(pdcm->pidlFolder, pdcm->cidl, pdcm->apidl, NULL, IID_IDataObject, (void**)&newDataObj))) + pDataObj = newDataObj; + CopyMemory(&dcm, pdcm, sizeof(DEFCONTEXTMENU)); + return S_OK; +} + +void +IDefaultContextMenuImpl::SH_AddStaticEntry(const WCHAR *szVerb, const WCHAR * szClass) +{ + PStaticShellEntry curEntry; + PStaticShellEntry lastEntry = NULL; + + curEntry = shead; + while(curEntry) + { + if (!wcsicmp(curEntry->szVerb, szVerb)) + { + /* entry already exists */ + return; + } + lastEntry = curEntry; + curEntry = curEntry->Next; + } + + TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb), debugstr_w(szClass)); + + curEntry = (StaticShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry)); + if (curEntry) + { + curEntry->Next = NULL; + curEntry->szVerb = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb)+1) * sizeof(WCHAR)); + if (curEntry->szVerb) + wcscpy(curEntry->szVerb, szVerb); + curEntry->szClass = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass)+1) * sizeof(WCHAR)); + if (curEntry->szClass) + wcscpy(curEntry->szClass, szClass); + } + + if (!wcsicmp(szVerb, L"open")) + { + /* open verb is always inserted in front */ + curEntry->Next = shead; + shead = curEntry; + return; + } + + + + if (lastEntry) + { + lastEntry->Next = curEntry; + } + else + { + shead = curEntry; + } +} + +void +IDefaultContextMenuImpl::SH_AddStaticEntryForKey(HKEY hKey, const WCHAR * szClass) +{ + LONG result; + DWORD dwIndex; + WCHAR szName[40]; + DWORD dwName; + + dwIndex = 0; + do + { + szName[0] = 0; + dwName = sizeof(szName) / sizeof(WCHAR); + result = RegEnumKeyExW(hKey, dwIndex, szName, &dwName, NULL, NULL, NULL, NULL); + szName[(sizeof(szName)/sizeof(WCHAR))-1] = 0; + if (result == ERROR_SUCCESS) + { + SH_AddStaticEntry(szName, szClass); + } + dwIndex++; + }while(result == ERROR_SUCCESS); +} + +void +IDefaultContextMenuImpl::SH_AddStaticEntryForFileClass(const WCHAR * szExt) +{ + WCHAR szBuffer[100]; + HKEY hKey; + LONG result; + DWORD dwBuffer; + UINT Length; + static WCHAR szShell[] = L"\\shell"; + static WCHAR szShellAssoc[] = L"SystemFileAssociations\\"; + + TRACE("SH_AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt)); + + Length = wcslen(szExt); + if (Length + (sizeof(szShell)/sizeof(WCHAR)) + 1 < sizeof(szBuffer)/sizeof(WCHAR)) + { + wcscpy(szBuffer, szExt); + wcscpy(&szBuffer[Length], szShell); + result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); + if (result == ERROR_SUCCESS) + { + szBuffer[Length] = 0; + SH_AddStaticEntryForKey(hKey, szExt); + RegCloseKey(hKey); + } + } + + dwBuffer = sizeof(szBuffer); + result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, (LPBYTE)szBuffer, &dwBuffer); + if (result == ERROR_SUCCESS) + { + Length = wcslen(szBuffer); + if (Length + (sizeof(szShell)/sizeof(WCHAR)) + 1 < sizeof(szBuffer)/sizeof(WCHAR)) + { + wcscpy(&szBuffer[Length], szShell); + TRACE("szBuffer %s\n", debugstr_w(szBuffer)); + + result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); + if (result == ERROR_SUCCESS) + { + szBuffer[Length] = 0; + SH_AddStaticEntryForKey(hKey, szBuffer); + RegCloseKey(hKey); + } + } + } + + wcscpy(szBuffer, szShellAssoc); + dwBuffer = sizeof(szBuffer) - sizeof(szShellAssoc) - sizeof(WCHAR); + result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, L"PerceivedType", RRF_RT_REG_SZ, NULL, (LPBYTE)&szBuffer[_countof(szShellAssoc) - 1], &dwBuffer); + if (result == ERROR_SUCCESS) + { + Length = wcslen(&szBuffer[_countof(szShellAssoc)]) + _countof(szShellAssoc); + wcscat(szBuffer, L"\\shell"); + TRACE("szBuffer %s\n", debugstr_w(szBuffer)); + + result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey); + if (result == ERROR_SUCCESS) + { + szBuffer[Length] = 0; + SH_AddStaticEntryForKey(hKey, szBuffer); + RegCloseKey(hKey); + } + } +} + +static +BOOL +HasClipboardData() +{ + BOOL ret = FALSE; + IDataObject * pda; + + if(SUCCEEDED(OleGetClipboard(&pda))) + { + STGMEDIUM medium; + FORMATETC formatetc; + + TRACE("pda=%p\n", pda); + + /* Set the FORMATETC structure*/ + InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL); + if(SUCCEEDED(pda->GetData(&formatetc,&medium))) + { + ret = TRUE; + ReleaseStgMedium(&medium); + } + + pda->Release(); + } + + return ret; +} + +VOID +DisablePasteOptions(HMENU hMenu) +{ + MENUITEMINFOW mii; + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_STATE; + mii.fState = MFS_DISABLED; + + TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERT, FALSE, &mii)); + TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERTLINK, FALSE, &mii)); +} + +BOOL +IDefaultContextMenuImpl::IsShellExtensionAlreadyLoaded(const CLSID * szClass) +{ + PDynamicShellEntry curEntry = dhead; + + while(curEntry) + { + if (!memcmp(&curEntry->ClassID, szClass, sizeof(CLSID))) + return TRUE; + curEntry = curEntry->Next; + } + return FALSE; +} + + +HRESULT +IDefaultContextMenuImpl::SH_LoadDynamicContextMenuHandler(HKEY hKey, const CLSID * szClass, BOOL bExternalInit) +{ + HRESULT hr; + IContextMenu * cmobj; + IShellExtInit *shext; + PDynamicShellEntry curEntry; + //WCHAR szTemp[100]; + LPOLESTR pstr; + + StringFromCLSID(*szClass, &pstr); + + TRACE("SH_LoadDynamicContextMenuHandler entered with This %p hKey %p szClass %s bExternalInit %u\n",this, hKey, wine_dbgstr_guid(szClass), bExternalInit); + //swprintf(szTemp, L"This %p hKey %p szClass %s bExternalInit %u", this, hKey, pstr, bExternalInit); + //MessageBoxW(NULL, szTemp, NULL, MB_OK); + + if (IsShellExtensionAlreadyLoaded(szClass)) + return S_OK; + + hr = SHCoCreateInstance(NULL, szClass, NULL, IID_IContextMenu, (void**)&cmobj); + if (hr != S_OK) + { + TRACE("SHCoCreateInstance failed %x\n", GetLastError()); + return hr; + } + + if (bExternalInit) + { + hr = cmobj->QueryInterface(IID_IShellExtInit, (void**)&shext); + if (hr != S_OK) + { + TRACE("Failed to query for interface IID_IShellExtInit\n"); + cmobj->Release(); + return FALSE; + } + hr = shext->Initialize(NULL, pDataObj, hKey); + shext->Release(); + if (hr != S_OK) + { + TRACE("Failed to initialize shell extension error %x\n", hr); + cmobj->Release(); + return hr; + } + } + + curEntry = (DynamicShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry)); + if(!curEntry) + { + cmobj->Release(); + return E_OUTOFMEMORY; + } + + curEntry->iIdCmdFirst = 0; + curEntry->Next = NULL; + curEntry->NumIds = 0; + curEntry->CMenu = cmobj; + memcpy(&curEntry->ClassID, szClass, sizeof(CLSID)); + + if (dhead) + { + PDynamicShellEntry pEntry = dhead; + + while(pEntry->Next) + { + pEntry = pEntry->Next; + } + + pEntry->Next = curEntry; + } + else + { + dhead = curEntry; + } + + return hr; +} + +UINT +IDefaultContextMenuImpl::EnumerateDynamicContextHandlerForKey(HKEY hRootKey) +{ + WCHAR szKey[MAX_PATH] = {0}; + WCHAR szName[MAX_PATH] = {0}; + DWORD dwIndex, dwName; + LONG res; + HRESULT hResult; + UINT index; + CLSID clsid; + HKEY hKey; + + static const WCHAR szShellEx[] = { '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 }; + + if (RegOpenKeyExW(hRootKey, szShellEx, 0, KEY_READ, &hKey) != ERROR_SUCCESS) + { + TRACE("RegOpenKeyExW failed for key %s\n", debugstr_w(szKey)); + return 0; + } + + dwIndex = 0; + index = 0; + do + { + dwName = MAX_PATH; + res = RegEnumKeyExW(hKey, dwIndex, szName, &dwName, NULL, NULL, NULL, NULL); + if (res == ERROR_SUCCESS) + { + hResult = CLSIDFromString(szName, &clsid); + if (hResult != S_OK) + { + dwName = MAX_PATH; + if (RegGetValueW(hKey, szName, NULL, RRF_RT_REG_SZ, NULL, szKey, &dwName) == ERROR_SUCCESS) + { + hResult = CLSIDFromString(szKey, &clsid); + } + } + if (SUCCEEDED(hResult)) + { + if (bGroupPolicyActive) + { + if (RegGetValueW(HKEY_LOCAL_MACHINE, + L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", + szKey, + RRF_RT_REG_SZ, + NULL, + NULL, + &dwName) == ERROR_SUCCESS) + { + SH_LoadDynamicContextMenuHandler(hKey, &clsid, TRUE); + } + } + else + { + SH_LoadDynamicContextMenuHandler(hKey, &clsid, TRUE); + } + } + } + dwIndex++; + }while(res == ERROR_SUCCESS); + + RegCloseKey(hKey); + return index; +} + +UINT +IDefaultContextMenuImpl::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast) +{ + PDynamicShellEntry curEntry; + HRESULT hResult; + + if (!dhead) + { + iIdSHEFirst = 0; + iIdSHELast = 0; + return indexMenu; + } + + curEntry = dhead; + idCmdFirst = 0x5000; + idCmdLast = 0x6000; + iIdSHEFirst = idCmdFirst; + do + { + hResult = curEntry->CMenu->QueryContextMenu(hMenu, indexMenu++, idCmdFirst, idCmdLast, CMF_NORMAL); + if (SUCCEEDED(hResult)) + { + curEntry->iIdCmdFirst = idCmdFirst; + curEntry->NumIds = LOWORD(hResult); + indexMenu += curEntry->NumIds; + idCmdFirst += curEntry->NumIds + 0x10; + } + TRACE("curEntry %p hresult %x contextmenu %p cmdfirst %x num ids %x\n", curEntry, hResult, curEntry->CMenu, curEntry->iIdCmdFirst, curEntry->NumIds); + curEntry = curEntry->Next; + }while(curEntry); + + iIdSHELast = idCmdFirst; + TRACE("SH_LoadContextMenuHandlers first %x last %x\n", iIdSHEFirst, iIdSHELast); + return indexMenu; +} + +UINT +IDefaultContextMenuImpl::BuildBackgroundContextMenu( + HMENU hMenu, + UINT iIdCmdFirst, + UINT iIdCmdLast, + UINT uFlags) +{ + MENUITEMINFOW mii; + WCHAR szBuffer[MAX_PATH]; + UINT indexMenu = 0; + HMENU hSubMenu; + HKEY hKey; + + ZeroMemory(&mii, sizeof(mii)); + + TRACE("BuildBackgroundContextMenu entered\n"); + + if (!_ILIsDesktop(dcm.pidlFolder)) + { + /* view option is only available in browsing mode */ + hSubMenu = LoadMenuA(shell32_hInstance, "MENU_001"); + if (hSubMenu) + { + szBuffer[0] = 0; + LoadStringW(shell32_hInstance, FCIDM_SHVIEW_VIEW, szBuffer, MAX_PATH); + szBuffer[MAX_PATH-1] = 0; + + TRACE("szBuffer %s\n", debugstr_w(szBuffer)); + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID; + mii.fType = MFT_STRING; + mii.wID = iIdCmdFirst++; + mii.dwTypeData = szBuffer; + mii.cch = wcslen( mii.dwTypeData ); + mii.fState = MFS_ENABLED; + mii.hSubMenu = hSubMenu; + InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii); + DestroyMenu(hSubMenu); + } + } + hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_002"); + if (hSubMenu) + { + /* merge general background context menu in */ + iIdCmdFirst = Shell_MergeMenus(hMenu, GetSubMenu(hSubMenu, 0), indexMenu, 0, 0xFFFF, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS) + 1; + DestroyMenu(hSubMenu); + } + + if (!HasClipboardData()) + { + TRACE("disabling paste options\n"); + DisablePasteOptions(hMenu); + } + /* load extensions from HKCR\* key */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, + L"*", + 0, + KEY_READ, + &hKey) == ERROR_SUCCESS) + { + EnumerateDynamicContextHandlerForKey(hKey); + RegCloseKey(hKey); + } + + /* load create new shell extension */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, + L"CLSID\\{D969A300-E7FF-11d0-A93B-00A0C90F2719}", + 0, + KEY_READ, + &hKey) == ERROR_SUCCESS) + { + SH_LoadDynamicContextMenuHandler(hKey, &CLSID_NewMenu, TRUE); + RegCloseKey(hKey); + } + + if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu, GetMenuItemCount(hMenu)-1, iIdCmdFirst, iIdCmdLast)) + { + /* seperate dynamic context menu items */ + _InsertMenuItemW(hMenu, GetMenuItemCount(hMenu)-1, TRUE, -1, MFT_SEPARATOR, NULL, MFS_ENABLED); + } + + return iIdCmdLast; +} + +UINT +IDefaultContextMenuImpl::AddStaticContextMenusToMenu( + HMENU hMenu, + UINT indexMenu) +{ + MENUITEMINFOW mii; + UINT idResource; + PStaticShellEntry curEntry; + WCHAR szVerb[40]; + WCHAR szTemp[50]; + DWORD dwSize; + UINT fState; + UINT Length; + + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; + mii.fType = MFT_STRING; + mii.fState = MFS_ENABLED; + mii.wID = 0x4000; + mii.dwTypeData = NULL; + iIdSCMFirst = mii.wID; + + curEntry = shead; + + while(curEntry) + { + fState = MFS_ENABLED; + if (!wcsicmp(curEntry->szVerb, L"open")) + { + fState |= MFS_DEFAULT; + idResource = IDS_OPEN_VERB; + } + else if (!wcsicmp(curEntry->szVerb, L"explore")) + idResource = IDS_EXPLORE_VERB; + else if (!wcsicmp(curEntry->szVerb, L"runas")) + idResource = IDS_RUNAS_VERB; + else if (!wcsicmp(curEntry->szVerb, L"edit")) + idResource = IDS_EDIT_VERB; + else if (!wcsicmp(curEntry->szVerb, L"find")) + idResource = IDS_FIND_VERB; + else if (!wcsicmp(curEntry->szVerb, L"print")) + idResource = IDS_PRINT_VERB; + else if (!wcsicmp(curEntry->szVerb, L"printto")) + { + curEntry = curEntry->Next; + continue; + } + else + idResource = 0; + + if (idResource > 0) + { + if (LoadStringW(shell32_hInstance, idResource, szVerb, sizeof(szVerb)/sizeof(WCHAR))) + { + /* use translated verb */ + szVerb[(sizeof(szVerb)/sizeof(WCHAR))-1] = L'\0'; + mii.dwTypeData = szVerb; + } + else + { + TRACE("Failed to load string, defaulting to NULL value for mii.dwTypeData\n"); + } + } + else + { + Length = wcslen(curEntry->szClass) + wcslen(curEntry->szVerb) + 8; + if (Length < sizeof(szTemp)/sizeof(WCHAR)) + { + wcscpy(szTemp, curEntry->szClass); + wcscat(szTemp, L"\\shell\\"); + wcscat(szTemp, curEntry->szVerb); + dwSize = sizeof(szVerb); + + if (RegGetValueW(HKEY_CLASSES_ROOT, szTemp, NULL, RRF_RT_REG_SZ, NULL, szVerb, &dwSize) == ERROR_SUCCESS) + { + /* use description for the menu entry */ + mii.dwTypeData = szVerb; + } + else + { + /* use verb for the menu entry */ + mii.dwTypeData = curEntry->szVerb; + } + } + + } + + mii.cch = wcslen(mii.dwTypeData); + mii.fState = fState; + InsertMenuItemW(hMenu, indexMenu++, TRUE, &mii); + + mii.wID++; + curEntry = curEntry->Next; + } + iIdSCMLast = mii.wID - 1; + return indexMenu; +} + +void WINAPI _InsertMenuItemW ( + HMENU hmenu, + UINT indexMenu, + BOOL fByPosition, + UINT wID, + UINT fType, + LPCWSTR dwTypeData, + UINT fState) +{ + MENUITEMINFOW mii; + WCHAR szText[100]; + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + if (fType == MFT_SEPARATOR) + { + mii.fMask = MIIM_ID | MIIM_TYPE; + } + else if (fType == MFT_STRING) + { + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; + if ((ULONG_PTR)HIWORD((ULONG_PTR)dwTypeData) == 0) + { + if (LoadStringW(shell32_hInstance, LOWORD((ULONG_PTR)dwTypeData), szText, sizeof(szText)/sizeof(WCHAR))) + { + szText[(sizeof(szText)/sizeof(WCHAR))-1] = 0; + mii.dwTypeData = szText; + } + else + { + TRACE("failed to load string %p\n", dwTypeData); + return; + } + } + else + { + mii.dwTypeData = (LPWSTR) dwTypeData; + } + mii.fState = fState; + } + + mii.wID = wID; + mii.fType = fType; + InsertMenuItemW( hmenu, indexMenu, fByPosition, &mii); +} + +UINT +IDefaultContextMenuImpl::BuildShellItemContextMenu( + HMENU hMenu, + UINT iIdCmdFirst, + UINT iIdCmdLast, + UINT uFlags) +{ + WCHAR szPath[MAX_PATH]; + WCHAR szTemp[40]; + HKEY hKey; + UINT indexMenu; + SFGAOF rfg; + HRESULT hr; + BOOL bAddSep = FALSE; + GUID * guid; + BOOL bClipboardData; + STRRET strFile; + LPWSTR pOffset; + DWORD dwSize; + + TRACE("BuildShellItemContextMenu entered\n"); + + if (dcm.psf->GetDisplayNameOf(dcm.apidl[0], SHGDN_FORPARSING, &strFile) == S_OK) + { + if (StrRetToBufW(&strFile, dcm.apidl[0], szPath, MAX_PATH) == S_OK) + { + pOffset = wcsrchr(szPath, L'.'); + if (pOffset) + { + /* enumerate dynamic/static for a given file class */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pOffset, 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + /* add static verbs */ + SH_AddStaticEntryForFileClass(pOffset); + /* load dynamic extensions from file extension key */ + EnumerateDynamicContextHandlerForKey(hKey); + RegCloseKey(hKey); + } + dwSize = sizeof(szTemp); + if (RegGetValueW(HKEY_CLASSES_ROOT, pOffset, NULL, RRF_RT_REG_SZ, NULL, szTemp, &dwSize) == ERROR_SUCCESS) + { + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, szTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + /* add static verbs from progid key */ + SH_AddStaticEntryForFileClass(szTemp); + /* load dynamic extensions from progid key */ + EnumerateDynamicContextHandlerForKey(hKey); + RegCloseKey(hKey); + } + } + } + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"*", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + /* load default extensions */ + EnumerateDynamicContextHandlerForKey(hKey); + RegCloseKey(hKey); + } + } + } + + guid = _ILGetGUIDPointer(dcm.apidl[0]); + if (guid) + { + LPOLESTR pwszCLSID; + WCHAR buffer[60]; + + wcscpy(buffer, L"CLSID\\"); + hr = StringFromCLSID(*guid, &pwszCLSID); + if (hr == S_OK) + { + wcscpy(&buffer[6], pwszCLSID); + TRACE("buffer %s\n", debugstr_w(buffer)); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + EnumerateDynamicContextHandlerForKey(hKey); + SH_AddStaticEntryForFileClass(buffer); + RegCloseKey(hKey); + } + CoTaskMemFree(pwszCLSID); + } + } + + + if (_ILIsDrive(dcm.apidl[0])) + { + SH_AddStaticEntryForFileClass(L"Drive"); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + EnumerateDynamicContextHandlerForKey(hKey); + RegCloseKey(hKey); + } + + } + + /* add static actions */ + rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER; + hr = dcm.psf->GetAttributesOf(dcm.cidl, dcm.apidl, &rfg); + if (!SUCCEEDED(hr)) + rfg = 0; + + if (rfg & SFGAO_FOLDER) + { + /* add the default verbs open / explore */ + SH_AddStaticEntryForFileClass(L"Folder"); + SH_AddStaticEntryForFileClass(L"Directory"); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + EnumerateDynamicContextHandlerForKey(hKey); + RegCloseKey(hKey); + } + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + EnumerateDynamicContextHandlerForKey(hKey); + RegCloseKey(hKey); + } + } + + + if (rfg & SFGAO_FILESYSTEM) + { + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + /* sendto service is registered here */ + EnumerateDynamicContextHandlerForKey(hKey); + RegCloseKey(hKey); + } + } + + /* add static context menu handlers */ + indexMenu = AddStaticContextMenusToMenu(hMenu, 0); + /* now process dynamic context menu handlers */ + indexMenu = InsertMenuItemsOfDynamicContextMenuExtension(hMenu, indexMenu, iIdCmdFirst, iIdCmdLast); + TRACE("indexMenu %d\n", indexMenu); + + if (_ILIsDrive(dcm.apidl[0])) + { + /* The 'Format' option must be always available, + * thus it is not registered as a static shell extension + */ + _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0x7ABC, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED); + bAddSep = TRUE; + } + + bClipboardData = (HasClipboardData() && (rfg & SFGAO_FILESYSTEM)); + if (rfg & (SFGAO_CANCOPY | SFGAO_CANMOVE) || bClipboardData) + { + _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); + if (rfg & SFGAO_CANMOVE) + _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_CUT, MFT_STRING, MAKEINTRESOURCEW(IDS_CUT), MFS_ENABLED); + if (rfg & SFGAO_CANCOPY) + _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_COPY, MFT_STRING, MAKEINTRESOURCEW(IDS_COPY), MFS_ENABLED); + if (bClipboardData) + _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_INSERT, MFT_STRING, MAKEINTRESOURCEW(IDS_INSERT), MFS_ENABLED); + + bAddSep = TRUE; + } + + + if (rfg & SFGAO_CANLINK) + { + bAddSep = FALSE; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED); + } + + + if (rfg & SFGAO_CANDELETE) + { + if (bAddSep) + { + bAddSep = FALSE; + _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); + } + _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_DELETE, MFT_STRING, MAKEINTRESOURCEW(IDS_DELETE), MFS_ENABLED); + } + + if (rfg & SFGAO_CANRENAME) + { + if (bAddSep) + { + _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); + } + _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_RENAME, MFT_STRING, MAKEINTRESOURCEW(IDS_RENAME), MFS_ENABLED); + bAddSep = TRUE; + } + + if (rfg & SFGAO_HASPROPSHEET) + { + _InsertMenuItemW(hMenu, indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); + } + + return iIdCmdLast; +} + +HRESULT +WINAPI +IDefaultContextMenuImpl::QueryContextMenu( + HMENU hmenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags) +{ + if (dcm.cidl) + { + idCmdFirst = BuildShellItemContextMenu(hmenu, idCmdFirst, idCmdLast, uFlags); + } + else + { + idCmdFirst = BuildBackgroundContextMenu(hmenu, idCmdFirst, idCmdLast, uFlags); + } + + return S_OK; +} + +static +HRESULT +NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi, BOOL bRefresh) +{ + LPSHELLBROWSER lpSB; + LPSHELLVIEW lpSV = NULL; + HWND hwndSV = NULL; + + if((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0))) + { + if(SUCCEEDED(lpSB->QueryActiveShellView(&lpSV))) + { + lpSV->GetWindow(&hwndSV); + } + } + + if (LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_REFRESH || bRefresh) + { + if (lpSV) + lpSV->Refresh(); + + return S_OK; + } + + SendMessageW(hwndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0); + + return S_OK; +} + +HRESULT +IDefaultContextMenuImpl::DoPaste( + LPCMINVOKECOMMANDINFO lpcmi) +{ + IDataObject * pda; + STGMEDIUM medium; + FORMATETC formatetc; + LPITEMIDLIST * apidl; + LPITEMIDLIST pidl; + IShellFolder *psfFrom = NULL, *psfDesktop, *psfTarget = NULL; + LPIDA lpcida; + ISFHelper *psfhlpdst, *psfhlpsrc; + HRESULT hr; + + if (OleGetClipboard(&pda) != S_OK) + return E_FAIL; + + InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL); + hr = pda->GetData(&formatetc,&medium); + + if (FAILED(hr)) + { + pda->Release(); + return E_FAIL; + } + + /* lock the handle */ + lpcida = (LPIDA)GlobalLock(medium.hGlobal); + if (!lpcida) + { + ReleaseStgMedium(&medium); + pda->Release(); + return E_FAIL; + } + + /* convert the data into pidl */ + apidl = _ILCopyCidaToaPidl(&pidl, lpcida); + + if (!apidl) + return E_FAIL; + + if (FAILED(SHGetDesktopFolder(&psfDesktop))) + { + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + pda->Release(); + 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"); + + psfDesktop->Release(); + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + pda->Release(); + + return E_FAIL; + } + + if (dcm.cidl) + { + psfDesktop->Release(); + hr = dcm.psf->BindToObject(dcm.apidl[0], NULL, IID_IShellFolder, (LPVOID*)&psfTarget); + } + else + { + IPersistFolder2 *ppf2 = NULL; + LPITEMIDLIST pidl; + + /* cidl is zero due to explorer view */ + hr = dcm.psf->QueryInterface (IID_IPersistFolder2, (LPVOID *) &ppf2); + if (SUCCEEDED(hr)) + { + hr = ppf2->GetCurFolder (&pidl); + ppf2->Release(); + if (SUCCEEDED(hr)) + { + if (_ILIsDesktop(pidl)) + { + /* use desktop shellfolder */ + psfTarget = psfDesktop; + } + else + { + /* retrieve target desktop folder */ + hr = psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfTarget); + } + TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget, _ILIsDesktop(pidl)); + ILFree(pidl); + } + } + } + + if (FAILED(hr)) + { + ERR("no IShellFolder\n"); + + psfFrom->Release(); + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + pda->Release(); + + return E_FAIL; + } + + + /* get source and destination shellfolder */ + if (FAILED(psfTarget->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpdst))) + { + ERR("no IID_ISFHelper for destination\n"); + + psfFrom->Release(); + psfTarget->Release(); + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + pda->Release(); + + return E_FAIL; + } + + if (FAILED(psfFrom->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlpsrc))) + { + ERR("no IID_ISFHelper for source\n"); + + psfhlpdst->Release(); + psfFrom->Release(); + psfTarget->Release(); + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + pda->Release(); + return E_FAIL; + } + + /* FIXXME + * do we want to perform a copy or move ??? + */ + hr = psfhlpdst->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl); + + psfhlpdst->Release(); + psfhlpsrc->Release(); + psfFrom->Release(); + psfTarget->Release(); + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + pda->Release(); + TRACE("CP result %x\n",hr); + return S_OK; +} + +HRESULT +IDefaultContextMenuImpl::DoOpenOrExplore( + LPCMINVOKECOMMANDINFO lpcmi) +{ + + + return E_FAIL; +} + +BOOL +GetUniqueFileName(LPWSTR szBasePath, LPWSTR szExt, LPWSTR szTarget, BOOL bShortcut) +{ + UINT RetryCount = 0, Length; + WCHAR szLnk[40]; + HANDLE hFile; + + if (!bShortcut) + { + Length = LoadStringW(shell32_hInstance, IDS_LNK_FILE, szLnk, sizeof(szLnk)/sizeof(WCHAR)); + } + + do + { + if (!bShortcut) + { + if (RetryCount) + swprintf(szTarget, L"%s%s(%u).%s", szLnk, szBasePath, RetryCount, szExt); + else + swprintf(szTarget, L"%s%s.%s", szLnk, szBasePath, szExt); + } + else + { + if (RetryCount) + swprintf(szTarget, L"%s(%u).%s", szBasePath, RetryCount, szExt); + else + swprintf(szTarget, L"%s.%s", szBasePath, szExt); + } + + hFile = CreateFileW(szTarget, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + CloseHandle(hFile); + return TRUE; + } + + }while(RetryCount++ < 100); + + return FALSE; + +} + +HRESULT +IDefaultContextMenuImpl::DoCreateLink( + LPCMINVOKECOMMANDINFO lpcmi) +{ + WCHAR szPath[MAX_PATH]; + WCHAR szTarget[MAX_PATH] = {0}; + WCHAR szDirPath[MAX_PATH]; + LPWSTR pszFile; + STRRET strFile; + LPWSTR pszExt; + HRESULT hr; + IShellLinkW * nLink; + IPersistFile * ipf; + static WCHAR szLnk[] = L"lnk"; + + if (dcm.psf->GetDisplayNameOf(dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK) + { + ERR("IShellFolder_GetDisplayNameOf failed for apidl\n"); + return E_FAIL; + } + + if (StrRetToBufW(&strFile, dcm.apidl[0], szPath, MAX_PATH) != S_OK) + return E_FAIL; + + pszExt = wcsrchr(szPath, L'.'); + + if (pszExt && !wcsicmp(pszExt + 1, szLnk)) + { + if (!GetUniqueFileName(szPath, pszExt + 1, szTarget, TRUE)) + return E_FAIL; + + hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, dcm.apidl[0], (LPVOID*)&ipf); + if (hr != S_OK) + { + return hr; + } + hr = ipf->Save(szTarget, FALSE); + ipf->Release(); + NotifyShellViewWindow(lpcmi, TRUE); + return hr; + } + else + { + if (!GetUniqueFileName(szPath, szLnk, szTarget, TRUE)) + return E_FAIL; + + hr = ShellLink::_CreatorClass::CreateInstance(NULL, IID_IShellLinkW, (void**)&nLink); + if (hr != S_OK) + { + return E_FAIL; + } + + GetFullPathName(szPath, MAX_PATH, szDirPath, &pszFile); + if (pszFile) pszFile[0] = 0; + + if (SUCCEEDED(nLink->SetPath(szPath)) && + SUCCEEDED(nLink->SetWorkingDirectory(szDirPath))) + { + if (SUCCEEDED(nLink->QueryInterface(IID_IPersistFile, (LPVOID*)&ipf))) + { + hr = ipf->Save(szTarget, TRUE); + ipf->Release(); + } + } + nLink->Release(); + NotifyShellViewWindow(lpcmi, TRUE); + return hr; + } +} + +HRESULT +IDefaultContextMenuImpl::DoDelete( + LPCMINVOKECOMMANDINFO lpcmi) +{ + HRESULT hr; + STRRET strTemp; + WCHAR szPath[MAX_PATH]; + LPWSTR wszPath, wszPos; + SHFILEOPSTRUCTW op; + int ret; + LPSHELLBROWSER lpSB; + HWND hwnd; + + + hr = dcm.psf->GetDisplayNameOf(dcm.apidl[0], SHGDN_FORPARSING, &strTemp); + if(hr != S_OK) + { + ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr); + return hr; + } + ZeroMemory(szPath, sizeof(szPath)); + hr = StrRetToBufW(&strTemp, dcm.apidl[0], szPath, MAX_PATH); + if (hr != S_OK) + { + ERR("StrRetToBufW failed with %x\n", hr); + return hr; + } + + /* Only keep the base path */ + wszPos = strrchrW(szPath, '\\'); + if (wszPos != NULL) + { + *(wszPos + 1) = '\0'; + } + + wszPath = build_paths_list(szPath, dcm.cidl, dcm.apidl); + + ZeroMemory(&op, sizeof(op)); + op.hwnd = GetActiveWindow(); + op.wFunc = FO_DELETE; + op.pFrom = wszPath; + op.fFlags = FOF_ALLOWUNDO; + ret = SHFileOperationW(&op); + + if (ret) + { + ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(wszPath)); + return S_OK; + } + + /* get the active IShellView */ + if ((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0))) + { + /* is the treeview focused */ + if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd))) + { + HTREEITEM hItem = TreeView_GetSelection(hwnd); + if (hItem) + { + (void)TreeView_DeleteItem(hwnd, hItem); + } + } + } + NotifyShellViewWindow(lpcmi, TRUE); + + HeapFree(GetProcessHeap(), 0, wszPath); + return S_OK; + +} + +HRESULT +IDefaultContextMenuImpl::DoCopyOrCut( + LPCMINVOKECOMMANDINFO lpcmi, + BOOL bCopy) +{ + LPSHELLBROWSER lpSB; + LPSHELLVIEW lpSV; + LPDATAOBJECT pDataObj; + HRESULT hr; + + if (SUCCEEDED(SHCreateDataObject(dcm.pidlFolder, dcm.cidl, dcm.apidl, NULL, IID_IDataObject, (void**)&pDataObj))) + { + hr = OleSetClipboard(pDataObj); + pDataObj->Release(); + return hr; + } + + lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0); + if (!lpSB) + { + TRACE("failed to get shellbrowser\n"); + return E_FAIL; + } + + hr = lpSB->QueryActiveShellView(&lpSV); + if (FAILED(hr)) + { + TRACE("failed to query the active shellview\n"); + return hr; + } + + hr = lpSV->GetItemObject(SVGIO_SELECTION, IID_IDataObject, (LPVOID*)&pDataObj); + if (FAILED(hr)) + { + TRACE("failed to get item object\n"); + return hr; + } + + hr = OleSetClipboard(pDataObj); + if (FAILED(hr)) + { + WARN("OleSetClipboard failed"); + } + pDataObj->Release(); + lpSV->Release(); + return S_OK; +} + +HRESULT +IDefaultContextMenuImpl::DoRename( + LPCMINVOKECOMMANDINFO lpcmi) +{ + LPSHELLBROWSER lpSB; + LPSHELLVIEW lpSV; + HWND hwnd; + + /* get the active IShellView */ + if ((lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER,0,0))) + { + /* is the treeview focused */ + if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd))) + { + HTREEITEM hItem = TreeView_GetSelection(hwnd); + if (hItem) + { + (void)TreeView_EditLabel(hwnd, hItem); + } + } + + if(SUCCEEDED(lpSB->QueryActiveShellView(&lpSV))) + { + lpSV->SelectItem(dcm.apidl[0], + SVSI_DESELECTOTHERS|SVSI_EDIT|SVSI_ENSUREVISIBLE|SVSI_FOCUSED|SVSI_SELECT); + lpSV->Release(); + return S_OK; + } + } + return E_FAIL; +} + +HRESULT +IDefaultContextMenuImpl::DoProperties( + LPCMINVOKECOMMANDINFO lpcmi) +{ + WCHAR szDrive[MAX_PATH]; + STRRET strFile; + + if (dcm.cidl &&_ILIsMyComputer(dcm.apidl[0])) + { + ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL, NULL, SW_SHOWNORMAL); + return S_OK; + } + else if (dcm.cidl == 0 && _ILIsDesktop(dcm.pidlFolder)) + { + ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL); + return S_OK; + } + else if (_ILIsDrive(dcm.apidl[0])) + { + ILGetDisplayName(dcm.apidl[0], szDrive); + SH_ShowDriveProperties(szDrive, dcm.pidlFolder, dcm.apidl); + return S_OK; + } + else if (_ILIsNetHood(dcm.apidl[0])) + { + //FIXME path! + ShellExecuteW(NULL, L"open", L"explorer.exe", + L"/n,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}", + NULL, SW_SHOWDEFAULT); + return S_OK; + } + else if (_ILIsBitBucket(dcm.apidl[0])) + { + /* FIXME + * detect the drive path of bitbucket if appropiate + */ + + SH_ShowRecycleBinProperties(L'C'); + return S_OK; + } + + if (dcm.cidl > 1) + WARN("SHMultiFileProperties is not yet implemented\n"); + + if (dcm.psf->GetDisplayNameOf(dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK) + { + ERR("IShellFolder_GetDisplayNameOf failed for apidl\n"); + return E_FAIL; + } + + if (StrRetToBufW(&strFile, dcm.apidl[0], szDrive, MAX_PATH) != S_OK) + return E_FAIL; + + return SH_ShowPropertiesDialog(szDrive, dcm.pidlFolder, dcm.apidl); +} + +HRESULT +IDefaultContextMenuImpl::DoFormat( + LPCMINVOKECOMMANDINFO lpcmi) +{ + char sDrive[5] = {0}; + + if (!_ILGetDrive(dcm.apidl[0], sDrive, sizeof(sDrive))) + { + ERR("pidl is not a drive\n"); + return E_FAIL; + } + + SHFormatDrive(lpcmi->hwnd, sDrive[0] - 'A', SHFMT_ID_DEFAULT, 0); + return S_OK; +} + +HRESULT +IDefaultContextMenuImpl::DoDynamicShellExtensions( + LPCMINVOKECOMMANDINFO lpcmi) +{ + UINT verb = LOWORD(lpcmi->lpVerb); + PDynamicShellEntry pCurrent = dhead; + + TRACE("verb %p first %x last %x", lpcmi->lpVerb, iIdSHEFirst, iIdSHELast); + + while(pCurrent && verb > pCurrent->iIdCmdFirst + pCurrent->NumIds) + pCurrent = pCurrent->Next; + + if (!pCurrent) + return E_FAIL; + + if (verb >= pCurrent->iIdCmdFirst && verb <= pCurrent->iIdCmdFirst + pCurrent->NumIds) + { + /* invoke the dynamic context menu */ + lpcmi->lpVerb = MAKEINTRESOURCEA(verb - pCurrent->iIdCmdFirst); + return pCurrent->CMenu->InvokeCommand(lpcmi); + } + + return E_FAIL; +} + + +HRESULT +IDefaultContextMenuImpl::DoStaticShellExtensions( + LPCMINVOKECOMMANDINFO lpcmi) +{ + STRRET strFile; + WCHAR szPath[MAX_PATH]; + WCHAR szDir[MAX_PATH]; + SHELLEXECUTEINFOW sei; + PStaticShellEntry pCurrent = shead; + int verb = LOWORD(lpcmi->lpVerb) - iIdSCMFirst; + + + while(pCurrent && verb-- > 0) + pCurrent = pCurrent->Next; + + if (verb > 0) + return E_FAIL; + + + if (dcm.psf->GetDisplayNameOf(dcm.apidl[0], SHGDN_FORPARSING, &strFile) != S_OK) + { + ERR("IShellFolder_GetDisplayNameOf failed for apidl\n"); + return E_FAIL; + } + + if (StrRetToBufW(&strFile, dcm.apidl[0], szPath, MAX_PATH) != S_OK) + return E_FAIL; + + wcscpy(szDir, szPath); + PathRemoveFileSpec(szDir); + + ZeroMemory(&sei, sizeof(sei)); + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_CLASSNAME; + sei.lpClass = pCurrent->szClass; + sei.hwnd = lpcmi->hwnd; + sei.nShow = SW_SHOWNORMAL; + sei.lpVerb = pCurrent->szVerb; + sei.lpFile = szPath; + sei.lpDirectory = szDir; + ShellExecuteExW(&sei); + return S_OK; + +} + +HRESULT +WINAPI +IDefaultContextMenuImpl::InvokeCommand( + LPCMINVOKECOMMANDINFO lpcmi) +{ + switch(LOWORD(lpcmi->lpVerb)) + { + case FCIDM_SHVIEW_BIGICON: + case FCIDM_SHVIEW_SMALLICON: + case FCIDM_SHVIEW_LISTVIEW: + case FCIDM_SHVIEW_REPORTVIEW: + case 0x30: /* FIX IDS in resource files */ + case 0x31: + case 0x32: + case 0x33: + case FCIDM_SHVIEW_AUTOARRANGE: + case FCIDM_SHVIEW_SNAPTOGRID: + case FCIDM_SHVIEW_REFRESH: + return NotifyShellViewWindow(lpcmi, FALSE); + case FCIDM_SHVIEW_INSERT: + case FCIDM_SHVIEW_INSERTLINK: + return DoPaste(lpcmi); + case FCIDM_SHVIEW_OPEN: + case FCIDM_SHVIEW_EXPLORE: + return DoOpenOrExplore(lpcmi); + case FCIDM_SHVIEW_COPY: + case FCIDM_SHVIEW_CUT: + return DoCopyOrCut(lpcmi, LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_COPY); + case FCIDM_SHVIEW_CREATELINK: + return DoCreateLink(lpcmi); + case FCIDM_SHVIEW_DELETE: + return DoDelete(lpcmi); + case FCIDM_SHVIEW_RENAME: + return DoRename(lpcmi); + case FCIDM_SHVIEW_PROPERTIES: + return DoProperties(lpcmi); + case 0x7ABC: + return DoFormat(lpcmi); + } + + if (iIdSHEFirst && iIdSHELast) + { + if (LOWORD(lpcmi->lpVerb) >= iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= iIdSHELast) + { + return DoDynamicShellExtensions(lpcmi); + } + } + + if (iIdSCMFirst && iIdSCMLast) + { + if (LOWORD(lpcmi->lpVerb) >= iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= iIdSCMLast) + { + return DoStaticShellExtensions(lpcmi); + } + } + + FIXME("Unhandled Verb %xl\n",LOWORD(lpcmi->lpVerb)); + return E_UNEXPECTED; +} + +HRESULT +WINAPI +IDefaultContextMenuImpl::GetCommandString( + UINT_PTR idCommand, + UINT uFlags, + UINT* lpReserved, + LPSTR lpszName, + UINT uMaxNameLen) +{ + + return S_OK; +} + +HRESULT +WINAPI +IDefaultContextMenuImpl::HandleMenuMsg( + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + + return S_OK; +} + +static +HRESULT +IDefaultContextMenu_Constructor( + const DEFCONTEXTMENU *pdcm, + REFIID riid, + void **ppv) +{ + CComObject *theContextMenu; + CComPtr result; + HRESULT hResult; + + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; + ATLTRY (theContextMenu = new CComObject); + if (theContextMenu == NULL) + return E_OUTOFMEMORY; + hResult = theContextMenu->QueryInterface (riid, (void **)&result); + if (FAILED (hResult)) + { + delete theContextMenu; + return hResult; + } + hResult = theContextMenu->Initialize (pdcm); + if (FAILED (hResult)) + return hResult; + *ppv = result.Detach (); + TRACE("This(%p)(%x) cidl %u\n", *ppv, hResult, pdcm->cidl); + return S_OK; +} + +/************************************************************************* + * SHCreateDefaultContextMenu [SHELL32.325] Vista API + * + */ + +HRESULT +WINAPI +SHCreateDefaultContextMenu( + const DEFCONTEXTMENU *pdcm, + REFIID riid, + void **ppv) +{ + HRESULT hr = E_FAIL; + + *ppv = NULL; + hr = IDefaultContextMenu_Constructor( pdcm, riid, ppv ); + + TRACE("pcm %p hr %x\n", pdcm, hr); + return hr; +} + +/************************************************************************* + * CDefFolderMenu_Create2 [SHELL32.701] + * + */ + +HRESULT +WINAPI +CDefFolderMenu_Create2( + LPCITEMIDLIST pidlFolder, + HWND hwnd, + UINT cidl, + LPCITEMIDLIST *apidl, + IShellFolder *psf, + LPFNDFMCALLBACK lpfn, + UINT nKeys, + const HKEY *ahkeyClsKeys, + IContextMenu **ppcm) +{ + DEFCONTEXTMENU pdcm; + HRESULT hr; + + pdcm.hwnd = hwnd; + pdcm.pcmcb = NULL; + pdcm.pidlFolder = pidlFolder; + pdcm.psf = psf; + pdcm.cidl = cidl; + pdcm.apidl = apidl; + pdcm.punkAssociationInfo = NULL; + pdcm.cKeys = nKeys; + pdcm.aKeys = ahkeyClsKeys; + + hr = SHCreateDefaultContextMenu(&pdcm, IID_IContextMenu, (void**)ppcm); + return hr; +} + diff --git a/reactos/dll/win32/shell32/shv_item_new.cpp b/reactos/dll/win32/shell32/shv_item_new.cpp new file mode 100644 index 00000000000..e370ac86133 --- /dev/null +++ b/reactos/dll/win32/shell32/shv_item_new.cpp @@ -0,0 +1,730 @@ +/* + * provides new shell item service + * + * Copyright 2007 Johannes Anderwald (janderwald@reactos.org) + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +static WCHAR szNew[MAX_PATH]; + +CNewMenu::CNewMenu() +{ + s_SnHead = NULL; + szPath = NULL; +} + +CNewMenu::~CNewMenu() +{ +} + +static +BOOL +GetKeyDescription(LPWSTR szKeyName, LPWSTR szResult) +{ + HKEY hKey; + DWORD dwDesc, dwError; + WCHAR szDesc[100]; + + static const WCHAR szFriendlyTypeName[] = { '\\','F','r','i','e','n','d','l','y','T','y','p','e','N','a','m','e',0 }; + + TRACE("GetKeyDescription: keyname %s\n", debugstr_w(szKeyName)); + + if (RegOpenKeyExW(HKEY_CLASSES_ROOT,szKeyName,0, KEY_READ | KEY_QUERY_VALUE,&hKey) != ERROR_SUCCESS) + return FALSE; + + if (RegLoadMUIStringW(hKey,szFriendlyTypeName,szResult,MAX_PATH,&dwDesc,0,NULL) == ERROR_SUCCESS) + { + TRACE("result %s\n", debugstr_w(szResult)); + RegCloseKey(hKey); + return TRUE; + } + /* fetch default value */ + dwDesc = sizeof(szDesc); + dwError = RegGetValueW(hKey,NULL,NULL, RRF_RT_REG_SZ,NULL,szDesc,&dwDesc); + if(dwError == ERROR_SUCCESS) + { + if (wcsncmp(szKeyName, szDesc, dwDesc / sizeof(WCHAR))) + { + /* recurse for to a linked key */ + if (!GetKeyDescription(szDesc, szResult)) + { + /* use description */ + wcscpy(szResult, szDesc); + } + } + else + { + /* use default value as description */ + wcscpy(szResult, szDesc); + } + } + else + { + /* registry key w/o default key?? */ + TRACE("RegGetValue failed with %x\n", dwError); + wcscpy(szResult, szKeyName); + } + + RegCloseKey(hKey); + return TRUE; +} + +void CNewMenu::UnloadItem(SHELLNEW_ITEM *item) +{ + // bail if the item is clearly invalid + if (NULL == item) + return; + + if (NULL != item->szTarget) + free(item->szTarget); + + free(item->szDesc); + free(item->szIcon); + free(item->szExt); + + HeapFree(GetProcessHeap(), 0, item); +} + +CNewMenu::SHELLNEW_ITEM *CNewMenu::LoadItem(LPWSTR szKeyName) +{ + HKEY hKey; + DWORD dwIndex; + WCHAR szName[MAX_PATH]; + WCHAR szCommand[MAX_PATH]; + WCHAR szDesc[MAX_PATH] = {0}; + WCHAR szIcon[MAX_PATH] = {0}; + DWORD dwName, dwCommand; + LONG result; + SHELLNEW_ITEM *pNewItem; + + static const WCHAR szShellNew[] = { '\\','S','h','e','l','l','N','e','w',0 }; + static const WCHAR szCmd[] = { 'C','o','m','m','a','n','d',0 }; + static const WCHAR szData[] = { 'D','a','t','a',0 }; + static const WCHAR szFileName[] = { 'F','i','l','e','N','a','m','e', 0 }; + static const WCHAR szNullFile[] = { 'N','u','l','l','F','i','l','e', 0 }; + + + wcscpy(szName, szKeyName); + GetKeyDescription(szKeyName, szDesc); + wcscat(szName, szShellNew); + result = RegOpenKeyExW(HKEY_CLASSES_ROOT,szName,0,KEY_READ,&hKey); + + //TRACE("LoadItem dwName %d keyname %s szName %s szDesc %s szIcon %s\n", dwName, debugstr_w(szKeyName), debugstr_w(szName), debugstr_w(szDesc), debugstr_w(szIcon)); + + if (result != ERROR_SUCCESS) + { + return NULL; + } + + dwIndex = 0; + pNewItem = NULL; + + do + { + dwName = MAX_PATH; + dwCommand = MAX_PATH; + result = RegEnumValueW(hKey,dwIndex,szName,&dwName,NULL,NULL,(LPBYTE)szCommand, &dwCommand); + if (result == ERROR_SUCCESS) + { + SHELLNEW_TYPE type = SHELLNEW_TYPE_INVALID; + LPWSTR szTarget = szCommand; + //TRACE("szName %s szCommand %s\n", debugstr_w(szName), debugstr_w(szCommand)); + if (!wcsicmp(szName, szCmd)) + { + type = SHELLNEW_TYPE_COMMAND; + }else if (!wcsicmp(szName, szData)) + { + type = SHELLNEW_TYPE_DATA; + } + else if (!wcsicmp(szName, szFileName)) + { + type = SHELLNEW_TYPE_FILENAME; + } + else if (!wcsicmp(szName, szNullFile)) + { + type = SHELLNEW_TYPE_NULLFILE; + szTarget = NULL; + } + if (type != SHELLNEW_TYPE_INVALID) + { + pNewItem = (SHELLNEW_ITEM *)HeapAlloc(GetProcessHeap(), 0, sizeof(SHELLNEW_ITEM)); + pNewItem->Type = type; + if (szTarget) + pNewItem->szTarget = _wcsdup(szTarget); + else + pNewItem->szTarget = NULL; + + pNewItem->szDesc = _wcsdup(szDesc); + pNewItem->szIcon = _wcsdup(szIcon); + pNewItem->szExt = _wcsdup(szKeyName); + pNewItem->Next = NULL; + break; + } + } + dwIndex++; + }while(result != ERROR_NO_MORE_ITEMS); + RegCloseKey(hKey); + return pNewItem; +} + + +BOOL +CNewMenu::LoadShellNewItems() +{ + DWORD dwIndex; + WCHAR szName[MAX_PATH]; + LONG result; + SHELLNEW_ITEM *pNewItem; + SHELLNEW_ITEM *pCurItem = NULL; + static WCHAR szLnk[] = { '.','l','n','k',0 }; + + /* insert do new folder action */ + if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, szNew, sizeof(szNew) / sizeof(WCHAR))) + szNew[0] = 0; + szNew[MAX_PATH-1] = 0; + + dwIndex = 0; + do + { + result = RegEnumKeyW(HKEY_CLASSES_ROOT,dwIndex,szName,MAX_PATH); + if (result == ERROR_SUCCESS) + { + pNewItem = LoadItem(szName); + if (pNewItem) + { + if (!wcsicmp(pNewItem->szExt, szLnk)) + { + if (s_SnHead) + { + pNewItem->Next = s_SnHead; + s_SnHead = pNewItem; + } + else + { + s_SnHead = pCurItem = pNewItem; + } + } + else + { + if (pCurItem) + { + pCurItem->Next = pNewItem; + pCurItem = pNewItem; + } + else + { + pCurItem = s_SnHead = pNewItem; + } + } + } + } + dwIndex++; + }while(result != ERROR_NO_MORE_ITEMS); + + if (s_SnHead == NULL) + return FALSE; + else + return TRUE; +} + +UINT +CNewMenu::InsertShellNewItems(HMENU hMenu, UINT idFirst, UINT idMenu) +{ + MENUITEMINFOW mii; + SHELLNEW_ITEM *pCurItem; + UINT i; + WCHAR szBuffer[MAX_PATH]; + + if (s_SnHead == NULL) + { + if (!LoadShellNewItems()) + return 0; + } + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + + /* insert do new shortcut action */ + if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEWFOLDER, szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]))) + szBuffer[0] = 0; + szBuffer[MAX_PATH-1] = 0; + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; + mii.fType = MFT_STRING; + mii.dwTypeData = szBuffer; + mii.cch = wcslen(mii.dwTypeData); + mii.wID = idFirst++; + InsertMenuItemW(hMenu, idMenu++, TRUE, &mii); + + /* insert do new shortcut action */ + if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEWLINK, szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]))) + szBuffer[0] = 0; + szBuffer[MAX_PATH-1] = 0; + mii.dwTypeData = szBuffer; + mii.cch = wcslen(mii.dwTypeData); + mii.wID = idFirst++; + InsertMenuItemW(hMenu, idMenu++, TRUE, &mii); + + /* insert seperator for custom new action */ + mii.fMask = MIIM_TYPE | MIIM_ID; + mii.fType = MFT_SEPARATOR; + mii.wID = -1; + InsertMenuItemW(hMenu, idMenu++, TRUE, &mii); + + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; + /* + * FIXME + * implement loading of icons + * and using MFT_OWNERDRAWN + */ + mii.fType = MFT_STRING; + mii.fState = MFS_ENABLED; + + pCurItem = s_SnHead; + i = 0; + + while(pCurItem) + { + if (i >= 1) + { + TRACE("szDesc %s\n", debugstr_w(pCurItem->szDesc)); + mii.dwTypeData = pCurItem->szDesc; + mii.cch = wcslen(mii.dwTypeData); + mii.wID = idFirst++; + InsertMenuItemW(hMenu, idMenu++, TRUE, &mii); + } + pCurItem = pCurItem->Next; + i++; + } + return (i+2); +} + +HRESULT +CNewMenu::DoShellNewCmd(LPCMINVOKECOMMANDINFO lpcmi) +{ + SHELLNEW_ITEM *pCurItem = s_SnHead; + IPersistFolder3 * psf; + LPITEMIDLIST pidl; + STRRET strTemp; + WCHAR szTemp[MAX_PATH]; + WCHAR szBuffer[MAX_PATH]; + WCHAR szPath[MAX_PATH]; + STARTUPINFOW sInfo; + PROCESS_INFORMATION pi; + UINT i, target; + HANDLE hFile; + DWORD dwWritten, dwError; + CComPtr folderView; + CComPtr parentFolder; + HRESULT hResult; + + static const WCHAR szP1[] = { '%', '1', 0 }; + static const WCHAR szFormat[] = {'%','s',' ','(','%','d',')','%','s',0 }; + + i = 1; + target = LOWORD(lpcmi->lpVerb); + + while(pCurItem) + { + if (i == target) + break; + + pCurItem = pCurItem->Next; + i++; + } + + if (!pCurItem) + return E_UNEXPECTED; + + if (fSite == NULL) + return E_FAIL; + hResult = IUnknown_QueryService(fSite, SID_IFolderView, IID_IFolderView, (void **)&folderView); + if (FAILED(hResult)) + return hResult; + hResult = folderView->GetFolder(IID_IShellFolder, (void **)&parentFolder); + if (FAILED(hResult)) + return hResult; + + if (parentFolder->QueryInterface(IID_IPersistFolder2, (LPVOID*)&psf) != S_OK) + { + ERR("Failed to get interface IID_IPersistFolder2\n"); + return E_FAIL; + } + if (psf->GetCurFolder(&pidl) != S_OK) + { + ERR("IPersistFolder2_GetCurFolder failed\n"); + return E_FAIL; + } + + if (parentFolder == NULL || parentFolder->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strTemp) != S_OK) + { + ERR("IShellFolder_GetDisplayNameOf failed\n"); + return E_FAIL; + } + StrRetToBufW(&strTemp, pidl, szPath, MAX_PATH); + + switch(pCurItem->Type) + { + case SHELLNEW_TYPE_COMMAND: + { + LPWSTR ptr; + LPWSTR szCmd; + + if (!ExpandEnvironmentStringsW(pCurItem->szTarget, szBuffer, MAX_PATH)) + { + TRACE("ExpandEnvironmentStrings failed\n"); + break; + } + + ptr = wcsstr(szBuffer, szP1); + if (ptr) + { + ptr[1] = 's'; + swprintf(szTemp, szBuffer, szPath); + ptr = szTemp; + } + else + { + ptr = szBuffer; + } + + ZeroMemory(&sInfo, sizeof(sInfo)); + sInfo.cb = sizeof(sInfo); + szCmd = _wcsdup(ptr); + if (!szCmd) + break; + if (CreateProcessW(NULL, szCmd, NULL, NULL,FALSE,0,NULL,NULL,&sInfo, &pi)) + { + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + } + free(szCmd); + break; + } + case SHELLNEW_TYPE_DATA: + case SHELLNEW_TYPE_FILENAME: + case SHELLNEW_TYPE_NULLFILE: + { + i = 2; + + PathAddBackslashW(szPath); + wcscat(szPath, szNew); + wcscat(szPath, L" "); + wcscat(szPath, pCurItem->szDesc); + wcscpy(szBuffer, szPath); + wcscat(szBuffer, pCurItem->szExt); + do + { + hFile = CreateFileW(szBuffer, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile != INVALID_HANDLE_VALUE) + break; + dwError = GetLastError(); + + TRACE("FileName %s szBuffer %s i %u error %x\n", debugstr_w(szBuffer), debugstr_w(szPath), i, dwError); + swprintf(szBuffer, szFormat, szPath, i, pCurItem->szExt); + i++; + }while(hFile == INVALID_HANDLE_VALUE && dwError == ERROR_FILE_EXISTS); + + if (hFile == INVALID_HANDLE_VALUE) + return E_FAIL; + + if (pCurItem->Type == SHELLNEW_TYPE_DATA) + { + i = WideCharToMultiByte(CP_ACP, 0, pCurItem->szTarget, -1, (LPSTR)szTemp, MAX_PATH*2, NULL, NULL); + if (i) + { + WriteFile(hFile, (LPCVOID)szTemp, i, &dwWritten, NULL); + } + } + CloseHandle(hFile); + if (pCurItem->Type == SHELLNEW_TYPE_FILENAME) + { + if (!CopyFileW(pCurItem->szTarget, szBuffer, FALSE)) + break; + } + TRACE("Notifying fs %s\n", debugstr_w(szBuffer)); + SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, (LPCVOID)szBuffer, NULL); + break; + case SHELLNEW_TYPE_INVALID: + break; + } + } + return S_OK; +} +/************************************************************************** +* DoMeasureItem +*/ +HRESULT +CNewMenu::DoMeasureItem(HWND hWnd, MEASUREITEMSTRUCT * lpmis) +{ + SHELLNEW_ITEM *pCurItem; + SHELLNEW_ITEM *pItem; + UINT i; + HDC hDC; + SIZE size; + + TRACE("DoMeasureItem entered with id %x\n", lpmis->itemID); + + pCurItem = s_SnHead; + + i = 1; + pItem = NULL; + while(pCurItem) + { + if (i == lpmis->itemID) + { + pItem = pCurItem; + break; + } + pCurItem = pCurItem->Next; + i++; + } + + if (!pItem) + { + TRACE("DoMeasureItem no item found\n"); + return E_FAIL; + } + hDC = GetDC(hWnd); + GetTextExtentPoint32W(hDC, pCurItem->szDesc, wcslen(pCurItem->szDesc), &size); + lpmis->itemWidth = size.cx + 32; + lpmis->itemHeight = max(size.cy, 20); + ReleaseDC (hWnd, hDC); + return S_OK; +} +/************************************************************************** +* DoDrawItem +*/ +HRESULT +CNewMenu::DoDrawItem(HWND hWnd, DRAWITEMSTRUCT * drawItem) +{ + SHELLNEW_ITEM *pCurItem; + SHELLNEW_ITEM *pItem; + UINT i; + pCurItem = s_SnHead; + + TRACE("DoDrawItem entered with id %x\n", drawItem->itemID); + + i = 1; + pItem = NULL; + while(pCurItem) + { + if (i == drawItem->itemID) + { + pItem = pCurItem; + break; + } + pCurItem = pCurItem->Next; + i++; + } + + if (!pItem) + return E_FAIL; + + drawItem->rcItem.left += 20; + + DrawTextW(drawItem->hDC, pCurItem->szDesc, wcslen(pCurItem->szDesc), &drawItem->rcItem, 0); + return S_OK; +} + +/************************************************************************** +* DoNewFolder +*/ +void CNewMenu::DoNewFolder( + IShellView *psv) +{ + ISFHelper * psfhlp; + WCHAR wszName[MAX_PATH]; + CComPtr folderView; + CComPtr parentFolder; + HRESULT hResult; + + if (fSite == NULL) + return; + hResult = IUnknown_QueryService(fSite, SID_IFolderView, IID_IFolderView, (void **)&folderView); + if (FAILED(hResult)) + return; + hResult = folderView->GetFolder(IID_IShellFolder, (void **)&parentFolder); + if (FAILED(hResult)) + return; + + parentFolder->QueryInterface(IID_ISFHelper, (LPVOID*)&psfhlp); + if (psfhlp) + { + LPITEMIDLIST pidl; + + if (psfhlp->GetUniqueName(wszName, MAX_PATH) != S_OK) + return; + if (psfhlp->AddFolder(0, wszName, &pidl) != S_OK) + return; + + if(psv) + { + psv->Refresh(); + /* if we are in a shellview do labeledit */ + psv->SelectItem( + pidl,(SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE + |SVSI_FOCUSED|SVSI_SELECT)); + psv->Refresh(); + } + SHFree(pidl); + + psfhlp->Release(); + } +} + +HRESULT STDMETHODCALLTYPE CNewMenu::SetSite(IUnknown *pUnkSite) +{ + fSite = pUnkSite; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CNewMenu::GetSite(REFIID riid, void **ppvSite) +{ + if (ppvSite == NULL) + return E_POINTER; + *ppvSite = fSite; + if (fSite.p != NULL) + fSite.p->AddRef(); + return S_OK; +} + +HRESULT +WINAPI +CNewMenu::QueryContextMenu(HMENU hmenu, + UINT indexMenu, + UINT idCmdFirst, + UINT idCmdLast, + UINT uFlags) +{ + WCHAR szBuffer[200]; + MENUITEMINFOW mii; + HMENU hSubMenu; + int id = 1; + + TRACE("%p %p %u %u %u %u\n", this, + hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags ); + + if (!LoadStringW(shell32_hInstance, FCIDM_SHVIEW_NEW, szBuffer, 200)) + { + szBuffer[0] = 0; + } + szBuffer[199] = 0; + + hSubMenu = CreateMenu(); + memset( &mii, 0, sizeof(mii) ); + mii.cbSize = sizeof (mii); + mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; + mii.fType = MFT_STRING; + mii.wID = idCmdFirst + id++; + mii.dwTypeData = szBuffer; + mii.cch = wcslen( mii.dwTypeData ); + mii.fState = MFS_ENABLED; + + if (hSubMenu) + { + id += InsertShellNewItems( hSubMenu, idCmdFirst, 0); + mii.fMask |= MIIM_SUBMENU; + mii.hSubMenu = hSubMenu; + } + + + if (!InsertMenuItemW( hmenu, indexMenu, TRUE, &mii )) + return E_FAIL; + + return MAKE_HRESULT( SEVERITY_SUCCESS, 0, id ); +} + +HRESULT +WINAPI +CNewMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) +{ + LPSHELLBROWSER lpSB; + LPSHELLVIEW lpSV = NULL; + HRESULT hr; + + if((lpSB = (LPSHELLBROWSER)SendMessageA(lpici->hwnd, CWM_GETISHELLBROWSER,0,0))) + { + lpSB->QueryActiveShellView(&lpSV); + } + + if (LOWORD(lpici->lpVerb) == 0) + { + DoNewFolder(lpSV); + return S_OK; + } + + hr = DoShellNewCmd(lpici); + if (SUCCEEDED(hr) && lpSV) + { + lpSV->Refresh(); + } + + TRACE("INewItem_IContextMenu_fnInvokeCommand %x\n", hr); + return hr; +} + +HRESULT +WINAPI +CNewMenu::GetCommandString(UINT_PTR idCmd, + UINT uType, + UINT* pwReserved, + LPSTR pszName, + UINT cchMax) +{ + FIXME("%p %lu %u %p %p %u\n", this, + idCmd, uType, pwReserved, pszName, cchMax ); + + return E_NOTIMPL; +} + +HRESULT +WINAPI +CNewMenu::HandleMenuMsg(UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + DRAWITEMSTRUCT * lpids = (DRAWITEMSTRUCT*) lParam; + MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*) lParam; + + TRACE("INewItem_IContextMenu_fnHandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n",this, uMsg, wParam, lParam); + + + switch(uMsg) + { + case WM_MEASUREITEM: + return DoMeasureItem((HWND)wParam, lpmis); + break; + case WM_DRAWITEM: + return DoDrawItem((HWND)wParam, lpids); + break; + } + return S_OK; + + return E_UNEXPECTED; +} + +HRESULT WINAPI +CNewMenu::Initialize(LPCITEMIDLIST pidlFolder, + IDataObject *pdtobj, HKEY hkeyProgID ) +{ + + return S_OK; +} diff --git a/reactos/dll/win32/shell32/shv_item_new.h b/reactos/dll/win32/shell32/shv_item_new.h new file mode 100644 index 00000000000..a8168419fd8 --- /dev/null +++ b/reactos/dll/win32/shell32/shv_item_new.h @@ -0,0 +1,95 @@ +/* + * provides new shell item service + * + * Copyright 2007 Johannes Anderwald (janderwald@reactos.org) + * 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 + */ + +#ifndef _SHV_ITEM_NEW_H_ +#define _SHV_ITEM_NEW_H_ + +class CNewMenu : + public CComCoClass, + public CComObjectRootEx, + public IObjectWithSite, + public IContextMenu2, + public IShellExtInit +{ +private: + enum SHELLNEW_TYPE + { + SHELLNEW_TYPE_INVALID = -1, + SHELLNEW_TYPE_COMMAND = 1, + SHELLNEW_TYPE_DATA = 2, + SHELLNEW_TYPE_FILENAME = 4, + SHELLNEW_TYPE_NULLFILE = 8 + }; + + struct SHELLNEW_ITEM + { + SHELLNEW_TYPE Type; + LPWSTR szExt; + LPWSTR szTarget; + LPWSTR szDesc; + LPWSTR szIcon; + SHELLNEW_ITEM *Next; + }; + + LPWSTR szPath; + SHELLNEW_ITEM *s_SnHead; + CComPtr fSite; +public: + CNewMenu(); + ~CNewMenu(); + SHELLNEW_ITEM *LoadItem(LPWSTR szKeyName); + void UnloadItem(SHELLNEW_ITEM *item); + BOOL LoadShellNewItems(); + UINT InsertShellNewItems(HMENU hMenu, UINT idFirst, UINT idMenu); + HRESULT DoShellNewCmd(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoMeasureItem(HWND hWnd, MEASUREITEMSTRUCT *lpmis); + HRESULT DoDrawItem(HWND hWnd, DRAWITEMSTRUCT *drawItem); + void DoNewFolder(IShellView *psv); + + // IObjectWithSite + virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite); + virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, void **ppvSite); + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand,UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen); + + // IContextMenu2 + virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); + + // IShellExtInit + virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID); + +DECLARE_REGISTRY_RESOURCEID(IDR_NEWMENU) +DECLARE_NOT_AGGREGATABLE(CNewMenu) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CNewMenu) + COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit) +END_COM_MAP() +}; + +#endif // _SHV_ITEM_NEW_H_ diff --git a/reactos/dll/win32/shell32/startmenu.cpp b/reactos/dll/win32/shell32/startmenu.cpp new file mode 100644 index 00000000000..4c22b2b4352 --- /dev/null +++ b/reactos/dll/win32/shell32/startmenu.cpp @@ -0,0 +1,169 @@ +/* + * Start menu object + * + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL(shell32start); + +CStartMenuCallback::CStartMenuCallback() +{ +} + +CStartMenuCallback::~CStartMenuCallback() +{ +} + +HRESULT STDMETHODCALLTYPE CStartMenuCallback::SetSite(IUnknown *pUnkSite) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CStartMenuCallback::GetSite(REFIID riid, void **ppvSite) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CStartMenuCallback::CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return E_NOTIMPL; +} + +CMenuBandSite::CMenuBandSite() +{ +} + +CMenuBandSite::~CMenuBandSite() +{ +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::GetWindow(HWND *phwnd) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::ContextSensitiveHelp(BOOL fEnterMode) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::SetDeskBarSite(IUnknown *punkSite) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::SetModeDBC(DWORD dwMode) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::UIActivateDBC(DWORD dwState) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::GetSize(DWORD dwWhich, LPRECT prc) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::UIActivateIO(BOOL fActivate, LPMSG lpMsg) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::HasFocusIO() +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::TranslateAcceleratorIO(LPMSG lpMsg) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::OnWinEvent(HWND paramC, UINT param10, WPARAM param14, LPARAM param18, LRESULT *param1C) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::IsWindowOwner(HWND paramC) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::QueryService(REFGUID guidService, REFIID riid, void **ppvObject) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[ ], OLECMDTEXT *pCmdText) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::AddBand(IUnknown *punk) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::EnumBands(UINT uBand, DWORD *pdwBandID) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::RemoveBand(DWORD dwBandID) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::SetBandSiteInfo(const BANDSITEINFO *pbsinfo) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CMenuBandSite::GetBandSiteInfo(BANDSITEINFO *pbsinfo) +{ + return E_NOTIMPL; +} diff --git a/reactos/dll/win32/shell32/startmenu.h b/reactos/dll/win32/shell32/startmenu.h new file mode 100644 index 00000000000..d9773da4bbd --- /dev/null +++ b/reactos/dll/win32/shell32/startmenu.h @@ -0,0 +1,125 @@ +/* + * Start menu object + * + * 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 + */ + +#ifndef _STARTMENU_H_ +#define _STARTMENU_H_ + +class CStartMenuCallback : + public CComCoClass, + public CComObjectRootEx, + public IObjectWithSite, + public IShellMenuCallback +{ +private: +public: + CStartMenuCallback(); + ~CStartMenuCallback(); + + // *** IObjectWithSite methods *** + virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite); + virtual HRESULT STDMETHODCALLTYPE GetSite(REFIID riid, void **ppvSite); + + // *** IShellMenuCallback methods *** + virtual HRESULT STDMETHODCALLTYPE CallbackSM(LPSMDATA psmd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +DECLARE_NO_REGISTRY() +DECLARE_NOT_AGGREGATABLE(CStartMenuCallback) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CStartMenuCallback) + COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite) + COM_INTERFACE_ENTRY_IID(IID_IShellMenuCallback, IShellMenuCallback) +END_COM_MAP() +}; + +class CMenuBandSite : + public CComCoClass, + public CComObjectRootEx, + public IDeskBarClient, + public IInputObject, + public IInputObjectSite, + public IWinEventHandler, + public IServiceProvider, + public IOleCommandTarget, + public IBandSite +{ +private: +public: + CMenuBandSite(); + ~CMenuBandSite(); + + // *** IOleWindow methods *** + virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *phwnd); + virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); + + // *** IDeskBarClient methods *** + virtual HRESULT STDMETHODCALLTYPE SetDeskBarSite(IUnknown *punkSite); + virtual HRESULT STDMETHODCALLTYPE SetModeDBC(DWORD dwMode); + virtual HRESULT STDMETHODCALLTYPE UIActivateDBC(DWORD dwState); + virtual HRESULT STDMETHODCALLTYPE GetSize(DWORD dwWhich, LPRECT prc); + + // *** IInputObject methods *** + virtual HRESULT STDMETHODCALLTYPE UIActivateIO(BOOL fActivate, LPMSG lpMsg); + virtual HRESULT STDMETHODCALLTYPE HasFocusIO(); + virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorIO(LPMSG lpMsg); + + // *** IInputObjectSite methods *** + virtual HRESULT STDMETHODCALLTYPE OnFocusChangeIS(IUnknown *punkObj, BOOL fSetFocus); + + // *** IWinEventHandler methods *** + virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND paramC, UINT param10, WPARAM param14, LPARAM param18, LRESULT *param1C); + virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND paramC); + + // *** IServiceProvider methods *** + virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); + + // *** 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); + + // *** IBandSite methods *** + virtual HRESULT STDMETHODCALLTYPE AddBand(IUnknown *punk); + virtual HRESULT STDMETHODCALLTYPE EnumBands(UINT uBand, DWORD *pdwBandID); + virtual HRESULT STDMETHODCALLTYPE QueryBand(DWORD dwBandID, IDeskBand **ppstb, DWORD *pdwState, LPWSTR pszName, int cchName); + virtual HRESULT STDMETHODCALLTYPE SetBandState(DWORD dwBandID, DWORD dwMask, DWORD dwState); + virtual HRESULT STDMETHODCALLTYPE RemoveBand(DWORD dwBandID); + virtual HRESULT STDMETHODCALLTYPE GetBandObject(DWORD dwBandID, REFIID riid, VOID **ppv); + virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(const BANDSITEINFO *pbsinfo); + virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(BANDSITEINFO *pbsinfo); + +DECLARE_REGISTRY_RESOURCEID(IDR_MENUBANDSITE) +DECLARE_NOT_AGGREGATABLE(CMenuBandSite) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CMenuBandSite) + COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) + COM_INTERFACE_ENTRY_IID(IID_IDeskBarClient, IDeskBarClient) + COM_INTERFACE_ENTRY_IID(IID_IInputObject, IInputObject) + COM_INTERFACE_ENTRY_IID(IID_IInputObjectSite, IInputObjectSite) + COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler) + COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) + COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget) + COM_INTERFACE_ENTRY_IID(IID_IBandSite, IBandSite) +END_COM_MAP() +}; + +#endif // _STARTMENU_H_ diff --git a/reactos/dll/win32/shell32/stubs.cpp b/reactos/dll/win32/shell32/stubs.cpp new file mode 100644 index 00000000000..ab94da13761 --- /dev/null +++ b/reactos/dll/win32/shell32/stubs.cpp @@ -0,0 +1,1419 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: shell32.dll + * FILE: dll/win32/shell32/stubs.c + * PURPOSE: shell32.dll stubs + * PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org) + * NOTES: If you implement a function, remove it from this file + * UPDATE HISTORY: + * 03/02/2009 Created + */ + + +#include + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* + * Unimplemented + */ +EXTERN_C HLOCAL +WINAPI +SHLocalAlloc(UINT uFlags, SIZE_T uBytes) +{ + FIXME("SHLocalAlloc() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C HLOCAL +WINAPI +SHLocalFree(HLOCAL hMem) +{ + FIXME("SHLocalFree() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C HLOCAL +WINAPI +SHLocalReAlloc(HLOCAL hMem, + SIZE_T uBytes, + UINT uFlags) +{ + FIXME("SHLocalReAlloc() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C LPWSTR +WINAPI +AddCommasW(DWORD dwUnknown, LPWSTR lpNumber) +{ + LPCWSTR lpRetBuf = L"0"; + + FIXME("AddCommasW() stub\n"); + return const_cast(lpRetBuf); +} + +/* + * Unimplemented + */ +EXTERN_C LPWSTR +WINAPI +ShortSizeFormatW(LONGLONG llNumber) +{ + FIXME("ShortSizeFormatW() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHFindComputer(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + FIXME("SHFindComputer() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHLimitInputEdit(HWND hWnd, IShellFolder *psf) +{ + FIXME("SHLimitInputEdit() stub\n"); + return S_FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHLimitInputCombo(HWND hWnd, LPVOID lpUnknown) +{ + FIXME("SHLimitInputCombo() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +PathIsEqualOrSubFolder(LPWSTR lpFolder, LPWSTR lpSubFolder) +{ + FIXME("PathIsEqualOrSubFolder() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHCreateFileExtractIconW(LPCWSTR pszPath, + DWORD dwFileAttributes, + REFIID riid, + void **ppv) +{ + FIXME("SHCreateFileExtractIconW() stub\n"); + return E_FAIL; +} + +EXTERN_C HRESULT +WINAPI +SHGetUnreadMailCountW(HKEY hKeyUser, + LPCWSTR pszMailAddress, + DWORD *pdwCount, + FILETIME *pFileTime, + LPWSTR pszShellExecuteCommand, + int cchShellExecuteCommand) +{ + FIXME("SHGetUnreadMailCountW() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHSetUnreadMailCountW(LPCWSTR pszMailAddress, + DWORD dwCount, + LPCWSTR pszShellExecuteCommand) +{ + FIXME("SHSetUnreadMailCountW() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +CheckDiskSpace(VOID) +{ + FIXME("CheckDiskSpace() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +SHReValidateDarwinCache(VOID) +{ + FIXME("SHReValidateDarwinCache() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +CopyStreamUI(IStream *pSrc, IStream *pDst, IProgressDialog *pProgDlg) +{ + FIXME("CopyStreamUI() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C FILEDESCRIPTOR* +WINAPI +GetFileDescriptor(FILEGROUPDESCRIPTOR *pFileGroupDesc, BOOL bUnicode, INT iIndex, LPWSTR lpName) +{ + FIXME("GetFileDescriptor() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHIsTempDisplayMode(VOID) +{ + FIXME("SHIsTempDisplayMode() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C LONG +WINAPI +SHCreateSessionKey(REGSAM regSam, PHKEY phKey) +{ + FIXME("SHCreateSessionKey() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +MakeShellURLFromPathW(LPCWSTR lpPath, LPWSTR lpUrl, INT cchMax) +{ + FIXME("MakeShellURLFromPathW() stub\n"); + lpUrl = NULL; + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +MakeShellURLFromPathA(LPCSTR lpPath, LPSTR lpUrl, INT cchMax) +{ + FIXME("MakeShellURLFromPathA() stub\n"); + lpUrl = NULL; + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHParseDarwinIDFromCacheW(LPCWSTR lpUnknown1, LPWSTR lpUnknown2) +{ + FIXME("SHParseDarwinIDFromCacheW() stub\n"); + lpUnknown2 = NULL; + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHMultiFileProperties(IDataObject *pDataObject, DWORD dwFlags) +{ + FIXME("SHMultiFileProperties() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHCreatePropertyBag(REFIID refIId, LPVOID *lpUnknown) +{ + /* Call SHCreatePropertyBagOnMemory() from shlwapi.dll */ + FIXME("SHCreatePropertyBag() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHCopyMonikerToTemp(IMoniker *pMoniker, LPCWSTR lpInput, LPWSTR lpOutput, INT cchMax) +{ + /* Unimplemented in XP SP3 */ + TRACE("SHCopyMonikerToTemp() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HLOCAL +WINAPI +CheckWinIniForAssocs(VOID) +{ + FIXME("CheckWinIniForAssocs() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHGetSetFolderCustomSettingsW(LPSHFOLDERCUSTOMSETTINGSW pfcs, + LPCWSTR pszPath, + DWORD dwReadWrite) +{ + FIXME("SHGetSetFolderCustomSettingsW() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHGetSetFolderCustomSettingsA(LPSHFOLDERCUSTOMSETTINGSA pfcs, + LPCSTR pszPath, + DWORD dwReadWrite) +{ + FIXME("SHGetSetFolderCustomSettingsA() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHOpenPropSheetA(LPCSTR lpCaption, + HKEY hKeys[], + UINT uCount, + const CLSID *pClsID, + IDataObject *pDataObject, + IShellBrowser *pShellBrowser, + LPCSTR lpStartPage) +{ + FIXME("SHOpenPropSheetA() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHOpenPropSheetW(LPCWSTR lpCaption, + HKEY hKeys[], + UINT uCount, + const CLSID *pClsID, + IDataObject *pDataObject, + IShellBrowser *pShellBrowser, + LPCWSTR lpStartPage) +{ + FIXME("SHOpenPropSheetW() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +CDefFolderMenu_MergeMenu(HINSTANCE hInstance, + UINT uMainMerge, + UINT uPopupMerge, + LPQCMINFO lpQcmInfo) +{ + FIXME("CDefFolderMenu_MergeMenu() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +CDefFolderMenu_Create(LPITEMIDLIST pidlFolder, + HWND hwnd, + UINT uidl, + PCUITEMID_CHILD_ARRAY *apidl, + IShellFolder *psf, + LPFNDFMCALLBACK lpfn, + HKEY hProgID, + HKEY hBaseProgID, + IContextMenu **ppcm) +{ + FIXME("CDefFolderMenu_Create() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHChangeRegistrationReceive(LPVOID lpUnknown1, DWORD dwUnknown2) +{ + FIXME("SHChangeRegistrationReceive() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +SHWaitOp_Operate(LPVOID lpUnknown1, DWORD dwUnknown2) +{ + FIXME("SHWaitOp_Operate() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +SHChangeNotifyReceive(LONG lUnknown, UINT uUnknown, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + FIXME("SHChangeNotifyReceive() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +RealDriveTypeFlags(INT iDrive, BOOL bUnknown) +{ + FIXME("RealDriveTypeFlags() stub\n"); + return 1; +} + +/* + * Unimplemented + */ +EXTERN_C LPWSTR +WINAPI +StrRStrW(LPWSTR lpSrc, LPWSTR lpLast, LPWSTR lpSearch) +{ + FIXME("StrRStrW() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C LPWSTR +WINAPI +StrRStrA(LPSTR lpSrc, LPSTR lpLast, LPSTR lpSearch) +{ + FIXME("StrRStrA() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C LONG +WINAPI +ShellHookProc(INT iCode, WPARAM wParam, LPARAM lParam) +{ + /* Unimplemented in WinXP SP3 */ + TRACE("ShellHookProc() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +ShellExec_RunDLL(HWND hwnd, HINSTANCE hInstance, LPWSTR pszCmdLine, int nCmdShow) +{ + FIXME("ShellExec_RunDLL() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +ShellExec_RunDLLA(HWND hwnd, HINSTANCE hInstance, LPSTR pszCmdLine, int nCmdShow) +{ + FIXME("ShellExec_RunDLLA() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +ShellExec_RunDLLW(HWND hwnd, HINSTANCE hInstance, LPWSTR pszCmdLine, int nCmdShow) +{ + FIXME("ShellExec_RunDLLW() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SheShortenPathW(LPWSTR lpPath, BOOL bShorten) +{ + FIXME("SheShortenPathW() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SheShortenPathA(LPSTR lpPath, BOOL bShorten) +{ + FIXME("SheShortenPathA() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +SheSetCurDrive(INT iIndex) +{ + FIXME("SheSetCurDrive() stub\n"); + return 1; +} + +/* + * Unimplemented + */ +EXTERN_C LPWSTR +WINAPI +SheRemoveQuotesW(LPWSTR lpInput) +{ + FIXME("SheRemoveQuotesW() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C LPSTR +WINAPI +SheRemoveQuotesA(LPSTR lpInput) +{ + FIXME("SheRemoveQuotesA() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +SheGetPathOffsetW(LPWSTR lpPath) +{ + FIXME("SheGetPathOffsetW() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SheGetDirExW(LPWSTR lpDrive, + LPDWORD lpCurDirLen, + LPWSTR lpCurDir) +{ + FIXME("SheGetDirExW() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +SheGetCurDrive(VOID) +{ + FIXME("SheGetCurDrive() stub\n"); + return 1; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +SheFullPathW(LPWSTR lpFullName, DWORD dwPathSize, LPWSTR lpBuffer) +{ + FIXME("SheFullPathW() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +SheFullPathA(LPSTR lpFullName, DWORD dwPathSize, LPSTR lpBuffer) +{ + FIXME("SheFullPathA() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SheConvertPathW(LPWSTR lpCmd, LPWSTR lpFileName, UINT uCmdLen) +{ + FIXME("SheConvertPathW() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +SheChangeDirExW(LPWSTR lpDir) +{ + FIXME("SheChangeDirExW() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +SheChangeDirExA(LPSTR lpDir) +{ + FIXME("SheChangeDirExA() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHInvokePrinterCommandW(HWND hwnd, + UINT uAction, + LPCWSTR lpBuf1, + LPCWSTR lpBuf2, + BOOL fModal) +{ + FIXME("SHInvokePrinterCommandW() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHInvokePrinterCommandA(HWND hwnd, + UINT uAction, + LPCSTR lpBuf1, + LPCSTR lpBuf2, + BOOL fModal) +{ + FIXME("SHInvokePrinterCommandA() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHCreateQueryCancelAutoPlayMoniker(IMoniker **ppmoniker) +{ + FIXME("SHCreateQueryCancelAutoPlayMoniker() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHCreateProcessAsUserW(PSHCREATEPROCESSINFOW pscpi) +{ + FIXME("SHCreateProcessAsUserW() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHChangeNotifySuspendResume(BOOL bSuspend, + LPITEMIDLIST pidl, + BOOL bRecursive, + DWORD dwReserved) +{ + FIXME("SHChangeNotifySuspendResume() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +RegenerateUserEnvironment(LPVOID *lpUnknown, BOOL bUnknown) +{ + FIXME("RegenerateUserEnvironment() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C HINSTANCE +WINAPI +RealShellExecuteExA(HWND hwnd, + LPCSTR lpOperation, + LPCSTR lpFile, + LPCSTR lpParameters, + LPCSTR lpDirectory, + LPSTR lpReturn, + LPCSTR lpTitle, + LPSTR lpReserved, + WORD nShowCmd, + HANDLE *lpProcess, + DWORD dwFlags) +{ + FIXME("RealShellExecuteExA() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C HINSTANCE +WINAPI +RealShellExecuteExW(HWND hwnd, + LPCWSTR lpOperation, + LPCWSTR lpFile, + LPCWSTR lpParameters, + LPCWSTR lpDirectory, + LPWSTR lpReturn, + LPCWSTR lpTitle, + LPWSTR lpReserved, + WORD nShowCmd, + HANDLE *lpProcess, + DWORD dwFlags) +{ + FIXME("RealShellExecuteExW() stub\n"); + return NULL; +} + +/* + * Implemented + */ +EXTERN_C HINSTANCE +WINAPI +RealShellExecuteA(HWND hwnd, + LPCSTR lpOperation, + LPCSTR lpFile, + LPCSTR lpParameters, + LPCSTR lpDirectory, + LPSTR lpReturn, + LPCSTR lpTitle, + LPSTR lpReserved, + WORD nShowCmd, + HANDLE *lpProcess) +{ + return RealShellExecuteExA(hwnd, + lpOperation, + lpFile, + lpParameters, + lpDirectory, + lpReturn, + lpTitle, + lpReserved, + nShowCmd, + lpProcess, + 0); +} + +/* + * Implemented + */ +EXTERN_C HINSTANCE +WINAPI +RealShellExecuteW(HWND hwnd, + LPCWSTR lpOperation, + LPCWSTR lpFile, + LPCWSTR lpParameters, + LPCWSTR lpDirectory, + LPWSTR lpReturn, + LPCWSTR lpTitle, + LPWSTR lpReserved, + WORD nShowCmd, + HANDLE *lpProcess) +{ + return RealShellExecuteExW(hwnd, + lpOperation, + lpFile, + lpParameters, + lpDirectory, + lpReturn, + lpTitle, + lpReserved, + nShowCmd, + lpProcess, + 0); +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +PrintersGetCommand_RunDLL(HWND hwnd, HINSTANCE hInstance, LPWSTR pszCmdLine, int nCmdShow) +{ + FIXME("PrintersGetCommand_RunDLL() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +PrintersGetCommand_RunDLLA(HWND hwnd, HINSTANCE hInstance, LPSTR pszCmdLine, int nCmdShow) +{ + FIXME("PrintersGetCommand_RunDLLA() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +PrintersGetCommand_RunDLLW(HWND hwnd, HINSTANCE hInstance, LPWSTR pszCmdLine, int nCmdShow) +{ + FIXME("PrintersGetCommand_RunDLLW() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C IShellFolderViewCB* +WINAPI +SHGetShellFolderViewCB(HWND hwnd) +{ + FIXME("SHGetShellFolderViewCB() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +SHLookupIconIndexA(LPCSTR lpName, INT iIndex, UINT uFlags) +{ + FIXME("SHLookupIconIndexA() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +SHLookupIconIndexW(LPCWSTR lpName, INT iIndex, UINT uFlags) +{ + FIXME("SHLookupIconIndexW() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C HANDLE +WINAPI +PifMgr_OpenProperties(LPCWSTR lpAppPath, LPCWSTR lpPifPath, UINT hInfIndex, UINT options) +{ + FIXME("PifMgr_OpenProperties() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +PifMgr_GetProperties(HANDLE hHandle, LPCSTR lpName, LPVOID lpUnknown, INT iUnknown, UINT uUnknown) +{ + FIXME("PifMgr_GetProperties() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +PifMgr_SetProperties(HANDLE hHandle, LPCSTR lpName, LPCVOID lpUnknown, INT iUnknown, UINT uUnknown) +{ + FIXME("PifMgr_SetProperties() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHStartNetConnectionDialogA(HWND hwnd, + LPCSTR pszRemoteName, + DWORD dwType) +{ + FIXME("SHStartNetConnectionDialogA() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHStartNetConnectionDialogW(HWND hwnd, + LPCWSTR pszRemoteName, + DWORD dwType) +{ + FIXME("SHStartNetConnectionDialogW() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HANDLE +WINAPI +PifMgr_CloseProperties(HANDLE hHandle, UINT uUnknown) +{ + FIXME("PifMgr_CloseProperties() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +DAD_DragEnterEx2(HWND hwndTarget, + POINT ptStart, + IDataObject *pdtObject) +{ + FIXME("DAD_DragEnterEx2() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +IsSuspendAllowed(VOID) +{ + FIXME("IsSuspendAllowed() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C UINT +WINAPI +SHGetNetResource(LPVOID lpUnknown1, UINT iIndex, LPVOID lpUnknown2, UINT cchMax) +{ + FIXME("SHGetNetResource() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +DragQueryInfo(HDROP hDrop, DRAGINFO *pDragInfo) +{ + FIXME("DragQueryInfo() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C LPVOID +WINAPI +DDECreatePostNotify(LPVOID lpUnknown) +{ + FIXME("DDECreatePostNotify() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHIsBadInterfacePtr(LPVOID pv, UINT ucb) +{ + FIXME("SHIsBadInterfacePtr() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +Activate_RunDLL(DWORD dwProcessId, LPVOID lpUnused1, LPVOID lpUnused2, LPVOID lpUnused3) +{ + FIXME("Activate_RunDLL() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +AppCompat_RunDLLW(HWND hwnd, HINSTANCE hInstance, LPWSTR pszCmdLine, int nCmdShow) +{ + FIXME("AppCompat_RunDLLW() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +Control_RunDLLAsUserW(HWND hwnd, HINSTANCE hInstance, LPWSTR pszCmdLine, int nCmdShow) +{ + FIXME("Control_RunDLLAsUserW() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C UINT +WINAPI +DragQueryFileAorW(HDROP hDrop, UINT iIndex, LPWSTR lpFile, UINT ucb, BOOL bUnicode, BOOL bShorten) +{ + FIXME("DragQueryFileAorW() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C DWORD +WINAPI +SHNetConnectionDialog(HWND hwndOwner, + LPCWSTR lpstrRemoteName, + DWORD dwType) +{ + FIXME("SHNetConnectionDialog() stub\n"); + return ERROR_INVALID_PARAMETER; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +DAD_SetDragImageFromListView(HWND hwnd, POINT pt) +{ + FIXME("DAD_SetDragImageFromListView() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C void +WINAPI +SHHandleDiskFull(HWND hwndOwner, UINT uDrive) +{ + FIXME("SHHandleDiskFull() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +ILGetPseudoNameW(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, LPWSTR szStr, INT iUnknown) +{ + /* Unimplemented in WinXP SP3 */ + TRACE("ILGetPseudoNameW() stub\n"); + *szStr = 0; + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C VOID +WINAPI +SHGlobalDefect(DWORD dwUnknown) +{ + /* Unimplemented in WinXP SP3 */ + TRACE("SHGlobalDefect() stub\n"); +} + +/* + * Unimplemented + */ +EXTERN_C LPITEMIDLIST +WINAPI +Printers_GetPidl(LPCITEMIDLIST pidl, LPCWSTR lpName) +{ + FIXME("Printers_GetPidl() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +Int64ToString(LONGLONG llInt64, + LPWSTR lpOut, + UINT uSize, + BOOL bUseFormat, + NUMBERFMT *pNumberFormat, + DWORD dwNumberFlags) +{ + FIXME("Int64ToString() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C INT +WINAPI +LargeIntegerToString(LARGE_INTEGER *pLargeInt, + LPWSTR lpOut, + UINT uSize, + BOOL bUseFormat, + NUMBERFMT *pNumberFormat, + DWORD dwNumberFlags) +{ + FIXME("LargeIntegerToString() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C LONG +WINAPI +Printers_AddPrinterPropPages(LPVOID lpUnknown1, LPVOID lpUnknown2) +{ + FIXME("Printers_AddPrinterPropPages() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C WORD +WINAPI +ExtractIconResInfoA(HANDLE hHandle, + LPSTR lpFile, + WORD wIndex, + LPWORD lpSize, + LPHANDLE lpIcon) +{ + FIXME("ExtractIconResInfoA() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C WORD +WINAPI +ExtractIconResInfoW(HANDLE hHandle, + LPWSTR lpFile, + WORD wIndex, + LPWORD lpSize, + LPHANDLE lpIcon) +{ + FIXME("ExtractIconResInfoW() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C DWORD +WINAPI +ExtractVersionResource16W(LPWSTR lpName, LPHANDLE lpHandle) +{ + FIXME("ExtractVersionResource16W() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL* +WINAPI +FindExeDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + FIXME("FindExeDlgProc() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C HANDLE +WINAPI +InternalExtractIconListW(HANDLE hHandle, + LPWSTR lpFileName, + LPINT lpCount) +{ + FIXME("InternalExtractIconListW() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C HANDLE +WINAPI +InternalExtractIconListA(HANDLE hHandle, + LPSTR lpFileName, + LPINT lpCount) +{ + FIXME("InternalExtractIconListA() stub\n"); + return NULL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +FirstUserLogon(LPWSTR lpUnknown1, LPWSTR lpUnknown2) +{ + FIXME("FirstUserLogon() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHSetFolderPathA(int csidl, + HANDLE hToken, + DWORD dwFlags, + LPCSTR pszPath) +{ + FIXME("SHSetFolderPathA() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHSetFolderPathW(int csidl, + HANDLE hToken, + DWORD dwFlags, + LPCWSTR pszPath) +{ + FIXME("SHSetFolderPathW() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHGetUserPicturePathW(LPCWSTR lpPath, int csidl, LPVOID lpUnknown) +{ + FIXME("SHGetUserPicturePathW() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C HRESULT +WINAPI +SHSetUserPicturePathW(LPCWSTR lpPath, int csidl, LPVOID lpUnknown) +{ + FIXME("SHGetUserPicturePathA() stub\n"); + return E_FAIL; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHOpenEffectiveToken(LPVOID Token) +{ + FIXME("SHOpenEffectiveToken() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHTestTokenPrivilegeW(HANDLE hToken, LPDWORD ReturnLength) +{ + FIXME("SHTestTokenPrivilegeW() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHShouldShowWizards(LPVOID lpUnknown) +{ + FIXME("SHShouldShowWizards() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +PathIsSlowW(LPCWSTR pszFile, DWORD dwFileAttr) +{ + FIXME("PathIsSlowW() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +PathIsSlowA(LPCSTR pszFile, DWORD dwFileAttr) +{ + FIXME("PathIsSlowA() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C DWORD +WINAPI +SHGetUserDisplayName(LPWSTR lpName, PULONG puSize) +{ + FIXME("SHGetUserDisplayName() stub\n"); + wcscpy(lpName, L"UserName"); + return ERROR_SUCCESS; +} + +/* + * Unimplemented + */ +EXTERN_C DWORD +WINAPI +SHGetProcessDword(DWORD dwUnknown1, DWORD dwUnknown2) +{ + /* Unimplemented in WinXP SP3 */ + TRACE("SHGetProcessDword() stub\n"); + return 0; +} + +/* + * Unimplemented + */ +EXTERN_C BOOL +WINAPI +SHTestTokenMembership(HANDLE TokenHandle, ULONG SidToCheck) +{ + FIXME("SHTestTokenMembership() stub\n"); + return FALSE; +} + +/* + * Unimplemented + */ +EXTERN_C LPVOID +WINAPI +SHGetUserSessionId(HANDLE hHandle) +{ + FIXME("SHGetUserSessionId() stub\n"); + return NULL; +} diff --git a/reactos/dll/win32/shell32/systray.cpp b/reactos/dll/win32/shell32/systray.cpp new file mode 100644 index 00000000000..1ca8edfd431 --- /dev/null +++ b/reactos/dll/win32/shell32/systray.cpp @@ -0,0 +1,184 @@ +/* + * Systray handling + * + * Copyright 1999 Kai Morich + * Copyright 2004 Mike Hearn, for CodeWeavers + * Copyright 2005 Robert Shearman + * + * 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 + +WINE_DEFAULT_DEBUG_CHANNEL(systray); + +static const WCHAR classname[] = /* Shell_TrayWnd */ {'S','h','e','l','l','_','T','r','a','y','W','n','d','\0'}; + +/************************************************************************* + * Shell_NotifyIcon [SHELL32.296] + * Shell_NotifyIconA [SHELL32.297] + */ +BOOL WINAPI Shell_NotifyIconA(DWORD dwMessage, PNOTIFYICONDATAA pnid) +{ + NOTIFYICONDATAW nidW; + INT cbSize; + + /* Validate the cbSize as Windows XP does */ + if (pnid->cbSize != NOTIFYICONDATAA_V1_SIZE && + pnid->cbSize != NOTIFYICONDATAA_V2_SIZE && + pnid->cbSize != NOTIFYICONDATAA_V3_SIZE && + pnid->cbSize != sizeof(NOTIFYICONDATAA)) + { + WARN("Invalid cbSize (%d) - using only Win95 fields (size=%d)\n", + pnid->cbSize, NOTIFYICONDATAA_V1_SIZE); + cbSize = NOTIFYICONDATAA_V1_SIZE; + } + else + cbSize = pnid->cbSize; + + ZeroMemory(&nidW, sizeof(nidW)); + nidW.cbSize = sizeof(nidW); + nidW.hWnd = pnid->hWnd; + nidW.uID = pnid->uID; + nidW.uFlags = pnid->uFlags; + nidW.uCallbackMessage = pnid->uCallbackMessage; + nidW.hIcon = pnid->hIcon; + + /* szTip */ + if (pnid->uFlags & NIF_TIP) + MultiByteToWideChar(CP_ACP, 0, pnid->szTip, -1, nidW.szTip, sizeof(nidW.szTip)/sizeof(WCHAR)); + + if (cbSize >= NOTIFYICONDATAA_V2_SIZE) + { + nidW.dwState = pnid->dwState; + nidW.dwStateMask = pnid->dwStateMask; + + /* szInfo, szInfoTitle */ + if (pnid->uFlags & NIF_INFO) + { + MultiByteToWideChar(CP_ACP, 0, pnid->szInfo, -1, nidW.szInfo, sizeof(nidW.szInfo)/sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, pnid->szInfoTitle, -1, nidW.szInfoTitle, sizeof(nidW.szInfoTitle)/sizeof(WCHAR)); + } + + nidW.u.uTimeout = pnid->u.uTimeout; + nidW.dwInfoFlags = pnid->dwInfoFlags; + } + + if (cbSize >= NOTIFYICONDATAA_V3_SIZE) + nidW.guidItem = pnid->guidItem; + + if (cbSize >= sizeof(NOTIFYICONDATAA)) + nidW.hBalloonIcon = pnid->hBalloonIcon; + return Shell_NotifyIconW(dwMessage, &nidW); +} + +/************************************************************************* + * Shell_NotifyIconW [SHELL32.298] + */ +BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid) +{ + HWND tray; + COPYDATASTRUCT cds; + char *buffer = NULL; + BOOL ret; + + TRACE("dwMessage = %d, nid->cbSize=%d\n", dwMessage, nid->cbSize); + + /* Validate the cbSize so that WM_COPYDATA doesn't crash the application */ + if (nid->cbSize != NOTIFYICONDATAW_V1_SIZE && + nid->cbSize != NOTIFYICONDATAW_V2_SIZE && + nid->cbSize != NOTIFYICONDATAW_V3_SIZE && + nid->cbSize != sizeof(NOTIFYICONDATAW)) + { + NOTIFYICONDATAW newNid; + + WARN("Invalid cbSize (%d) - using only Win95 fields (size=%d)\n", + nid->cbSize, NOTIFYICONDATAW_V1_SIZE); + CopyMemory(&newNid, nid, NOTIFYICONDATAW_V1_SIZE); + newNid.cbSize = NOTIFYICONDATAW_V1_SIZE; + return Shell_NotifyIconW(dwMessage, &newNid); + } + + tray = FindWindowExW(0, NULL, classname, NULL); + if (!tray) return FALSE; + + cds.dwData = dwMessage; + + /* FIXME: if statement only needed because we don't support interprocess + * icon handles */ + if (nid->uFlags & NIF_ICON) + { + ICONINFO iconinfo; + BITMAP bmMask; + BITMAP bmColour; + LONG cbMaskBits; + LONG cbColourBits; + + if (!GetIconInfo(nid->hIcon, &iconinfo)) + goto noicon; + + if (!GetObjectW(iconinfo.hbmMask, sizeof(bmMask), &bmMask) || + !GetObjectW(iconinfo.hbmColor, sizeof(bmColour), &bmColour)) + { + DeleteObject(iconinfo.hbmMask); + DeleteObject(iconinfo.hbmColor); + goto noicon; + } + + cbMaskBits = (bmMask.bmPlanes * bmMask.bmWidth * bmMask.bmHeight * bmMask.bmBitsPixel) / 8; + cbColourBits = (bmColour.bmPlanes * bmColour.bmWidth * bmColour.bmHeight * bmColour.bmBitsPixel) / 8; + cds.cbData = nid->cbSize + 2*sizeof(BITMAP) + cbMaskBits + cbColourBits; + buffer = HeapAlloc(GetProcessHeap(), 0, cds.cbData); + if (!buffer) + { + DeleteObject(iconinfo.hbmMask); + DeleteObject(iconinfo.hbmColor); + return FALSE; + } + cds.lpData = buffer; + + memcpy(buffer, nid, nid->cbSize); + buffer += nid->cbSize; + memcpy(buffer, &bmMask, sizeof(bmMask)); + buffer += sizeof(bmMask); + memcpy(buffer, &bmColour, sizeof(bmColour)); + buffer += sizeof(bmColour); + GetBitmapBits(iconinfo.hbmMask, cbMaskBits, buffer); + buffer += cbMaskBits; + GetBitmapBits(iconinfo.hbmColor, cbColourBits, buffer); + + /* Reset pointer to allocated block so it can be freed later. + * Note that cds.lpData cannot be passed to HeapFree since it + * points to nid when no icon info is found. */ + buffer = cds.lpData; + + DeleteObject(iconinfo.hbmMask); + DeleteObject(iconinfo.hbmColor); + } + else + { +noicon: + cds.cbData = nid->cbSize; + cds.lpData = nid; + } + + ret = SendMessageW(tray, WM_COPYDATA, (WPARAM)nid->hWnd, (LPARAM)&cds); + + /* FIXME: if statement only needed because we don't support interprocess + * icon handles */ + HeapFree(GetProcessHeap(), 0, buffer); + + return ret; +} diff --git a/reactos/dll/win32/shell32/toolband.cpp b/reactos/dll/win32/shell32/toolband.cpp new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/toolband.h b/reactos/dll/win32/shell32/toolband.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/reactos/dll/win32/shell32/undocshell.h b/reactos/dll/win32/shell32/undocshell.h index f9ec7cdb5ce..735484d74df 100644 --- a/reactos/dll/win32/shell32/undocshell.h +++ b/reactos/dll/win32/shell32/undocshell.h @@ -79,6 +79,7 @@ BOOL WINAPI StrRetToStrNW(LPWSTR,DWORD,LPSTRRET,const ITEMIDLIST*); #define SHCNRF_RecursiveInterrupt 0x1000 /* Must be combined with SHCNRF_InterruptLevel */ #define SHCNRF_NewDelivery 0x8000 /* Messages use shared memory */ + /**************************************************************************** * Shell Common Dialogs */ @@ -133,30 +134,6 @@ DWORD WINAPI SHNetConnectionDialog( LPCWSTR lpstrRemoteName, DWORD dwType); -/**************************************************************************** - * Memory Routines - */ - -/* The Platform SDK's shlobj.h header defines similar functions with a - * leading underscore. However those are unusable because of the leading - * underscore, because they have an incorrect calling convention, and - * because these functions are not exported by name anyway. - */ -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); - /**************************************************************************** * Cabinet Window Messages */ diff --git a/reactos/include/ndk/rtlfuncs.h b/reactos/include/ndk/rtlfuncs.h index af07d1e79ae..6b185beae0f 100644 --- a/reactos/include/ndk/rtlfuncs.h +++ b/reactos/include/ndk/rtlfuncs.h @@ -3694,6 +3694,15 @@ RtlUnlockBootStatusData( ); #endif +#ifdef NTOS_MODE_USER +NTSYSAPI +NTSTATUS +NTAPI +RtlGUIDFromString( + IN PUNICODE_STRING GuidString, + OUT GUID *Guid); +#endif + #ifdef __cplusplus } #endif diff --git a/reactos/include/psdk/appmgmt.h b/reactos/include/psdk/appmgmt.h index 365be1d62c1..6050c650f30 100644 --- a/reactos/include/psdk/appmgmt.h +++ b/reactos/include/psdk/appmgmt.h @@ -19,6 +19,10 @@ #ifndef _APPMGMT_H #define _APPMGMT_H +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + typedef struct _MANAGEDAPPLICATION { LPWSTR pszPackageName; @@ -42,4 +46,8 @@ typedef struct _MANAGEDAPPLICATION DWORD WINAPI CommandLineFromMsiDescriptor(WCHAR*,WCHAR*,DWORD*); DWORD WINAPI GetManagedApplications(GUID*,DWORD,DWORD,LPDWORD,PMANAGEDAPPLICATION*); +#ifdef __cplusplus +} /* extern "C" */ +#endif /* defined(__cplusplus) */ + #endif /* _APPMGMT_H */ diff --git a/reactos/include/psdk/shlguid.h b/reactos/include/psdk/shlguid.h index a2f0a91022f..5f50fba422f 100644 --- a/reactos/include/psdk/shlguid.h +++ b/reactos/include/psdk/shlguid.h @@ -57,27 +57,26 @@ DEFINE_GUID(IID_IObjMgr, 0x00BB2761L,0x6A77,0x11D0,0xA5,0x35,0x00,0xC0,0x4F,0x DEFINE_GUID(IID_IProgressDialog, 0xEBBC7C04,0x315E,0x11D2,0xB6,0x2F,0x00,0x60,0x97,0xDF,0x5B,0xD4); -#ifndef __GNUC__ /* avoid duplicate definitions with shobjidl.h (FIXME) */ -DEFINE_GUID(IID_IDockingWindow, 0x012dd920L, 0x7B26, 0x11D0, 0x8C, 0xA9, 0x00, 0xA0, 0xC9, 0x2D, 0xBF, 0xE8); -DEFINE_OLEGUID(IID_IShellPropSheetExt, 0x000214E9L, 0, 0); -DEFINE_OLEGUID(IID_IExtractIconA, 0x000214EBL, 0, 0); -DEFINE_OLEGUID(IID_IExtractIconW, 0x000214FAL, 0, 0); -DEFINE_OLEGUID(IID_IContextMenu, 0x000214E4L, 0, 0); -DEFINE_OLEGUID(IID_IContextMenu2, 0x000214F4L, 0, 0); -DEFINE_OLEGUID(IID_ICommDlgBrowser, 0x000214F1L, 0, 0); -DEFINE_OLEGUID(IID_IShellBrowser, 0x000214E2L, 0, 0); -DEFINE_OLEGUID(IID_IShellView, 0x000214E3L, 0, 0); -DEFINE_OLEGUID(IID_IShellFolder, 0x000214E6L, 0, 0); -DEFINE_OLEGUID(IID_IShellExtInit, 0x000214E8L, 0, 0); -DEFINE_OLEGUID(IID_IPersistFolder, 0x000214EAL, 0, 0); -DEFINE_OLEGUID(IID_IShellLinkA, 0x000214EEL, 0, 0); -DEFINE_OLEGUID(IID_IEnumIDList, 0x000214F2L, 0, 0); -DEFINE_OLEGUID(IID_IShellLinkW, 0x000214F9L, 0, 0); -DEFINE_OLEGUID(IID_IShellExecuteHookA, 0x000214F5L, 0, 0); -DEFINE_OLEGUID(IID_IShellExecuteHookW, 0x000214FBL, 0, 0); -DEFINE_OLEGUID(IID_INewShortcutHookA, 0x000214E1L, 0, 0); -DEFINE_OLEGUID(IID_INewShortcutHookW, 0x000214F7L, 0, 0); -#endif +/* avoid duplicate definitions with shobjidl.h (FIXME) */ +/* DEFINE_GUID(IID_IDockingWindow, 0x012dd920L, 0x7B26, 0x11D0, 0x8C, 0xA9, 0x00, 0xA0, 0xC9, 0x2D, 0xBF, 0xE8); */ +/* DEFINE_OLEGUID(IID_IShellPropSheetExt, 0x000214E9L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IExtractIconA, 0x000214EBL, 0, 0); */ +/* DEFINE_OLEGUID(IID_IExtractIconW, 0x000214FAL, 0, 0); */ +/* DEFINE_OLEGUID(IID_IContextMenu, 0x000214E4L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IContextMenu2, 0x000214F4L, 0, 0); */ +/* DEFINE_OLEGUID(IID_ICommDlgBrowser, 0x000214F1L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IShellBrowser, 0x000214E2L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IShellView, 0x000214E3L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IShellFolder, 0x000214E6L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IShellExtInit, 0x000214E8L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IPersistFolder, 0x000214EAL, 0, 0); */ +/* DEFINE_OLEGUID(IID_IShellLinkA, 0x000214EEL, 0, 0); */ +/* DEFINE_OLEGUID(IID_IEnumIDList, 0x000214F2L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IShellLinkW, 0x000214F9L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IShellExecuteHookA, 0x000214F5L, 0, 0); */ +/* DEFINE_OLEGUID(IID_IShellExecuteHookW, 0x000214FBL, 0, 0); */ +/* DEFINE_OLEGUID(IID_INewShortcutHookA, 0x000214E1L, 0, 0); */ +/* DEFINE_OLEGUID(IID_INewShortcutHookW, 0x000214F7L, 0, 0); */ DEFINE_GUID(CLSID_CUrlHistory, 0x3c374a40, 0xbae4, 0x11cf, 0xbf, 0x7d, 0x00, 0xaa, 0x00, 0x69, 0x46, 0xee); #define SID_SUrlHistory CLSID_CUrlHistory @@ -134,8 +133,6 @@ DEFINE_GUID(CLSID_ACListISF, 0x03c036f1, 0xa186, 0x11d0, 0x82, 0x4a, 0x00, DEFINE_GUID(CLSID_ProgressDialog, 0xf8383852, 0xfcd3, 0x11d1, 0xa6, 0xb9, 0x0, 0x60, 0x97, 0xdf, 0x5b, 0xd4); -DEFINE_GUID(CLSID_ShellItem, 0x2fe352ea, 0xfd1f, 0x11d2, 0xb1, 0xf4, 0x00, 0xc0, 0x4f, 0x8e, 0xeb, 0x3e); - #define PSGUID_SHELLDETAILS {0x28636aa6, 0x953d, 0x11d2, 0xb5, 0xd6, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0} DEFINE_GUID(FMTID_ShellDetails, 0x28636aa6, 0x953d, 0x11d2, 0xb5, 0xd6, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0); #define PID_FINDDATA 0 diff --git a/reactos/include/psdk/shlguid_undoc.h b/reactos/include/psdk/shlguid_undoc.h index b55b90d81ed..d2c85227053 100644 --- a/reactos/include/psdk/shlguid_undoc.h +++ b/reactos/include/psdk/shlguid_undoc.h @@ -1,4 +1,24 @@ +/* + * Copyright (C) 1999 Juergen Schmied + * Copyright (C) 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 + */ +#ifndef __SHLGUID_UNDOC_H +#define __SHLGUID_UNDOC_H DEFINE_GUID(CLSID_RebarBandSite, 0xECD4FC4D, 0x521C, 0x11D0, 0xB7, 0x92, 0x00, 0xA0, 0xC9, 0x03, 0x12, 0xE1); DEFINE_GUID(CLSID_BandSiteMenu, 0xECD4FC4E, 0x521C, 0x11D0, 0xB7, 0x92, 0x00, 0xA0, 0xC9, 0x03, 0x12, 0xE1); DEFINE_GUID(IID_IBandSiteHelper, 0xD1E7AFEA, 0x6A2E, 0x11D0, 0x8C, 0x78, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xB4); @@ -11,60 +31,74 @@ DEFINE_GUID(IID_IShellMenuAcc, 0xFAF6FE96, 0xCE5E, 0x11D1, 0x83, 0x71, DEFINE_GUID(IID_IShellBrowserService, 0x1307EE17, 0xEA83, 0x49EB, 0x96, 0xB2, 0x3A, 0x28, 0xE2, 0xD7, 0x04, 0x8A); //DEFINE_GUID(IID_IFolderView, 0xCDE725B0, 0xCCC9, 0x4519, 0x91, 0x7E, 0x32, 0x5D, 0x72, 0xFA, 0xB4, 0xCE); -DEFINE_GUID(SID_SProxyBrowser, 0x20C46561, 0x8491, 0x11CF, 0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85); +DEFINE_GUID(SID_SProxyBrowser, 0x20C46561, 0x8491, 0x11CF, 0x96, 0x0C, 0x00, 0x80, 0xC7, 0xF4, 0xEE, 0x85); // this class lives in shell32.dll -DEFINE_GUID(IID_IGlobalFolderSettings, 0xEF8AD2D3, 0xAE36, 0x11D1, 0xB2, 0xD2, 0x00, 0x60, 0x97, 0xDF, 0x8C, 0x11); -DEFINE_GUID(CLSID_GlobalFolderSettings, 0xEF8AD2D1, 0xAE36, 0x11D1, 0xB2, 0xD2, 0x00, 0x60, 0x97, 0xDF, 0x8C, 0x11); -DEFINE_GUID(IID_IRegTreeOptions, 0xAF4F6511, 0xF982, 0x11D0, 0x85, 0x95, 0x00, 0xAA, 0x00, 0x4C, 0xD6, 0xD8); -DEFINE_GUID(CLSID_CRegTreeOptions, 0xAF4F6510, 0xF982, 0x11D0, 0x85, 0x95, 0x00, 0xAA, 0x00, 0x4C, 0xD6, 0xD8); -DEFINE_GUID(IID_IExplorerToolbar, 0x8455F0C1, 0x158F, 0x11D0, 0x89, 0xAE, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xAC); +DEFINE_GUID(IID_IGlobalFolderSettings, 0xEF8AD2D3, 0xAE36, 0x11D1, 0xB2, 0xD2, 0x00, 0x60, 0x97, 0xDF, 0x8C, 0x11); +DEFINE_GUID(CLSID_GlobalFolderSettings, 0xEF8AD2D1, 0xAE36, 0x11D1, 0xB2, 0xD2, 0x00, 0x60, 0x97, 0xDF, 0x8C, 0x11); +DEFINE_GUID(IID_IRegTreeOptions, 0xAF4F6511, 0xF982, 0x11D0, 0x85, 0x95, 0x00, 0xAA, 0x00, 0x4C, 0xD6, 0xD8); +DEFINE_GUID(CLSID_CRegTreeOptions, 0xAF4F6510, 0xF982, 0x11D0, 0x85, 0x95, 0x00, 0xAA, 0x00, 0x4C, 0xD6, 0xD8); +DEFINE_GUID(IID_IExplorerToolbar, 0x8455F0C1, 0x158F, 0x11D0, 0x89, 0xAE, 0x00, 0xA0, 0xC9, 0x0A, 0x90, 0xAC); // not registered, lives in browseui.dll -DEFINE_GUID(CLSID_BrowserBar, 0x9581015C, 0xD08E, 0x11D0, 0x8D, 0x36, 0x00, 0xA0, 0xC9, 0x2D, 0xBF, 0xE8); +DEFINE_GUID(CLSID_BrowserBar, 0x9581015C, 0xD08E, 0x11D0, 0x8D, 0x36, 0x00, 0xA0, 0xC9, 0x2D, 0xBF, 0xE8); -DEFINE_GUID(CGID_DefViewFrame, 0x710EB7A1, 0x45ED, 0x11D0, 0x92, 0x4A, 0x00, 0x20, 0xAF, 0xC7, 0xAC, 0x4D); +DEFINE_GUID(CGID_DefViewFrame, 0x710EB7A1, 0x45ED, 0x11D0, 0x92, 0x4A, 0x00, 0x20, 0xAF, 0xC7, 0xAC, 0x4D); // browseui.dll -DEFINE_GUID(CLSID_SH_AddressBand, 0x01E04581, 0x4EEE, 0x11D0, 0xBF, 0xE9, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); -DEFINE_GUID(CLSID_AddressEditBox, 0xA08C11D2, 0xA228, 0x11D0, 0x82, 0x5B, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); -DEFINE_GUID(IID_IAddressEditBox, 0xA08C11D1, 0xA228, 0x11D0, 0x82, 0x5B, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); +DEFINE_GUID(CLSID_SH_AddressBand, 0x01E04581, 0x4EEE, 0x11D0, 0xBF, 0xE9, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); +DEFINE_GUID(CLSID_AddressEditBox, 0xA08C11D2, 0xA228, 0x11D0, 0x82, 0x5B, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); +DEFINE_GUID(IID_IAddressEditBox, 0xA08C11D1, 0xA228, 0x11D0, 0x82, 0x5B, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); -DEFINE_GUID(IID_IAddressBand, 0x106E86E1, 0x52B5, 0x11D0, 0xBF, 0xED, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); -DEFINE_GUID(CLSID_BrandBand, 0x22BF0C20, 0x6DA7, 0x11D0, 0xB3, 0x73, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0x38); -DEFINE_GUID(SID_SBrandBand, 0x82A62DE8, 0x32AC, 0x4E4A, 0x99, 0x35, 0x90, 0x46, 0xC3, 0x78, 0xCF, 0x90); -DEFINE_GUID(CLSID_InternetToolbar, 0x5E6AB780, 0x7743, 0x11CF, 0xA1, 0x2B, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37); +DEFINE_GUID(IID_IAddressBand, 0x106E86E1, 0x52B5, 0x11D0, 0xBF, 0xED, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); +DEFINE_GUID(CLSID_BrandBand, 0x22BF0C20, 0x6DA7, 0x11D0, 0xB3, 0x73, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0x38); +DEFINE_GUID(SID_SBrandBand, 0x82A62DE8, 0x32AC, 0x4E4A, 0x99, 0x35, 0x90, 0x46, 0xC3, 0x78, 0xCF, 0x90); +DEFINE_GUID(CLSID_InternetToolbar, 0x5E6AB780, 0x7743, 0x11CF, 0xA1, 0x2B, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37); -DEFINE_GUID(CGID_PrivCITCommands, 0x67077B95, 0x4F9D, 0x11D0, 0xB8, 0x84, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04); -DEFINE_GUID(CGID_Theater, 0x0F12079C, 0xC193, 0x11D0, 0x8D, 0x49, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0x61); -DEFINE_GUID(CGID_ShellBrowser, 0x3531F060, 0x22B3, 0x11D0, 0x96, 0x9E, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04); +DEFINE_GUID(CGID_PrivCITCommands, 0x67077B95, 0x4F9D, 0x11D0, 0xB8, 0x84, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04); +DEFINE_GUID(CGID_Theater, 0x0F12079C, 0xC193, 0x11D0, 0x8D, 0x49, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0x61); +DEFINE_GUID(CGID_ShellBrowser, 0x3531F060, 0x22B3, 0x11D0, 0x96, 0x9E, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04); -DEFINE_GUID(CLSID_SearchBand, 0x2559A1F0, 0x21D7, 0x11D4, 0xBD, 0xAF, 0x00, 0xC0, 0x4F, 0x60, 0xB9, 0xF0); -DEFINE_GUID(CLSID_TipOfTheDayBand, 0x4D5C8C25, 0xD075, 0x11D0, 0xB4, 0x16, 0x00, 0xC0, 0x4F, 0xB9, 0x03, 0x76); -DEFINE_GUID(CLSID_DiscussBand, 0xBDEADE7F, 0xC265, 0x11D0, 0xBC, 0xED, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x0F); -DEFINE_GUID(CLSID_SH_FavBand, 0xEFA24E61, 0xB078, 0x11D0, 0x89, 0xE4, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E); -DEFINE_GUID(CLSID_SH_HistBand, 0xEFA24E62, 0xB078, 0x11D0, 0x89, 0xE4, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E); -DEFINE_GUID(CLSID_ExplorerBand, 0xEFA24E64, 0xB078, 0x11D0, 0x89, 0xE4, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E); -DEFINE_GUID(CLSID_SH_SearchBand, 0x21569614, 0xB795, 0x46B1, 0x85, 0xF4, 0xE7, 0x37, 0xA8, 0xDC, 0x09, 0xAD); -DEFINE_GUID(CLSID_FileSearchBand, 0xC4EE31F3, 0x4768, 0x11D2, 0x5C, 0xBE, 0x00, 0xA0, 0xC9, 0xA8, 0x3D, 0xA1); +DEFINE_GUID(CLSID_SearchBand, 0x2559A1F0, 0x21D7, 0x11D4, 0xBD, 0xAF, 0x00, 0xC0, 0x4F, 0x60, 0xB9, 0xF0); +DEFINE_GUID(CLSID_TipOfTheDayBand, 0x4D5C8C25, 0xD075, 0x11D0, 0xB4, 0x16, 0x00, 0xC0, 0x4F, 0xB9, 0x03, 0x76); +DEFINE_GUID(CLSID_DiscussBand, 0xBDEADE7F, 0xC265, 0x11D0, 0xBC, 0xED, 0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x0F); +DEFINE_GUID(CLSID_SH_FavBand, 0xEFA24E61, 0xB078, 0x11D0, 0x89, 0xE4, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E); +DEFINE_GUID(CLSID_SH_HistBand, 0xEFA24E62, 0xB078, 0x11D0, 0x89, 0xE4, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E); +DEFINE_GUID(CLSID_ExplorerBand, 0xEFA24E64, 0xB078, 0x11D0, 0x89, 0xE4, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E); +DEFINE_GUID(CLSID_SH_SearchBand, 0x21569614, 0xB795, 0x46B1, 0x85, 0xF4, 0xE7, 0x37, 0xA8, 0xDC, 0x09, 0xAD); +DEFINE_GUID(CLSID_FileSearchBand, 0xC4EE31F3, 0x4768, 0x11D2, 0x5C, 0xBE, 0x00, 0xA0, 0xC9, 0xA8, 0x3D, 0xA1); // missing ResearchBand -DEFINE_GUID(IID_IBandNavigate, 0x3697C30B, 0xCD88, 0x11D0, 0x8A, 0x3E, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E); -DEFINE_GUID(IID_INamespaceProxy, 0xCF1609EC, 0xFA4B, 0x4818, 0xAB, 0x01, 0x55, 0x64, 0x33, 0x67, 0xE6, 0x6D); -DEFINE_GUID(IID_IBandProxy, 0x208CE801, 0x754B, 0x11D0, 0x80, 0xCA, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); -DEFINE_GUID(CLSID_BandProxy, 0xF61FFEC1, 0x754F, 0x11D0, 0x80, 0xCA, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); -DEFINE_GUID(SID_IBandProxy, 0x80243AC1, 0x0569, 0x11D1, 0xA7, 0xAE, 0x00, 0x60, 0x97, 0xDF, 0x5B, 0xD4); -DEFINE_GUID(CLSID_ShellSearchExt, 0x169A0691, 0x8DF9, 0x11D1, 0xA1, 0xC4, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13); +DEFINE_GUID(IID_IBandNavigate, 0x3697C30B, 0xCD88, 0x11D0, 0x8A, 0x3E, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E); +DEFINE_GUID(IID_INamespaceProxy, 0xCF1609EC, 0xFA4B, 0x4818, 0xAB, 0x01, 0x55, 0x64, 0x33, 0x67, 0xE6, 0x6D); +DEFINE_GUID(IID_IBandProxy, 0x208CE801, 0x754B, 0x11D0, 0x80, 0xCA, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); +DEFINE_GUID(CLSID_BandProxy, 0xF61FFEC1, 0x754F, 0x11D0, 0x80, 0xCA, 0x00, 0xAA, 0x00, 0x5B, 0x43, 0x83); +DEFINE_GUID(SID_IBandProxy, 0x80243AC1, 0x0569, 0x11D1, 0xA7, 0xAE, 0x00, 0x60, 0x97, 0xDF, 0x5B, 0xD4); +DEFINE_GUID(CLSID_ShellSearchExt, 0x169A0691, 0x8DF9, 0x11D1, 0xA1, 0xC4, 0x00, 0xC0, 0x4F, 0xD7, 0x5D, 0x13); -DEFINE_GUID(CLSID_CommonButtons, 0x1E79697E, 0x9CC5, 0x11D1, 0xA8, 0x3F, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0x61); +DEFINE_GUID(CLSID_CommonButtons, 0x1E79697E, 0x9CC5, 0x11D1, 0xA8, 0x3F, 0x00, 0xC0, 0x4F, 0xC9, 0x9D, 0x61); -DEFINE_GUID(CGID_BrandCmdGroup, 0x25019D8C, 0x9EE0, 0x45C0, 0x88, 0x3B, 0x97, 0x2D, 0x48, 0x32, 0x5E, 0x18); +DEFINE_GUID(CGID_BrandCmdGroup, 0x25019D8C, 0x9EE0, 0x45C0, 0x88, 0x3B, 0x97, 0x2D, 0x48, 0x32, 0x5E, 0x18); -DEFINE_GUID(IID_INSCTree, 0x43A8F463, 0x4222, 0x11D2, 0xB6, 0x41, 0x00, 0x60, 0x97, 0xDF, 0x5B, 0xD4); -DEFINE_GUID(IID_INSCTree2, 0x801C1AD5, 0xC47C, 0x428C, 0x97, 0xAF, 0xE9, 0x91, 0xE4, 0x85, 0x7D, 0x97); +DEFINE_GUID(IID_INSCTree, 0x43A8F463, 0x4222, 0x11D2, 0xB6, 0x41, 0x00, 0x60, 0x97, 0xDF, 0x5B, 0xD4); +DEFINE_GUID(IID_INSCTree2, 0x801C1AD5, 0xC47C, 0x428C, 0x97, 0xAF, 0xE9, 0x91, 0xE4, 0x85, 0x7D, 0x97); -DEFINE_GUID(IID_IInitializeObject, 0x4622AD16, 0xFF23, 0x11D0, 0x8D, 0x34, 0x00, 0xA0, 0xC9, 0x0F, 0x27, 0x19); -DEFINE_GUID(IID_IBanneredBar, 0x596A9A94, 0x013E, 0x11D1, 0x8D, 0x34, 0x00, 0xA0, 0xC9, 0x0F, 0x27, 0x19); +DEFINE_GUID(IID_IInitializeObject, 0x4622AD16, 0xFF23, 0x11D0, 0x8D, 0x34, 0x00, 0xA0, 0xC9, 0x0F, 0x27, 0x19); +DEFINE_GUID(IID_IBanneredBar, 0x596A9A94, 0x013E, 0x11D1, 0x8D, 0x34, 0x00, 0xA0, 0xC9, 0x0F, 0x27, 0x19); + +DEFINE_GUID(CLSID_StartMenu, 0x4622AD11, 0xFF23, 0x11D0, 0x8D, 0x34, 0x00, 0xA0, 0xC9, 0x0F, 0x27, 0x19); +DEFINE_GUID(CLSID_MenuBandSite, 0xE13EF4E4, 0xD2F2, 0x11D0, 0x98, 0x16, 0x00, 0xC0, 0x4F, 0xD9, 0x19, 0x72); +DEFINE_GUID(SHELL32_AdvtShortcutProduct, 0x9DB1186F, 0x40DF, 0x11D1, 0xAA, 0x8C, 0x00, 0xC0, 0x4F, 0xB6, 0x78, 0x63); +DEFINE_GUID(SHELL32_AdvtShortcutComponent, 0x9DB1186E, 0x40DF, 0x11D1, 0xAA, 0x8C, 0x00, 0xC0, 0x4F, 0xB6, 0x78, 0x63); +DEFINE_GUID(CLSID_OpenWithMenu, 0x09799AFB, 0xAD67, 0x11D1, 0xAB, 0xCD, 0x00, 0xC0, 0x4F, 0xC3, 0x09, 0x36); + +DEFINE_GUID(CLSID_FontsFolderShortcut, 0xD20EA4E1, 0x3957, 0x11D2, 0xA4, 0x0B, 0x0C, 0x50, 0x20, 0x52, 0x41, 0x52); +DEFINE_GUID(CLSID_AdminFolderShortcut, 0xD20EA4E1, 0x3957, 0x11D2, 0xA4, 0x0B, 0x0C, 0x50, 0x20, 0x52, 0x41, 0x53); + +DEFINE_GUID(CLSID_FolderOptions, 0x6DFD7C5C, 0x2451, 0x11D3, 0xA2, 0x99, 0x00, 0xC0, 0x4F, 0x8E, 0xF6, 0xAF); + +// In theory, this is documented. But until I see an SDK header that defines it, it will be treated as undocumented... +DEFINE_GUID(CLSID_ShellItem, 0x2fe352ea, 0xfd1f, 0x11d2, 0xb1, 0xf4, 0x00, 0xc0, 0x4f, 0x8e, 0xeb, 0x3e); #define CGID_IExplorerToolbar IID_IExplorerToolbar #define SID_IExplorerToolbar IID_IExplorerToolbar @@ -74,4 +108,7 @@ DEFINE_GUID(IID_IBanneredBar, 0x596A9A94, 0x013E, 0x11D1, 0x8D, 0x34, #define CGID_MenuBand CLSID_MenuBand #define SID_STravelLogCursor IID_ITravelLogStg #define SID_IBandSite IID_IBandSite +#define SID_IFolderView IID_IFolderView +#define SID_IShellBrowser IID_IShellBrowser +#endif // __SHLGUID_UNDOC_H diff --git a/reactos/include/psdk/shlobj.h b/reactos/include/psdk/shlobj.h index b5f6d3673ff..881408bb1b6 100644 --- a/reactos/include/psdk/shlobj.h +++ b/reactos/include/psdk/shlobj.h @@ -97,6 +97,7 @@ DWORD WINAPI SHFormatDrive(HWND,UINT,UINT,UINT); void WINAPI SHFree(LPVOID); BOOL WINAPI GetFileNameFromBrowse(HWND,LPWSTR,UINT,LPCWSTR,LPCWSTR,LPCWSTR,LPCWSTR); HRESULT WINAPI SHGetInstanceExplorer(IUnknown**); +VOID WINAPI SHSetInstanceExplorer (IUnknown*); HRESULT WINAPI SHGetFolderPathAndSubDirA(HWND,int,HANDLE,DWORD,LPCSTR,LPSTR); HRESULT WINAPI SHGetFolderPathAndSubDirW(HWND,int,HANDLE,DWORD,LPCWSTR,LPWSTR); #define SHGetFolderPathAndSubDir WINELIB_NAME_AW(SHGetFolderPathAndSubDir); @@ -1458,7 +1459,7 @@ typedef struct _SHChangeProductKeyAsIDList { } SHChangeProductKeyAsIDList, *LPSHChangeProductKeyAsIDList; ULONG WINAPI SHChangeNotifyRegister(HWND hwnd, int fSources, LONG fEvents, UINT wMsg, - int cEntries, const SHChangeNotifyEntry *pshcne); + int cEntries, SHChangeNotifyEntry *pshcne); BOOL WINAPI SHChangeNotifyDeregister(ULONG ulID); HANDLE WINAPI SHChangeNotification_Lock(HANDLE hChangeNotification, DWORD dwProcessId, LPITEMIDLIST **pppidl, LONG *plEvent); @@ -1469,7 +1470,7 @@ HRESULT WINAPI SHGetRealIDL(IShellFolder *psf, LPCITEMIDLIST pidlSimple, LPITEMI /**************************************************************************** * SHCreateDirectory API */ -DWORD WINAPI SHCreateDirectory(HWND, LPCWSTR); +int WINAPI SHCreateDirectory(HWND, LPCWSTR); int WINAPI SHCreateDirectoryExA(HWND, LPCSTR, LPSECURITY_ATTRIBUTES); int WINAPI SHCreateDirectoryExW(HWND, LPCWSTR, LPSECURITY_ATTRIBUTES); #define SHCreateDirectoryEx WINELIB_NAME_AW(SHCreateDirectoryEx) @@ -1835,6 +1836,17 @@ DECLARE_INTERFACE_(IShellIconOverlayIdentifier, IUnknown) STDMETHOD (GetPriority)(THIS_ int * pIPriority) PURE; }; +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IShellIconOverlayIdentifier_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IShellIconOverlayIdentifier_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IShellIconOverlayIdentifier_Release(p) (p)->lpVtbl->Release(p) +/*** IShellIconOverlayIdentifier methods ***/ +#define IShellIconOverlayIdentifier_IsMemberOf(p,a,b) (p)->lpVtbl->IsMemberOf(p,a,b) +#define IShellIconOverlayIdentifier_GetOverlayInfo(p,a,b,c,d) (p)->lpVtbl->GetOverlayInfo(p,a,b,c,d) +#define IShellIconOverlayIdentifier_GetPriority(p,a) (p)->lpVtbl->GetPriority(p,a) +#endif + #define ISIOI_ICONFILE 0x00000001 #define ISIOI_ICONINDEX 0x00000002 @@ -1856,12 +1868,12 @@ DECLARE_INTERFACE_(IShellIconOverlayIdentifier, IUnknown) /***************************************************************************** * IDockingWindowSite interface */ -#define INTERFACE IDockingWindowSite +#define INTERFACE IDockingWindowSite DECLARE_INTERFACE_(IDockingWindowSite, IOleWindow) { // *** IUnknown methods *** STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppv) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; STDMETHOD_(ULONG,Release)(THIS) PURE; // *** IOleWindow methods *** @@ -1875,6 +1887,60 @@ DECLARE_INTERFACE_(IDockingWindowSite, IOleWindow) }; #undef INTERFACE +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IDockingWindowSite_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDockingWindowSite_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDockingWindowSite_Release(p) (p)->lpVtbl->Release(p) +/*** IOleWindow methods ***/ +#define IDockingWindowSite_GetWindow(p,a) (p)->lpVtbl->GetWindow(p,a) +#define IDockingWindowSite_ContextSensitiveHelp(p,a) (p)->lpVtbl->ContextSensitiveHelp(p,a) +/*** IDockingWindowSite methods ***/ +#define IDockingWindowSite_GetBorderDW(p,a,b) (p)->lpVtbl->GetBorderDW(p,a,b) +#define IDockingWindowSite_RequestBorderSpaceDW(p,a,b) (p)->lpVtbl->RequestBorderSpaceDW(p,a,b) +#define IDockingWindowSite_SetBorderSpaceDW(p,a,b) (p)->lpVtbl->SetBorderSpaceDW(p,a,b) +#endif + +/***************************************************************************** + * IShellTaskScheduler interface + */ +#define REFTASKOWNERID REFGUID + +#define INTERFACE IShellTaskScheduler +DECLARE_INTERFACE_(IShellTaskScheduler, IUnknown) +{ + // *** IUnknown methods *** + STDMETHOD(QueryInterface)(THIS_ REFIID riid, void **ppv) PURE; + STDMETHOD_(ULONG, AddRef)(THIS) PURE; + STDMETHOD_(ULONG, Release)(THIS) PURE; + + // *** IShellTaskScheduler methods *** + STDMETHOD(AddTask)(THIS_ IRunnableTask *pTask, REFTASKOWNERID rtoid, DWORD_PTR lParam, DWORD dwPriority) PURE; + STDMETHOD(RemoveTasks)(THIS_ REFTASKOWNERID rtoid, DWORD_PTR lParam, BOOL fWaitIfRunning) PURE; + STDMETHOD_(UINT, CountTasks)(THIS_ REFTASKOWNERID rtoid) PURE; + STDMETHOD(Status)(THIS_ DWORD dwReleaseStatus, DWORD dwThreadTimeout) PURE; +}; +#undef INTERFACE + +#if !defined(__cplusplus) || defined(CINTERFACE) +/*** IUnknown methods ***/ +#define IShellTaskScheduler_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IShellTaskScheduler_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IShellTaskScheduler_Release(p) (p)->lpVtbl->Release(p) +/*** IShellTaskScheduler methods ***/ +#define IShellTaskScheduler_AddTask(p,a,b,c,d) (p)->lpVtbl->AddTask(p,a,b,c,d) +#define IShellTaskScheduler_RemoveTasks(p,a,b,c) (p)->lpVtbl->RemoveTasks(p,a,b,c) +#define IShellTaskScheduler_CountTasks(p,a) (p)->lpVtbl->CountTasks(p,a) +#define IShellTaskScheduler_Status(p,a,b) (p)->lpVtbl->Status(p,a,b) +#endif + +typedef void (CALLBACK *PFNASYNCICONTASKBALLBACK)(LPCITEMIDLIST pidl, LPVOID pvData, LPVOID pvHint, INT iIconIndex, INT iOpenIconIndex); + +/***************************************************************************** + * Control Panel functions + */ +LRESULT WINAPI CallCPLEntry16(HINSTANCE hMod, FARPROC pFunc, HWND dw3, UINT dw4, LPARAM dw5, LPARAM dw6); + #ifdef __cplusplus } /* extern "C" */ #endif /* defined(__cplusplus) */ diff --git a/reactos/include/psdk/shlobj_undoc.h b/reactos/include/psdk/shlobj_undoc.h index ef475f04649..940d279fa95 100644 --- a/reactos/include/psdk/shlobj_undoc.h +++ b/reactos/include/psdk/shlobj_undoc.h @@ -777,6 +777,7 @@ typedef struct tagCREATEMRULISTW PROC lpfnCompare; } CREATEMRULISTW, *LPCREATEMRULISTW; +#define MRU_STRING 0x0 #define MRU_BINARY 0x1 #define MRU_CACHEWRITE 0x2 @@ -786,6 +787,20 @@ INT WINAPI AddMRUData(HANDLE,LPCVOID,DWORD); INT WINAPI FindMRUData(HANDLE,LPCVOID,DWORD,LPINT); VOID WINAPI FreeMRUList(HANDLE); +INT WINAPI AddMRUStringW(HANDLE hList, LPCWSTR lpszString); +INT WINAPI AddMRUStringA(HANDLE hList, LPCSTR lpszString); +BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos); +INT WINAPI FindMRUStringW(HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum); +INT WINAPI FindMRUStringA(HANDLE hList, LPCSTR lpszString, LPINT lpRegNum); +HANDLE WINAPI CreateMRUListLazyW(const CREATEMRULISTW *lpcml, DWORD dwParam2, + DWORD dwParam3, DWORD dwParam4); +HANDLE WINAPI CreateMRUListLazyA(const CREATEMRULISTA *lpcml, DWORD dwParam2, + DWORD dwParam3, DWORD dwParam4); +INT WINAPI EnumMRUListW(HANDLE hList, INT nItemPos, LPVOID lpBuffer, + DWORD nBufferSize); +INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer, + DWORD nBufferSize); + #define DC_NOSENDMSG 0x2000 BOOL WINAPI DrawCaptionTempA(HWND,HDC,const RECT*,HFONT,HICON,LPCSTR,UINT); BOOL WINAPI DrawCaptionTempW(HWND,HDC,const RECT*,HFONT,HICON,LPCWSTR,UINT); diff --git a/reactos/include/psdk/shlwapi.h b/reactos/include/psdk/shlwapi.h index bec8b3a4f2f..d7feeac8441 100644 --- a/reactos/include/psdk/shlwapi.h +++ b/reactos/include/psdk/shlwapi.h @@ -319,11 +319,7 @@ BOOL WINAPI AssocIsDangerous(LPCWSTR); #endif /* NO_SHLWAPI_REG */ -void WINAPI IUnknown_Set(IUnknown **ppunk, IUnknown *punk); -void WINAPI IUnknown_AtomicRelease(IUnknown **punk); -HRESULT WINAPI IUnknown_GetWindow(IUnknown *punk, HWND *phwnd); HRESULT WINAPI IUnknown_SetSite(IUnknown *punk, IUnknown *punkSite); -HRESULT WINAPI IUnknown_GetSite(IUnknown *punk, REFIID riid, void **ppv); HRESULT WINAPI IUnknown_QueryService(IUnknown *punk, REFGUID guidService, REFIID riid, void **ppvOut); /* Path functions */ @@ -881,9 +877,6 @@ LPSTR WINAPI StrStrIA(LPCSTR,LPCSTR); LPWSTR WINAPI StrStrIW(LPCWSTR,LPCWSTR); #define StrStrI WINELIB_NAME_AW(StrStrI) -LPWSTR WINAPI StrStrNW(LPCWSTR,LPCWSTR,UINT); -LPWSTR WINAPI StrStrNIW(LPCWSTR,LPCWSTR,UINT); - int WINAPI StrToIntA(LPCSTR); int WINAPI StrToIntW(LPCWSTR); #define StrToInt WINELIB_NAME_AW(StrToInt) @@ -988,7 +981,6 @@ HRESULT WINAPI SHCreateStreamWrapper(LPBYTE,DWORD,DWORD,struct IStream**); HRESULT WINAPI SHAutoComplete(HWND,DWORD); /* Threads */ -HRESULT WINAPI SHCreateThreadRef(LONG*, IUnknown**); HRESULT WINAPI SHGetThreadRef(IUnknown**); HRESULT WINAPI SHSetThreadRef(IUnknown*); HRESULT WINAPI SHReleaseThreadRef(void); @@ -1043,6 +1035,24 @@ typedef struct _DLLVERSIONINFO2 { 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 @@ -1109,6 +1119,11 @@ typedef struct 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 #ifdef __cplusplus diff --git a/reactos/include/psdk/shlwapi_undoc.h b/reactos/include/psdk/shlwapi_undoc.h index 41f60a13e9e..50eef6bf863 100644 --- a/reactos/include/psdk/shlwapi_undoc.h +++ b/reactos/include/psdk/shlwapi_undoc.h @@ -45,6 +45,43 @@ struct IEThreadParamBlock 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); diff --git a/reactos/include/reactos/wine/commctrl.h b/reactos/include/reactos/wine/commctrl.h index 0d2e2cada7d..28ce67f7c5b 100644 --- a/reactos/include/reactos/wine/commctrl.h +++ b/reactos/include/reactos/wine/commctrl.h @@ -12,6 +12,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + #undef DPA_GetPtr LPVOID WINAPI DPA_GetPtr(HDPA, INT); @@ -82,4 +86,8 @@ typedef struct #define TB_UNKWN45D (WM_USER+93) #define TB_UNKWN464 (WM_USER+100) +#ifdef __cplusplus +} +#endif + #endif /* _INC_COMMCTRL_WINE */ diff --git a/reactos/lib/atl/atlbase.h b/reactos/lib/atl/atlbase.h index 137acf11b4b..0c238ee20b6 100644 --- a/reactos/lib/atl/atlbase.h +++ b/reactos/lib/atl/atlbase.h @@ -538,6 +538,7 @@ public: { ATLASSERT(_pModule == NULL); _pModule = this; + _pModule->m_pObjMap = NULL; } ~CComModule()