ReactOS.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2024
December
November
October
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
February
January
2012
December
November
October
September
August
July
June
May
April
March
February
January
2011
December
November
October
September
August
July
June
May
April
March
February
January
2010
December
November
October
September
August
July
June
May
April
March
February
January
2009
December
November
October
September
August
July
June
May
April
March
February
January
2008
December
November
October
September
August
July
June
May
April
March
February
January
2007
December
November
October
September
August
July
June
May
April
March
February
January
2006
December
November
October
September
August
July
June
May
April
March
February
January
2005
December
November
October
September
August
July
June
May
April
March
February
January
2004
December
November
October
September
August
July
June
May
April
March
February
List overview
Download
Ros-diffs
December 2024
----- 2024 -----
December 2024
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
----- 2012 -----
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
----- 2011 -----
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
----- 2010 -----
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
----- 2009 -----
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
----- 2008 -----
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
----- 2007 -----
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
----- 2006 -----
December 2006
November 2006
October 2006
September 2006
August 2006
July 2006
June 2006
May 2006
April 2006
March 2006
February 2006
January 2006
----- 2005 -----
December 2005
November 2005
October 2005
September 2005
August 2005
July 2005
June 2005
May 2005
April 2005
March 2005
February 2005
January 2005
----- 2004 -----
December 2004
November 2004
October 2004
September 2004
August 2004
July 2004
June 2004
May 2004
April 2004
March 2004
February 2004
ros-diffs@reactos.org
16 participants
90 discussions
Start a n
N
ew thread
[reactos] 01/01: [LSALIB][SECURE32][LSASRV] Improve the check for trusted/untrusted callers
by Eric Kohl
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ae7e375a4d5d907411317…
commit ae7e375a4d5d9074113172e3edede7c1759746a9 Author: Eric Kohl <eric.kohl(a)reactos.org> AuthorDate: Sun Dec 22 11:15:37 2024 +0100 Commit: Eric Kohl <eric.kohl(a)reactos.org> CommitDate: Sun Dec 22 11:15:37 2024 +0100 [LSALIB][SECURE32][LSASRV] Improve the check for trusted/untrusted callers - A caller of LsaRegisterLogonProcess is a trusted caller if the calling process has got the Tcb privilege, otherwise it is an untrusted caller. - A caller of LsaConnectUntrusted is always an untrusted caller. - A caller of LsapOpenLsaPort is always a trusted caller. --- dll/win32/lsasrv/authport.c | 20 +++++++++++++++++--- dll/win32/secur32/lsalpc.c | 4 ++-- sdk/include/reactos/subsys/lsass/lsass.h | 8 +++++++- sdk/lib/lsalib/lsa.c | 1 + 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/dll/win32/lsasrv/authport.c b/dll/win32/lsasrv/authport.c index e8140c0930f..f15faecbde1 100644 --- a/dll/win32/lsasrv/authport.c +++ b/dll/win32/lsasrv/authport.c @@ -135,10 +135,24 @@ LsapCheckLogonProcess(PLSA_API_MSG RequestMsg, TRACE("New LogonContext: %p\n", Context); Context->ClientProcessHandle = ProcessHandle; - Context->TrustedCaller = RequestMsg->ConnectInfo.TrustedCaller; - if (Context->TrustedCaller) - Context->TrustedCaller = LsapIsTrustedClient(ProcessHandle); + switch (RequestMsg->ConnectInfo.TrustedCaller) + { + case NO: + Context->TrustedCaller = FALSE; + break; + + case YES: + Context->TrustedCaller = TRUE; + break; + + case CHECK: + default: + Context->TrustedCaller = LsapIsTrustedClient(ProcessHandle); + break; + } + + TRACE("TrustedCaller: %u\n", Context->TrustedCaller); *LogonContext = Context; diff --git a/dll/win32/secur32/lsalpc.c b/dll/win32/secur32/lsalpc.c index 131538103c3..1103e6f6f6b 100644 --- a/dll/win32/secur32/lsalpc.c +++ b/dll/win32/secur32/lsalpc.c @@ -74,7 +74,7 @@ LsapOpenLsaPort(VOID) sizeof(ConnectInfo)); ConnectInfo.CreateContext = FALSE; - ConnectInfo.TrustedCaller = TRUE; + ConnectInfo.TrustedCaller = YES; ConnectInfoLength = sizeof(LSA_CONNECTION_INFO); Status = NtConnectPort(&LsaPortHandle, @@ -175,7 +175,7 @@ LsaConnectUntrusted( ConnectInfoLength); ConnectInfo.CreateContext = TRUE; - ConnectInfo.TrustedCaller = FALSE; + ConnectInfo.TrustedCaller = NO; Status = NtConnectPort(LsaHandle, &PortName, diff --git a/sdk/include/reactos/subsys/lsass/lsass.h b/sdk/include/reactos/subsys/lsass/lsass.h index 5522b0ef85f..ad2df3ee2d9 100644 --- a/sdk/include/reactos/subsys/lsass/lsass.h +++ b/sdk/include/reactos/subsys/lsass/lsass.h @@ -27,6 +27,12 @@ typedef enum _LSA_API_NUMBER LSASS_REQUEST_MAXIMUM } LSA_API_NUMBER, *PLSA_API_NUMBER; +typedef enum _LSA_TRUSTED_CALLER +{ + NO, + YES, + CHECK +} LSA_TRUSTED_CALLER; typedef struct _LSA_CONNECTION_INFO { @@ -35,7 +41,7 @@ typedef struct _LSA_CONNECTION_INFO ULONG Length; CHAR LogonProcessNameBuffer[LSASS_MAX_LOGON_PROCESS_NAME_LENGTH + 1]; BOOL CreateContext; - BOOL TrustedCaller; + LSA_TRUSTED_CALLER TrustedCaller; } LSA_CONNECTION_INFO, *PLSA_CONNECTION_INFO; diff --git a/sdk/lib/lsalib/lsa.c b/sdk/lib/lsalib/lsa.c index 95a02f41cd7..321797e066b 100644 --- a/sdk/lib/lsalib/lsa.c +++ b/sdk/lib/lsalib/lsa.c @@ -317,6 +317,7 @@ LsaRegisterLogonProcess(IN PLSA_STRING LogonProcessName, ConnectInfo.Length = LogonProcessName->Length; ConnectInfo.LogonProcessNameBuffer[ConnectInfo.Length] = ANSI_NULL; ConnectInfo.CreateContext = TRUE; + ConnectInfo.TrustedCaller = CHECK; Status = ZwConnectPort(LsaHandle, &PortName,
2 days, 21 hours
1
0
0
0
[reactos] 01/01: [WIN32K:NTUSER] Check for NULL desktop window in co_IntProcessMouseMessage
by Timo Kreuzer
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2d4c0b87b1eccecbdd220…
commit 2d4c0b87b1eccecbdd220ef9dea6512bbeb2fcd8 Author: Timo Kreuzer <timo.kreuzer(a)reactos.org> AuthorDate: Tue Dec 10 17:26:00 2024 +0200 Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org> CommitDate: Sun Dec 22 10:19:01 2024 +0200 [WIN32K:NTUSER] Check for NULL desktop window in co_IntProcessMouseMessage --- win32ss/user/ntuser/msgqueue.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/win32ss/user/ntuser/msgqueue.c b/win32ss/user/ntuser/msgqueue.c index 3a8b60704ff..13a3a106d7d 100644 --- a/win32ss/user/ntuser/msgqueue.c +++ b/win32ss/user/ntuser/msgqueue.c @@ -1487,6 +1487,12 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, BOOL* NotForUs, L pti = PsGetCurrentThreadWin32Thread(); pwndDesktop = UserGetDesktopWindow(); + if (pwndDesktop == NULL) + { + ERR("No desktop window!\n"); + return FALSE; + } + MessageQueue = pti->MessageQueue; CurInfo = IntGetSysCursorInfo(); pwndMsg = ValidateHwndNoErr(msg->hwnd); @@ -2001,7 +2007,7 @@ co_MsqPeekHardwareMessage(IN PTHREADINFO pti, UpdateKeyStateFromMsg(MessageQueue, &msg); AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, &NotForUs, ExtraInfo, MsgFilterLow, MsgFilterHigh); - + if (!NotForUs && (MsgFilterLow != 0 || MsgFilterHigh != 0)) { /* Don't return message if not in range */
2 days, 23 hours
1
0
0
0
[reactos] 01/01: [WKSSVC] Simplify NetrWkstaSetInfo
by Eric Kohl
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=216196a10d90b154f9f1c…
commit 216196a10d90b154f9f1c45001e1e25601c4b79b Author: Eric Kohl <eric.kohl(a)reactos.org> AuthorDate: Sat Dec 21 16:19:14 2024 +0100 Commit: Eric Kohl <eric.kohl(a)reactos.org> CommitDate: Sat Dec 21 16:19:14 2024 +0100 [WKSSVC] Simplify NetrWkstaSetInfo --- base/services/wkssvc/rpcserver.c | 78 ++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/base/services/wkssvc/rpcserver.c b/base/services/wkssvc/rpcserver.c index 703e35e6935..5088b48f6e9 100644 --- a/base/services/wkssvc/rpcserver.c +++ b/base/services/wkssvc/rpcserver.c @@ -243,6 +243,7 @@ NetrWkstaSetInfo( LPWKSTA_INFO WkstaInfo, unsigned long *ErrorParameter) { + DWORD dwErrParam = 0; DWORD dwResult = NERR_Success; TRACE("NetrWkstaSetInfo(%lu %p %p)\n", @@ -254,45 +255,50 @@ NetrWkstaSetInfo( if (WkstaInfo->WkstaInfo502.wki502_keep_conn >= 1 && WkstaInfo->WkstaInfo502.wki502_keep_conn <= 65535) { WkstaInfo502.wki502_keep_conn = WkstaInfo->WkstaInfo502.wki502_keep_conn; + } + else + { + dwErrParam = WKSTA_KEEPCONN_PARMNUM; + dwResult = ERROR_INVALID_PARAMETER; + } + if (dwResult == NERR_Success) + { if (WkstaInfo->WkstaInfo502.wki502_max_cmds >= 50 && WkstaInfo->WkstaInfo502.wki502_max_cmds <= 65535) { WkstaInfo502.wki502_max_cmds = WkstaInfo->WkstaInfo502.wki502_max_cmds; + } + else + { + dwErrParam = WKSTA_MAXCMDS_PARMNUM; + dwResult = ERROR_INVALID_PARAMETER; + } + } - if (WkstaInfo->WkstaInfo502.wki502_sess_timeout >= 60 && WkstaInfo->WkstaInfo502.wki502_sess_timeout <= 65535) - { - WkstaInfo502.wki502_sess_timeout = WkstaInfo->WkstaInfo502.wki502_sess_timeout; - - if (WkstaInfo->WkstaInfo502.wki502_dormant_file_limit != 0) - { - WkstaInfo502.wki502_dormant_file_limit = WkstaInfo->WkstaInfo502.wki502_dormant_file_limit; - } - else - { - if (ErrorParameter) - *ErrorParameter = WKSTA_DORMANTFILELIMIT_PARMNUM; - dwResult = ERROR_INVALID_PARAMETER; - } - } - else - { - if (ErrorParameter) - *ErrorParameter = WKSTA_SESSTIMEOUT_PARMNUM; - dwResult = ERROR_INVALID_PARAMETER; - } + if (dwResult == NERR_Success) + { + if (WkstaInfo->WkstaInfo502.wki502_sess_timeout >= 60 && WkstaInfo->WkstaInfo502.wki502_sess_timeout <= 65535) + { + WkstaInfo502.wki502_sess_timeout = WkstaInfo->WkstaInfo502.wki502_sess_timeout; } else { - if (ErrorParameter) - *ErrorParameter = WKSTA_MAXCMDS_PARMNUM; + dwErrParam = WKSTA_SESSTIMEOUT_PARMNUM; dwResult = ERROR_INVALID_PARAMETER; } } - else + + if (dwResult == NERR_Success) { - if (ErrorParameter) - *ErrorParameter = WKSTA_KEEPCONN_PARMNUM; - dwResult = ERROR_INVALID_PARAMETER; + if (WkstaInfo->WkstaInfo502.wki502_dormant_file_limit != 0) + { + WkstaInfo502.wki502_dormant_file_limit = WkstaInfo->WkstaInfo502.wki502_dormant_file_limit; + } + else + { + dwErrParam = WKSTA_DORMANTFILELIMIT_PARMNUM; + dwResult = ERROR_INVALID_PARAMETER; + } } break; @@ -303,8 +309,7 @@ NetrWkstaSetInfo( } else { - if (ErrorParameter) - *ErrorParameter = WKSTA_KEEPCONN_PARMNUM; + dwErrParam = WKSTA_KEEPCONN_PARMNUM; dwResult = ERROR_INVALID_PARAMETER; } break; @@ -316,8 +321,7 @@ NetrWkstaSetInfo( } else { - if (ErrorParameter) - *ErrorParameter = WKSTA_SESSTIMEOUT_PARMNUM; + dwErrParam = WKSTA_SESSTIMEOUT_PARMNUM; dwResult = ERROR_INVALID_PARAMETER; } break; @@ -329,23 +333,27 @@ NetrWkstaSetInfo( } else { - if (ErrorParameter) - *ErrorParameter = WKSTA_DORMANTFILELIMIT_PARMNUM; + dwErrParam = WKSTA_DORMANTFILELIMIT_PARMNUM; dwResult = ERROR_INVALID_PARAMETER; } break; default: - FIXME("Level %lu unimplemented\n", Level); + ERR("Invalid Level %lu\n", Level); dwResult = ERROR_INVALID_LEVEL; break; } /* Save the workstation in the registry */ if (dwResult == NERR_Success) + { SaveWorkstationInfo(Level); - /* FIXME: Notify the redirector */ + /* FIXME: Notify the redirector */ + } + + if ((dwResult == ERROR_INVALID_PARAMETER) && (ErrorParameter != NULL)) + *ErrorParameter = dwErrParam; return dwResult; }
3 days, 16 hours
1
0
0
0
[reactos] 01/01: [WKSSVC] InitWorkstationInfo: Set data size before retrieving registry values
by Eric Kohl
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=f06c4dcc6bd015d966cb0…
commit f06c4dcc6bd015d966cb0800a532319092124319 Author: Eric Kohl <eric.kohl(a)reactos.org> AuthorDate: Sat Dec 21 15:28:43 2024 +0100 Commit: Eric Kohl <eric.kohl(a)reactos.org> CommitDate: Sat Dec 21 15:28:43 2024 +0100 [WKSSVC] InitWorkstationInfo: Set data size before retrieving registry values --- base/services/wkssvc/info.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/base/services/wkssvc/info.c b/base/services/wkssvc/info.c index 98e90256ecd..e596ffe529c 100644 --- a/base/services/wkssvc/info.c +++ b/base/services/wkssvc/info.c @@ -326,6 +326,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_use_unlock_behind = 1; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"UseCloseBehind", 0, @@ -337,6 +338,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_use_close_behind = 1; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"BufNamedPipes", 0, @@ -348,6 +350,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_buf_named_pipes = 1; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"UseLockReadUnlock", 0, @@ -359,6 +362,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_use_lock_read_unlock = 1; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"UtilizeNtCaching", 0, @@ -370,6 +374,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_utilize_nt_caching = 1; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"UseRawRead", 0, @@ -381,6 +386,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_use_raw_read = 1; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"UseRawWrite", 0, @@ -392,6 +398,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_use_raw_write = 1; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"UseWriteRawData", 0, @@ -403,6 +410,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_use_write_raw_data = 0; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"UseEncryption", 0, @@ -414,6 +422,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_use_encryption = 1; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"BufFilesDenyWrite", 0, @@ -425,6 +434,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_buf_files_deny_write = 0; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"BufReadOnlyFiles", 0, @@ -436,6 +446,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_buf_read_only_files = 0; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"ForceCoreCreateMode", 0, @@ -447,6 +458,7 @@ InitWorkstationInfo(VOID) else WkstaInfo502.wki502_force_core_create_mode = 0; + dwSize = sizeof(dwValue); dwError = RegQueryValueExW(hInfoKey, L"Use512ByteMaxTransfer", 0,
3 days, 17 hours
1
0
0
0
[reactos] 01/01: [SETUPAPI] Implement SetupDiGetCustomDevicePropertyA
by Eric Kohl
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=85e90601e05bafc7fa709…
commit 85e90601e05bafc7fa709691cc6bf2e90ef03a6a Author: Eric Kohl <eric.kohl(a)reactos.org> AuthorDate: Sat Dec 21 10:35:53 2024 +0100 Commit: Eric Kohl <eric.kohl(a)reactos.org> CommitDate: Sat Dec 21 10:35:53 2024 +0100 [SETUPAPI] Implement SetupDiGetCustomDevicePropertyA --- dll/win32/setupapi/devinst.c | 80 ++++++++++++++++++++++++++++++++++++++++ dll/win32/setupapi/setupapi.spec | 2 +- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/dll/win32/setupapi/devinst.c b/dll/win32/setupapi/devinst.c index 53e99ba5d29..9dbabb48a32 100644 --- a/dll/win32/setupapi/devinst.c +++ b/dll/win32/setupapi/devinst.c @@ -6151,6 +6151,86 @@ SetupDiRestartDevices( return TRUE; } +/*********************************************************************** + * SetupDiGetCustomDevicePropertyA (SETUPAPI.@) + */ +BOOL +WINAPI +SetupDiGetCustomDevicePropertyA( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PCSTR CustomPropertyName, + IN DWORD Flags, + OUT PDWORD PropertyRegDataType OPTIONAL, + OUT PBYTE PropertyBuffer, + IN DWORD PropertyBufferSize, + OUT PDWORD RequiredSize OPTIONAL) +{ + struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet; + struct DeviceInfo *deviceInfo; + DWORD ConfigFlags = 0, PropertySize; + CONFIGRET cr; + + TRACE("%s(%p %p %s 0x%lx %p %p %lu %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, + CustomPropertyName, Flags, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize); + + if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) + || !DeviceInfoData->Reserved) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (Flags & ~DICUSTOMDEVPROP_MERGE_MULTISZ) + { + SetLastError(ERROR_INVALID_FLAGS); + return FALSE; + } + + deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved; + if (deviceInfo->set != set) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (Flags & DICUSTOMDEVPROP_MERGE_MULTISZ) + { + ConfigFlags |= CM_CUSTOMDEVPROP_MERGE_MULTISZ; + } + + PropertySize = PropertyBufferSize; + cr = CM_Get_DevInst_Custom_Property_ExA(deviceInfo->dnDevInst, + CustomPropertyName, + PropertyRegDataType, + PropertyBuffer, + &PropertySize, + ConfigFlags, + set->hMachine); + if ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) + { + if (RequiredSize) + *RequiredSize = PropertySize; + } + + if (cr != CR_SUCCESS) + { + SetLastError(GetErrorCodeFromCrCode(cr)); + return FALSE; + } + + return TRUE; +} + /*********************************************************************** * SetupDiGetCustomDevicePropertyW (SETUPAPI.@) */ diff --git a/dll/win32/setupapi/setupapi.spec b/dll/win32/setupapi/setupapi.spec index 3a15bffab48..c5d56635107 100644 --- a/dll/win32/setupapi/setupapi.spec +++ b/dll/win32/setupapi/setupapi.spec @@ -315,7 +315,7 @@ @ stdcall SetupDiGetClassInstallParamsW(ptr ptr ptr long ptr) @ stdcall SetupDiGetClassRegistryPropertyA(ptr long ptr ptr long ptr str ptr) @ stdcall SetupDiGetClassRegistryPropertyW(ptr long ptr ptr long ptr wstr ptr) -@ stub SetupDiGetCustomDevicePropertyA +@ stdcall SetupDiGetCustomDevicePropertyA(ptr ptr str long ptr ptr long ptr) @ stdcall SetupDiGetCustomDevicePropertyW(ptr ptr wstr long ptr ptr long ptr) @ stdcall SetupDiGetDeviceInfoListClass(ptr ptr) @ stdcall SetupDiGetDeviceInfoListDetailA(ptr ptr)
3 days, 22 hours
1
0
0
0
[reactos] 01/01: [GITHUB] Stick to ubuntu-22.04 for build-linux
by Stanislav Motylkov
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=392473c7b515522742a2d…
commit 392473c7b515522742a2d4da7a92140b74b06c04 Author: Stanislav Motylkov <x86corez(a)gmail.com> AuthorDate: Fri Dec 20 18:18:30 2024 +0300 Commit: Stanislav Motylkov <x86corez(a)gmail.com> CommitDate: Fri Dec 20 19:48:55 2024 +0300 [GITHUB] Stick to ubuntu-22.04 for build-linux Fixes clang build, since ubuntu-latest (24.04.1 LTS / Noble Numbat) has no LLVM 13 package available: ``` Ign:6
https://apt.llvm.org/noble
llvm-toolchain-noble-13 InRelease Err:9
https://apt.llvm.org/noble
llvm-toolchain-noble-13 Release 404 Not Found [IP: 151.101.46.49 443] Reading package lists... E: The repository '
http://apt.llvm.org/noble
llvm-toolchain-noble-13 Release' does not have a Release file. Error: Process completed with exit code 100. ``` --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e53c2df7f1..ecf47dbc9c2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: - dllver: 0x600 config: Release fail-fast: false - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Get RosBE build specifics id: get_rosbe_spec
4 days, 14 hours
1
0
0
0
[reactos] 01/01: [SHELL32] Use FS compatible PIDL format for Recycle Bin items (#7532)
by Whindmar Saksit
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=28399a216b744e6263c77…
commit 28399a216b744e6263c772754644743e7a6682f1 Author: Whindmar Saksit <whindsaks(a)proton.me> AuthorDate: Thu Dec 19 14:38:27 2024 +0100 Commit: GitHub <noreply(a)github.com> CommitDate: Thu Dec 19 14:38:27 2024 +0100 [SHELL32] Use FS compatible PIDL format for Recycle Bin items (#7532) * [SHELL32] Use FS compatible PIDL format for Recycle Bin items This allows SHChangeNotify to handle these items and DefView will correctly update the recycle folder. CORE-18005 CORE-19239 CORE-13950 CORE-18435 CORE-18436 CORE-18437 --- dll/win32/shell32/CCopyAsPathMenu.cpp | 14 +- dll/win32/shell32/CDefView.cpp | 33 +- dll/win32/shell32/CDefaultContextMenu.cpp | 37 +- dll/win32/shell32/CFolderItemVerbs.cpp | 8 +- dll/win32/shell32/COpenWithMenu.cpp | 20 +- dll/win32/shell32/CSendToMenu.cpp | 9 +- dll/win32/shell32/CShellLink.cpp | 25 +- dll/win32/shell32/dialogs/recycler_prop.cpp | 77 +- dll/win32/shell32/folders/CDesktopFolder.cpp | 2 +- dll/win32/shell32/folders/CFSFolder.cpp | 150 +-- dll/win32/shell32/folders/CFSFolder.h | 7 + dll/win32/shell32/folders/CRecycleBin.cpp | 1008 +++++++++++--------- dll/win32/shell32/folders/CRecycleBin.h | 7 +- dll/win32/shell32/precomp.h | 6 + dll/win32/shell32/shellrecyclebin/recyclebin.c | 161 +--- dll/win32/shell32/shellrecyclebin/recyclebin.h | 133 ++- .../shell32/shellrecyclebin/recyclebin_generic.cpp | 12 + .../shell32/shellrecyclebin/recyclebin_private.h | 12 + .../shell32/shellrecyclebin/recyclebin_v5.cpp | 40 +- dll/win32/shell32/shellrecyclebin/recyclebin_v5.h | 3 +- .../shellrecyclebin/recyclebin_v5_enumerator.cpp | 73 +- dll/win32/shell32/shlexec.cpp | 10 +- dll/win32/shell32/utils.cpp | 94 ++ dll/win32/shell32/utils.h | 40 +- dll/win32/shell32/wine/pidl.c | 86 +- dll/win32/shell32/wine/pidl.h | 13 +- dll/win32/shell32/wine/shell32_main.h | 2 +- 27 files changed, 1141 insertions(+), 941 deletions(-) diff --git a/dll/win32/shell32/CCopyAsPathMenu.cpp b/dll/win32/shell32/CCopyAsPathMenu.cpp index f031874c5d4..3f8f43aeb2d 100644 --- a/dll/win32/shell32/CCopyAsPathMenu.cpp +++ b/dll/win32/shell32/CCopyAsPathMenu.cpp @@ -103,6 +103,12 @@ CCopyAsPathMenu::DoCopyAsPath(IDataObject *pdto) return hr; } +static const CMVERBMAP g_VerbMap[] = +{ + { "copyaspath", IDC_COPYASPATH }, + { NULL } +}; + STDMETHODIMP CCopyAsPathMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { @@ -133,7 +139,8 @@ CCopyAsPathMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) { TRACE("CCopyAsPathMenu::InvokeCommand(%p %p)\n", this, lpcmi); - if (IS_INTRESOURCE(lpcmi->lpVerb) && LOWORD(lpcmi->lpVerb) == IDC_COPYASPATH) + int CmdId = SHELL_MapContextMenuVerbToCmdId(lpcmi, g_VerbMap); + if (CmdId == IDC_COPYASPATH) return DoCopyAsPath(m_pDataObject); return E_FAIL; @@ -142,10 +149,9 @@ CCopyAsPathMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) STDMETHODIMP CCopyAsPathMenu::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen) { - FIXME("CCopyAsPathMenu::GetCommandString(%p %lu %u %p %p %u)\n", this, + TRACE("CCopyAsPathMenu::GetCommandString(%p %lu %u %p %p %u)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); - - return E_NOTIMPL; + return SHELL_GetCommandStringImpl(idCommand, uFlags, lpszName, uMaxNameLen, g_VerbMap); } STDMETHODIMP diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp index d4c8ed82cab..0505c8e7b69 100644 --- a/dll/win32/shell32/CDefView.cpp +++ b/dll/win32/shell32/CDefView.cpp @@ -1318,6 +1318,7 @@ int CDefView::LV_FindItemByPidl(PCUITEMID_CHILD pidl) { for (i = 0; i < cItems; i++) { + //FIXME: ILIsEqual needs absolute pidls! currentpidl = _PidlByItem(i); if (ILIsEqual(pidl, currentpidl)) return i; @@ -2848,29 +2849,35 @@ LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL & TRACE("(%p)(%p,%p,%p)\n", this, Pidls[0], Pidls[1], lParam); if (_DoFolderViewCB(SFVM_FSNOTIFY, (WPARAM)Pidls, lEvent) == S_FALSE) + { + SHChangeNotification_Unlock(hLock); return FALSE; + } // Translate child IDLs. // SHSimpleIDListFromPathW creates fake PIDLs (lacking some attributes) + lEvent &= ~SHCNE_INTERRUPT; HRESULT hr; PITEMID_CHILD child0 = NULL, child1 = NULL; CComHeapPtr<ITEMIDLIST_RELATIVE> pidl0Temp, pidl1Temp; - if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0])) + if (lEvent != SHCNE_UPDATEIMAGE && lEvent < SHCNE_EXTENDED_EVENT) { - child0 = ILFindLastID(Pidls[0]); - hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp); - if (SUCCEEDED(hr)) - child0 = pidl0Temp; - } - if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1])) - { - child1 = ILFindLastID(Pidls[1]); - hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp); - if (SUCCEEDED(hr)) - child1 = pidl1Temp; + if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0])) + { + child0 = ILFindLastID(Pidls[0]); + hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp); + if (SUCCEEDED(hr)) + child0 = pidl0Temp; + } + if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1])) + { + child1 = ILFindLastID(Pidls[1]); + hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp); + if (SUCCEEDED(hr)) + child1 = pidl1Temp; + } } - lEvent &= ~SHCNE_INTERRUPT; switch (lEvent) { case SHCNE_MKDIR: diff --git a/dll/win32/shell32/CDefaultContextMenu.cpp b/dll/win32/shell32/CDefaultContextMenu.cpp index 6b83bd8a069..90954dd87c9 100644 --- a/dll/win32/shell32/CDefaultContextMenu.cpp +++ b/dll/win32/shell32/CDefaultContextMenu.cpp @@ -84,6 +84,25 @@ UINT MapVerbToDfmCmd(_In_ LPCSTR verba) return 0; } +static HRESULT +MapVerbToCmdId(PVOID Verb, BOOL IsUnicode, IContextMenu *pCM, UINT idFirst, UINT idLast) +{ + const UINT gcs = IsUnicode ? GCS_VERBW : GCS_VERBA; + for (UINT id = idFirst; id <= idLast; ++id) + { + WCHAR buf[MAX_PATH]; + *buf = UNICODE_NULL; + HRESULT hr = pCM->GetCommandString(id, gcs, NULL, (LPSTR)buf, _countof(buf)); + if (FAILED(hr) || !*buf) + continue; + else if (IsUnicode && !_wcsicmp((LPWSTR)Verb, buf)) + return id; + else if (!IsUnicode && !lstrcmpiA((LPSTR)Verb, (LPSTR)buf)) + return id; + } + return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); +} + static inline bool IsVerbListSeparator(WCHAR Ch) { return Ch == L' ' || Ch == L','; //
learn.microsoft.com/en-us/windows/win32/shell/context-menu-handlers
@@ -738,7 +757,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu( return cIds; } -void WINAPI _InsertMenuItemW( +BOOL WINAPI _InsertMenuItemW( HMENU hMenu, UINT indexMenu, BOOL fByPosition, @@ -764,7 +783,7 @@ void WINAPI _InsertMenuItemW( else { ERR("failed to load string %p\n", dwTypeData); - return; + return FALSE; } } else @@ -774,7 +793,7 @@ void WINAPI _InsertMenuItemW( mii.wID = wID; mii.fType = fType; - InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii); + return InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii); } void @@ -1212,6 +1231,18 @@ CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode) } } + for (POSITION it = m_DynamicEntries.GetHeadPosition(); it != NULL;) + { + DynamicShellEntry& entry = m_DynamicEntries.GetNext(it); + if (!entry.NumIds) + continue; + HRESULT hr = ::MapVerbToCmdId(Verb, IsUnicode, entry.pCM, 0, entry.NumIds - 1); + if (SUCCEEDED(hr)) + { + *idCmd = m_iIdSHEFirst + entry.iIdCmdFirst + hr; + return TRUE; + } + } return FALSE; } diff --git a/dll/win32/shell32/CFolderItemVerbs.cpp b/dll/win32/shell32/CFolderItemVerbs.cpp index 775f342f737..ce7f2266ba6 100644 --- a/dll/win32/shell32/CFolderItemVerbs.cpp +++ b/dll/win32/shell32/CFolderItemVerbs.cpp @@ -91,13 +91,7 @@ CFolderItemVerbs::~CFolderItemVerbs() HRESULT CFolderItemVerbs::Init(LPITEMIDLIST idlist) { - CComPtr<IShellFolder> folder; - LPCITEMIDLIST child; - HRESULT hr = SHBindToParent(idlist, IID_PPV_ARG(IShellFolder, &folder), &child); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - hr = folder->GetUIObjectOf(NULL, 1, &child, IID_IContextMenu, NULL, (PVOID*)&m_contextmenu); + HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, idlist, IID_PPV_ARG(IContextMenu, &m_contextmenu)); if (FAILED_UNEXPECTEDLY(hr)) return hr; diff --git a/dll/win32/shell32/COpenWithMenu.cpp b/dll/win32/shell32/COpenWithMenu.cpp index 42f538a7eeb..96a73dd822d 100644 --- a/dll/win32/shell32/COpenWithMenu.cpp +++ b/dll/win32/shell32/COpenWithMenu.cpp @@ -1250,6 +1250,11 @@ VOID COpenWithMenu::AddApp(PVOID pApp) m_idCmdLast++; } +static const CMVERBMAP g_VerbMap[] = { + { "openas", 0 }, + { NULL } +}; + HRESULT WINAPI COpenWithMenu::QueryContextMenu( HMENU hMenu, UINT indexMenu, @@ -1328,14 +1333,19 @@ HRESULT WINAPI COpenWithMenu::QueryContextMenu( HRESULT WINAPI COpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) { + const SIZE_T idChooseApp = m_idCmdLast; HRESULT hr = E_FAIL; TRACE("This %p idFirst %u idLast %u idCmd %u\n", this, m_idCmdFirst, m_idCmdLast, m_idCmdFirst + LOWORD(lpici->lpVerb)); - if (HIWORD(lpici->lpVerb) == 0 && m_idCmdFirst + LOWORD(lpici->lpVerb) <= m_idCmdLast) + if (!IS_INTRESOURCE(lpici->lpVerb) && SHELL_MapContextMenuVerbToCmdId(lpici, g_VerbMap) == 0) + goto DoChooseApp; + + if (IS_INTRESOURCE(lpici->lpVerb) && m_idCmdFirst + LOWORD(lpici->lpVerb) <= m_idCmdLast) { - if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdLast) + if (m_idCmdFirst + LOWORD(lpici->lpVerb) == idChooseApp) { +DoChooseApp: OPENASINFO info; LPCWSTR pwszExt = PathFindExtensionW(m_wszPath); @@ -1371,9 +1381,13 @@ HRESULT WINAPI COpenWithMenu::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax ) { - FIXME("%p %lu %u %p %p %u\n", this, + TRACE("%p %lu %u %p %p %u\n", this, idCmd, uType, pwReserved, pszName, cchMax ); + const SIZE_T idChooseApp = m_idCmdLast; + if (m_idCmdFirst + idCmd == idChooseApp) + return SHELL_GetCommandStringImpl(0, uType, pszName, cchMax, g_VerbMap); + return E_NOTIMPL; } diff --git a/dll/win32/shell32/CSendToMenu.cpp b/dll/win32/shell32/CSendToMenu.cpp index 131f21e2a0a..8cce580ba08 100644 --- a/dll/win32/shell32/CSendToMenu.cpp +++ b/dll/win32/shell32/CSendToMenu.cpp @@ -130,14 +130,7 @@ HRESULT CSendToMenu::GetUIObjectFromPidl(HWND hwnd, PIDLIST_ABSOLUTE pidl, REFIID riid, LPVOID *ppvOut) { *ppvOut = NULL; - - PCITEMID_CHILD pidlLast; - CComPtr<IShellFolder> pFolder; - HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &pFolder), &pidlLast); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - hr = pFolder->GetUIObjectOf(hwnd, 1, &pidlLast, riid, NULL, ppvOut); + HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(hwnd, pidl, riid, ppvOut); if (FAILED_UNEXPECTEDLY(hr)) return hr; diff --git a/dll/win32/shell32/CShellLink.cpp b/dll/win32/shell32/CShellLink.cpp index d99db2f1470..9619efcf483 100644 --- a/dll/win32/shell32/CShellLink.cpp +++ b/dll/win32/shell32/CShellLink.cpp @@ -1729,18 +1729,10 @@ HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation(LPWSTR pszIconPath, INT cc static HRESULT SHELL_PidlGetIconLocationW(PCIDLIST_ABSOLUTE pidl, UINT uFlags, PWSTR pszIconFile, UINT cchMax, int *piIndex, UINT *pwFlags) { - LPCITEMIDLIST pidlLast; - CComPtr<IShellFolder> psf; - - HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - CComPtr<IExtractIconW> pei; - hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IExtractIconW, &pei)); + HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, pidl, IID_PPV_ARG(IExtractIconW, &pei)); if (FAILED_UNEXPECTEDLY(hr)) return hr; - hr = pei->GetIconLocation(uFlags, pszIconFile, cchMax, piIndex, pwFlags); if (FAILED_UNEXPECTEDLY(hr)) return hr; @@ -3142,20 +3134,9 @@ HRESULT STDMETHODCALLTYPE CShellLink::DragEnter(IDataObject *pDataObject, if (*pdwEffect == DROPEFFECT_NONE) return S_OK; - LPCITEMIDLIST pidlLast; - CComPtr<IShellFolder> psf; - - HRESULT hr = SHBindToParent(m_pPidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast); - + HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, m_pPidl, IID_PPV_ARG(IDropTarget, &m_DropTarget)); if (SUCCEEDED(hr)) - { - hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IDropTarget, &m_DropTarget)); - - if (SUCCEEDED(hr)) - hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect); - else - *pdwEffect = DROPEFFECT_NONE; - } + hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect); else *pdwEffect = DROPEFFECT_NONE; diff --git a/dll/win32/shell32/dialogs/recycler_prop.cpp b/dll/win32/shell32/dialogs/recycler_prop.cpp index d7f79251a3e..72387de388c 100644 --- a/dll/win32/shell32/dialogs/recycler_prop.cpp +++ b/dll/win32/shell32/dialogs/recycler_prop.cpp @@ -45,6 +45,9 @@ static void toggleNukeOnDeleteOption(HWND hwndDlg, BOOL bEnable) EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE); SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_UNCHECKED, 0); } + + // FIXME: Max capacity not implemented yet, disable for now (CORE-13743) + EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE); } static VOID @@ -129,7 +132,8 @@ InitializeRecycleBinDlg(HWND hwndDlg, WCHAR DefaultDrive) 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); + if (RegGetValueW(HKEY_CURRENT_USER, szName, L"MaxCapacity", RRF_RT_DWORD, NULL, &pItem->dwMaxCapacity, &dwSize)) + pItem->dwMaxCapacity = ~0; /* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */ FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024)); @@ -240,7 +244,7 @@ static VOID FreeDriveItemContext(HWND hwndDlg) } static INT -GetDefaultItem(HWND hwndDlg, LVITEMW* li) +GetSelectedDriveItem(HWND hwndDlg, LVITEMW* li) { HWND hDlgCtrl; UINT iItemCount, iIndex; @@ -275,6 +279,7 @@ RecycleBinDlg( WPARAM wParam, LPARAM lParam) { + enum { WM_NEWDRIVESELECTED = WM_APP, WM_UPDATEDRIVESETTINGS }; LPPSHNOTIFY lppsn; LPNMLISTVIEW lppl; LVITEMW li; @@ -329,25 +334,9 @@ RecycleBinDlg( ss.fNoConfirmRecycle = SendDlgItemMessage(hwndDlg, 14004, BM_GETCHECK, 0, 0) == BST_UNCHECKED; SHGetSetSettings(&ss, SSF_NOCONFIRMRECYCLE, TRUE); - if (GetDefaultItem(hwndDlg, &li) > -1) + if (GetSelectedDriveItem(hwndDlg, &li) > -1) { - pItem = (PDRIVE_ITEM_CONTEXT)li.lParam; - if (pItem) - { - uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE); - if (bSuccess) - { - /* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */ - FreeBytesAvailable = pItem->FreeBytesAvailable; - FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024)); - pItem->dwMaxCapacity = min(uResult, FreeBytesAvailable.LowPart); - SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE); - } - if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) - pItem->dwNukeOnDelete = TRUE; - else - pItem->dwNukeOnDelete = FALSE; - } + SendMessage(hwndDlg, WM_UPDATEDRIVESETTINGS, 0, li.lParam); } if (StoreDriveSettings(hwndDlg)) { @@ -369,31 +358,45 @@ RecycleBinDlg( if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED)) { - /* new focused item */ - toggleNukeOnDeleteOption(lppl->hdr.hwndFrom, pItem->dwNukeOnDelete); - SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE); + // New focused item, delay handling until after kill focus has been processed + PostMessage(hwndDlg, WM_NEWDRIVESELECTED, 0, (LPARAM)pItem); } else if ((lppl->uOldState & LVIS_FOCUSED) && !(lppl->uNewState & LVIS_FOCUSED)) { - /* kill focus */ - uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE); - if (bSuccess) - { - /* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */ - FreeBytesAvailable = pItem->FreeBytesAvailable; - FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024)); - pItem->dwMaxCapacity = min(uResult, FreeBytesAvailable.LowPart); - SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE); - } - if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) - pItem->dwNukeOnDelete = TRUE; - else - pItem->dwNukeOnDelete = FALSE; + // Kill focus + SendMessage(hwndDlg, WM_UPDATEDRIVESETTINGS, 0, (LPARAM)pItem); } return TRUE; } break; + case WM_NEWDRIVESELECTED: + if (lParam) + { + pItem = (PDRIVE_ITEM_CONTEXT)lParam; + toggleNukeOnDeleteOption(hwndDlg, pItem->dwNukeOnDelete); + SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE); + } + break; + case WM_UPDATEDRIVESETTINGS: + if (lParam) + { + pItem = (PDRIVE_ITEM_CONTEXT)lParam; + uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE); + if (bSuccess) + { + /* Check if the maximum capacity doesn't exceed the available disk space (in megabytes), and truncate it if needed */ + FreeBytesAvailable = pItem->FreeBytesAvailable; + FreeBytesAvailable.QuadPart = (FreeBytesAvailable.QuadPart / (1024 * 1024)); + pItem->dwMaxCapacity = min(uResult, FreeBytesAvailable.LowPart); + SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE); + } + if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) + pItem->dwNukeOnDelete = TRUE; + else + pItem->dwNukeOnDelete = FALSE; + } + break; case WM_DESTROY: FreeDriveItemContext(hwndDlg); break; diff --git a/dll/win32/shell32/folders/CDesktopFolder.cpp b/dll/win32/shell32/folders/CDesktopFolder.cpp index 945f3450ede..b785a28a959 100644 --- a/dll/win32/shell32/folders/CDesktopFolder.cpp +++ b/dll/win32/shell32/folders/CDesktopFolder.cpp @@ -695,7 +695,7 @@ HRESULT WINAPI CDesktopFolder::GetAttributesOf( *rgfInOut &= dwMyComputerAttributes; else if (_ILIsNetHood(apidl[i])) *rgfInOut &= dwMyNetPlacesAttributes; - else if (_ILIsFolder(apidl[i]) || _ILIsValue(apidl[i]) || _ILIsSpecialFolder(apidl[i])) + else if (_ILIsFolderOrFile(apidl[i]) || _ILIsSpecialFolder(apidl[i])) { CComPtr<IShellFolder2> psf; HRESULT hr = _GetSFFromPidl(apidl[i], &psf); diff --git a/dll/win32/shell32/folders/CFSFolder.cpp b/dll/win32/shell32/folders/CFSFolder.cpp index 9ae1f53da1f..dd4b3678771 100644 --- a/dll/win32/shell32/folders/CFSFolder.cpp +++ b/dll/win32/shell32/folders/CFSFolder.cpp @@ -620,7 +620,7 @@ HRESULT SHELL32_GetFSItemAttributes(IShellFolder * psf, LPCITEMIDLIST pidl, LPDW { DWORD dwFileAttributes, dwShellAttributes; - if (!_ILIsFolder(pidl) && !_ILIsValue(pidl)) + if (!_ILIsFolderOrFile(pidl)) { ERR("Got wrong type of pidl!\n"); *pdwAttributes &= SFGAO_CANLINK; @@ -1007,9 +1007,9 @@ HRESULT WINAPI CFSFolder::BindToObject( /* Get the pidl data */ FileStruct* pData = &_ILGetDataPointer(pidl)->u.file; - FileStructW* pDataW = _ILGetFileStructW(pidl); - - if (!pDataW) + WCHAR szNameBuf[MAX_PATH]; + LPCWSTR pszName = GetItemFileName(pidl, szNameBuf, _countof(szNameBuf)); + if (!pszName) { ERR("CFSFolder::BindToObject: Invalid pidl!\n"); return E_INVALIDARG; @@ -1021,7 +1021,7 @@ HRESULT WINAPI CFSFolder::BindToObject( PERSIST_FOLDER_TARGET_INFO pfti = {0}; pfti.dwAttributes = -1; pfti.csidl = -1; - PathCombineW(pfti.szTargetParsingName, m_sPathTarget, pDataW->wszName); + PathCombineW(pfti.szTargetParsingName, m_sPathTarget, pszName); /* Get the CLSID to bind to */ CLSID clsidFolder; @@ -1088,6 +1088,20 @@ HRESULT WINAPI CFSFolder::BindToStorage( return E_NOTIMPL; } +HRESULT CFSFolder::CompareSortFoldersFirst(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + BOOL bIsFolder1 = _ILIsFolder(pidl1), bIsFolder2 = _ILIsFolder(pidl2); + // When sorting between a File and a Folder, the Folder gets sorted first + if (bIsFolder1 != bIsFolder2) + { + // ...but only if neither of them were generated by SHSimpleIDListFromPath + // because in that case we cannot tell if it's a file or a folder. + if (pidl1 && IsRealItem(*pidl1) && pidl2 && IsRealItem(*pidl2)) + return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1); + } + return MAKE_SCODE(SEVERITY_ERROR, FACILITY_SHELL, S_EQUAL); +} + /************************************************************************** * CFSFolder::CompareIDs */ @@ -1096,31 +1110,24 @@ HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) { + WCHAR szNameBuf1[MAX_PATH], szNameBuf2[_countof(szNameBuf1)]; + LPCWSTR pszName1 = GetItemFileName(pidl1, szNameBuf1, _countof(szNameBuf1)); + LPCWSTR pszName2 = GetItemFileName(pidl2, szNameBuf2, _countof(szNameBuf2)); + if (!pszName1 || !pszName2 || LOWORD(lParam) >= GENERICSHELLVIEWCOLUMNS) + return E_INVALIDARG; + LPPIDLDATA pData1 = _ILGetDataPointer(pidl1); LPPIDLDATA pData2 = _ILGetDataPointer(pidl2); - FileStructW* pDataW1 = _ILGetFileStructW(pidl1); - FileStructW* pDataW2 = _ILGetFileStructW(pidl2); - BOOL bIsFolder1 = _ILIsFolder(pidl1); - BOOL bIsFolder2 = _ILIsFolder(pidl2); LPWSTR pExtension1, pExtension2; - if (!pDataW1 || !pDataW2 || LOWORD(lParam) >= GENERICSHELLVIEWCOLUMNS) - return E_INVALIDARG; - - /* When sorting between a File and a Folder, the Folder gets sorted first */ - if (bIsFolder1 != bIsFolder2) - { - // ...but only if neither of them were generated by SHSimpleIDListFromPath - // because in that case we cannot tell if it's a file or a folder. - if (IsRealItem(*pidl1) && IsRealItem(*pidl2)) - return MAKE_COMPARE_HRESULT(bIsFolder1 ? -1 : 1); - } - + HRESULT hr = CompareSortFoldersFirst(pidl1, pidl2); + if (SUCCEEDED(hr)) + return hr; int result = 0; switch (LOWORD(lParam)) { case SHFSF_COL_NAME: - result = _wcsicmp(pDataW1->wszName, pDataW2->wszName); + result = _wcsicmp(pszName1, pszName2); break; case SHFSF_COL_SIZE: if (pData1->u.file.dwFileSize > pData2->u.file.dwFileSize) @@ -1131,8 +1138,9 @@ HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam, result = 0; break; case SHFSF_COL_TYPE: - pExtension1 = PathFindExtensionW(pDataW1->wszName); - pExtension2 = PathFindExtensionW(pDataW2->wszName); + // FIXME: Compare the type strings from SHGetFileInfo + pExtension1 = PathFindExtensionW(pszName1); + pExtension2 = PathFindExtensionW(pszName2); result = _wcsicmp(pExtension1, pExtension2); break; case SHFSF_COL_MDATE: @@ -1273,7 +1281,7 @@ HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl, { LPCITEMIDLIST rpidl = ILFindLastID(m_pidlRoot); - if (_ILIsFolder(rpidl) || _ILIsValue(rpidl)) + if (_ILIsFolderOrFile(rpidl)) { SHELL32_GetFSItemAttributes(this, rpidl, rgfInOut); } @@ -1297,7 +1305,7 @@ HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl, while (cidl > 0 && *apidl) { pdump(*apidl); - if(_ILIsFolder(*apidl) || _ILIsValue(*apidl)) + if (_ILIsFolderOrFile(*apidl)) SHELL32_GetFSItemAttributes(this, *apidl, rgfInOut); else ERR("Got an unknown type of pidl!!!\n"); @@ -1549,14 +1557,14 @@ HRESULT WINAPI CFSFolder::SetNameOf( DWORD dwFlags, PITEMID_CHILD *pPidlOut) { - WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1]; + WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1], szNameBuf[MAX_PATH]; BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl)); TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut); - FileStructW* pDataW = _ILGetFileStructW(pidl); - if (!pDataW) + LPCWSTR pszName = GetItemFileName(pidl, szNameBuf, _countof(szNameBuf)); + if (!pszName) { ERR("Got garbage pidl:\n"); pdump_always(pidl); @@ -1564,7 +1572,7 @@ HRESULT WINAPI CFSFolder::SetNameOf( } /* build source path */ - PathCombineW(szSrc, m_sPathTarget, pDataW->wszName); // FIXME: PIDLs without wide string + PathCombineW(szSrc, m_sPathTarget, pszName); /* build destination path */ if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) @@ -1662,6 +1670,7 @@ HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl, } else { + FILETIME ft; hr = S_OK; psd->str.uType = STRRET_WSTR; if (iColumn != SHFSF_COL_NAME) @@ -1683,7 +1692,11 @@ HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl, GetItemDescription(pidl, psd->str.pOleStr, MAX_PATH); break; case SHFSF_COL_MDATE: - _ILGetFileDate(pidl, psd->str.pOleStr, MAX_PATH); + if (!_ILGetFileDateTime(pidl, &ft) || FAILED(FormatDateTime(ft, psd->str.pOleStr, MAX_PATH))) + { + *psd->str.pOleStr = UNICODE_NULL; + hr = S_FALSE; + } break; case SHFSF_COL_FATTS: _ILGetFileAttributes(pidl, psd->str.pOleStr, MAX_PATH); @@ -1744,17 +1757,12 @@ HRESULT WINAPI CFSFolder::Initialize(PCIDLIST_ABSOLUTE pidl) m_sPathTarget = NULL; /* set my path */ + HRESULT hr = E_FAIL; if (SHGetPathFromIDListW (pidl, wszTemp)) - { - int len = wcslen(wszTemp); - m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); - if (!m_sPathTarget) - return E_OUTOFMEMORY; - memcpy(m_sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); - } + hr = SHStrDupW(wszTemp, &m_sPathTarget); TRACE ("--(%p)->(%s)\n", this, debugstr_w(m_sPathTarget)); - return S_OK; + return hr; } /************************************************************************** @@ -1806,44 +1814,28 @@ HRESULT WINAPI CFSFolder::InitializeEx(IBindCtx * pbc, LPCITEMIDLIST pidlRootx, * the target folder is spezified in csidl OR pidlTargetFolder OR * szTargetParsingName */ + HRESULT hr = E_FAIL; if (ppfti) { if (ppfti->csidl != -1) { - if (SHGetSpecialFolderPathW(0, wszTemp, ppfti->csidl, - ppfti->csidl & CSIDL_FLAG_CREATE)) { - int len = wcslen(wszTemp); - m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); - if (!m_sPathTarget) - return E_OUTOFMEMORY; - memcpy(m_sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); - } + BOOL create = ppfti->csidl & CSIDL_FLAG_CREATE; + if (SHGetSpecialFolderPathW(0, wszTemp, ppfti->csidl, create)) + hr = SHStrDupW(wszTemp, &m_sPathTarget); } else if (ppfti->szTargetParsingName[0]) { - int len = wcslen(ppfti->szTargetParsingName); - m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); - if (!m_sPathTarget) - return E_OUTOFMEMORY; - memcpy(m_sPathTarget, ppfti->szTargetParsingName, - (len + 1) * sizeof(WCHAR)); + hr = SHStrDupW(ppfti->szTargetParsingName, &m_sPathTarget); } else if (ppfti->pidlTargetFolder) { if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp)) - { - int len = wcslen(wszTemp); - m_sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR)); - if (!m_sPathTarget) - return E_OUTOFMEMORY; - memcpy(m_sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR)); - } + hr = SHStrDupW(wszTemp, &m_sPathTarget); } } - TRACE("--(%p)->(target=%s)\n", this, debugstr_w(m_sPathTarget)); pdump(m_pidlRoot); - return (m_sPathTarget) ? S_OK : E_FAIL; + return hr; } HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti) @@ -1923,17 +1915,16 @@ HRESULT CFSFolder::_GetIconHandler(LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvO HRESULT CFSFolder::_CreateShellExtInstance(const CLSID *pclsid, LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut) { HRESULT hr; - WCHAR wszPath[MAX_PATH]; + WCHAR wszPath[MAX_PATH], szNameBuf[MAX_PATH]; - FileStructW* pDataW = _ILGetFileStructW(pidl); - if (!pDataW) + LPCWSTR pszName = GetItemFileName(pidl, szNameBuf, _countof(szNameBuf)); + if (!pszName) { ERR("Got garbage pidl\n"); pdump_always(pidl); return E_INVALIDARG; } - - PathCombineW(wszPath, m_sPathTarget, pDataW->wszName); + PathCombineW(wszPath, m_sPathTarget, pszName); CComPtr<IPersistFile> pp; hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IPersistFile, &pp)); @@ -2104,3 +2095,28 @@ HRESULT WINAPI CFSFolder::MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam) } return hr; } + +HRESULT CFSFolder::FormatDateTime(const FILETIME &ft, LPWSTR Buf, UINT cchBuf) +{ + FILETIME lft; + SYSTEMTIME time; + FileTimeToLocalFileTime(&ft, &lft); + FileTimeToSystemTime(&lft, &time); + UINT ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, Buf, cchBuf); + if (ret > 0 && ret < cchBuf) + { + /* Append space + time without seconds */ + Buf[ret-1] = ' '; + GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &Buf[ret], cchBuf - ret); + } + return ret ? S_OK : E_FAIL; +} + +HRESULT CFSFolder::FormatSize(UINT64 size, LPWSTR Buf, UINT cchBuf) +{ + if (StrFormatKBSizeW(size, Buf, cchBuf)) + return S_OK; + if (cchBuf) + *Buf = UNICODE_NULL; + return E_FAIL; +} diff --git a/dll/win32/shell32/folders/CFSFolder.h b/dll/win32/shell32/folders/CFSFolder.h index e3db017578d..79f9c2c17e5 100644 --- a/dll/win32/shell32/folders/CFSFolder.h +++ b/dll/win32/shell32/folders/CFSFolder.h @@ -130,6 +130,13 @@ class CFSFolder : // Helper functions shared with CDesktopFolder static HRESULT GetFSColumnDetails(UINT iColumn, SHELLDETAILS &sd); static HRESULT GetDefaultFSColumnState(UINT iColumn, SHCOLSTATEF &csFlags); + static HRESULT FormatDateTime(const FILETIME &ft, LPWSTR Buf, UINT cchBuf); + static HRESULT FormatSize(UINT64 size, LPWSTR Buf, UINT cchBuf); + static HRESULT CompareSortFoldersFirst(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2); + static inline int CompareUiStrings(LPCWSTR a, LPCWSTR b) + { + return StrCmpLogicalW(a, b); + } }; #endif /* _CFSFOLDER_H_ */ diff --git a/dll/win32/shell32/folders/CRecycleBin.cpp b/dll/win32/shell32/folders/CRecycleBin.cpp index a9660e216a8..bd09268623b 100644 --- a/dll/win32/shell32/folders/CRecycleBin.cpp +++ b/dll/win32/shell32/folders/CRecycleBin.cpp @@ -58,78 +58,259 @@ static const columninfo RecycleBinColumns[] = #define COLUMNS_COUNT 6 +// The ROS Recycle Bin PIDL format starts with a NT4/2000 Unicode FS PIDL followed by +// BBITEMDATA and BBITEMFOOTER. This makes it compatible with SHChangeNotify listeners. +#include "pshpack1.h" +#define BBITEMFILETYPE (PT_FS | PT_FS_UNICODE_FLAG | PT_FS_FILE_FLAG) +#define BBITEMFOLDERTYPE (PT_FS | PT_FS_UNICODE_FLAG | PT_FS_FOLDER_FLAG) +struct BBITEMDATA +{ + FILETIME DeletionTime; +#ifdef COLUMN_FATTS + WORD AttribsHi; // Nobody needs this yet +#endif + WORD RecycledPathOffset; + WCHAR OriginalLocation[ANYSIZE_ARRAY]; + // ... @RecycledPathOffset WCHAR RecycledPath[ANYSIZE_ARRAY]; +}; +struct BBITEMFOOTER +{ + enum { ENDSIG = MAKEWORD('K', 'I') }; // "Killed item". MUST have the low bit set so _ILGetFileStructW returns NULL. + WORD DataSize; + WORD EndSignature; +}; +#include "poppack.h" + +static inline BOOL IsFolder(LPCITEMIDLIST pidl) +{ + return _ILGetFSType(pidl) & PT_FS_FOLDER_FLAG; +} + +static BBITEMDATA* ValidateItem(LPCITEMIDLIST pidl) +{ + const UINT minstringsize = sizeof(L"X") + sizeof(""); // PT_FS strings + const UINT minfs = sizeof(WORD) + FIELD_OFFSET(PIDLDATA, u.file.szNames) + minstringsize; + const UINT mindatasize = FIELD_OFFSET(BBITEMDATA, OriginalLocation) + (sizeof(L"C:\\X") * 2); + const UINT minsize = minfs + mindatasize + sizeof(BBITEMFOOTER); + const BYTE type = _ILGetType(pidl); + if ((type == BBITEMFILETYPE || type == BBITEMFOLDERTYPE) && pidl->mkid.cb >= minsize) + { + BBITEMFOOTER *pEnd = (BBITEMFOOTER*)((BYTE*)pidl + pidl->mkid.cb - sizeof(BBITEMFOOTER)); + if (pEnd->EndSignature == BBITEMFOOTER::ENDSIG && pEnd->DataSize >= mindatasize) + return (BBITEMDATA*)((BYTE*)pEnd - pEnd->DataSize); + } + return NULL; +} + +static LPITEMIDLIST CreateItem(LPCWSTR pszTrash, LPCWSTR pszOrig, const DELETED_FILE_INFO &Details) +{ + const BOOL folder = Details.Attributes & FILE_ATTRIBUTE_DIRECTORY; + LPCWSTR pszName = PathFindFileNameW(pszTrash); + SIZE_T ofsName = (SIZE_T)(pszName - pszTrash); + SIZE_T cchName = wcslen(pszName) + 1, cbName = cchName * sizeof(WCHAR); + SIZE_T cbFSNames = cbName + sizeof("") + 1; // Empty short name + 1 for WORD alignment + SIZE_T cbFS = sizeof(WORD) + FIELD_OFFSET(PIDLDATA, u.file.szNames) + cbFSNames; + SIZE_T cchTrash = ofsName + cchName, cbTrash = cchTrash * sizeof(WCHAR); + SIZE_T cchOrig = wcslen(pszOrig) + 1, cbOrig = cchOrig * sizeof(WCHAR); + SIZE_T cbData = FIELD_OFFSET(BBITEMDATA, OriginalLocation) + cbOrig + cbTrash; + SIZE_T cb = cbFS + cbData + sizeof(BBITEMFOOTER); + if (cb > 0xffff) + return NULL; + LPITEMIDLIST pidl = (LPITEMIDLIST)SHAlloc(cb + sizeof(WORD)); + if (!pidl) + return pidl; + + pidl->mkid.cb = cb; + pidl->mkid.abID[0] = folder ? BBITEMFOLDERTYPE : BBITEMFILETYPE; + ILGetNext(pidl)->mkid.cb = 0; // Terminator + FileStruct &fsitem = ((PIDLDATA*)pidl->mkid.abID)->u.file; + fsitem.dummy = 0; + C_ASSERT(sizeof(RECYCLEBINFILESIZETYPE) <= sizeof(fsitem.dwFileSize)); + fsitem.dwFileSize = Details.FileSize; + fsitem.uFileAttribs = LOWORD(Details.Attributes); + FileTimeToDosDateTime(&Details.LastModification, &fsitem.uFileDate, &fsitem.uFileTime); + CopyMemory(fsitem.szNames, pszName, cbName); + LPSTR pszShort = const_cast<LPSTR>(&fsitem.szNames[cbName]); + pszShort[0] = '\0'; + pszShort[1] = '\0'; // Fill alignment padding (for ILIsEqual memcmp) + + BBITEMFOOTER *footer = (BBITEMFOOTER*)((BYTE*)pidl + cb - sizeof(BBITEMFOOTER)); + footer->DataSize = cbData; + footer->EndSignature = BBITEMFOOTER::ENDSIG; + + BBITEMDATA *data = (BBITEMDATA*)((BYTE*)footer - footer->DataSize); + data->DeletionTime = Details.DeletionTime; +#ifdef COLUMN_FATTS + data->AttribsHi = HIWORD(Details.Attributes); +#endif + data->RecycledPathOffset = FIELD_OFFSET(BBITEMDATA, OriginalLocation) + cbOrig; + CopyMemory(data->OriginalLocation, pszOrig, cbOrig); + CopyMemory((BYTE*)data + data->RecycledPathOffset, pszTrash, cbTrash); + + assert(!(((SIZE_T)&fsitem.szNames) & 1)); // WORD aligned please + C_ASSERT(!(FIELD_OFFSET(BBITEMDATA, OriginalLocation) & 1)); // WORD aligned please + assert(!(((SIZE_T)data) & 1)); // WORD aligned please + assert(_ILGetFSType(pidl)); + assert(_ILIsPidlSimple(pidl)); + assert(*(WORD*)((BYTE*)pidl + pidl->mkid.cb - sizeof(WORD)) & 1); // ENDSIG bit + assert(_ILGetFileStructW(pidl) == NULL); // Our custom footer is incompatible with WinXP pidl data + assert(ValidateItem(pidl) == data); + return pidl; +} + +static inline UINT GetItemFileSize(LPCITEMIDLIST pidl) +{ + return _ILGetFSType(pidl) ? ((PIDLDATA*)pidl->mkid.abID)->u.file.dwFileSize : 0; +} + +static inline LPCWSTR GetItemOriginalFullPath(const BBITEMDATA &Data) +{ + return Data.OriginalLocation; +} + +static HRESULT GetItemOriginalFolder(const BBITEMDATA &Data, LPWSTR &Out) +{ + HRESULT hr = SHStrDupW(GetItemOriginalFullPath(Data), &Out); + if (SUCCEEDED(hr)) + PathRemoveFileSpecW(Out); + return hr; +} + +static LPCWSTR GetItemOriginalFileName(const BBITEMDATA &Data) +{ + return PathFindFileNameW(GetItemOriginalFullPath(Data)); +} + +static inline LPCWSTR GetItemRecycledFullPath(const BBITEMDATA &Data) +{ + return (LPCWSTR)((BYTE*)&Data + Data.RecycledPathOffset); +} + +static inline LPCWSTR GetItemRecycledFileName(LPCITEMIDLIST pidl, const BBITEMDATA &Data) +{ + C_ASSERT(BBITEMFILETYPE & PT_FS_UNICODE_FLAG); + return (LPCWSTR)((LPPIDLDATA)pidl->mkid.abID)->u.file.szNames; +} + +static int GetItemDriveNumber(LPCITEMIDLIST pidl) +{ + if (BBITEMDATA *pData = ValidateItem(pidl)) + return PathGetDriveNumberW(GetItemRecycledFullPath(*pData)); + WCHAR buf[MAX_PATH]; + return _ILSimpleGetTextW(pidl, buf, _countof(buf)) ? PathGetDriveNumberW(buf) : -1; +} + +static HRESULT GetItemTypeName(PCUITEMID_CHILD pidl, const BBITEMDATA &Data, SHFILEINFOW &shfi) +{ + LPCWSTR path = GetItemRecycledFullPath(Data); + UINT attribs = ((PIDLDATA*)pidl->mkid.abID)->u.file.uFileAttribs; + if (SHGetFileInfoW(path, attribs, &shfi, sizeof(shfi), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES)) + return S_OK; + shfi.szTypeName[0] = UNICODE_NULL; + return E_FAIL; +} + +static HDELFILE GetRecycleBinFileHandleFromItem(const BBITEMDATA &Data) +{ + RECYCLEBINFILEIDENTITY identity = { Data.DeletionTime, GetItemRecycledFullPath(Data) }; + return GetRecycleBinFileHandle(NULL, &identity); +} + /* * Recycle Bin folder */ -BOOL WINAPI CBSearchRecycleBin(IN PVOID Context, IN HDELFILE hDeletedFile); - -static PIDLRecycleStruct * _ILGetRecycleStruct(LPCITEMIDLIST pidl); +static UINT GetDefaultRecycleDriveNumber() +{ + int drive = 0; + WCHAR buf[MAX_PATH]; + if (GetWindowsDirectoryW(buf, _countof(buf))) + drive = PathGetDriveNumberW(buf); + return max(0, drive); +} -typedef struct _SEARCH_CONTEXT +static inline LPCWSTR GetGlobalRecycleBinPath() { - PIDLRecycleStruct *pFileDetails; - HDELFILE hDeletedFile; - BOOL bFound; -} SEARCH_CONTEXT, *PSEARCH_CONTEXT; + return NULL; +} -HRESULT CRecyclerExtractIcon_CreateInstance( - LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut) +static BOOL IsRecycleBinEmpty(IShellFolder *pSF) { - PIDLRecycleStruct *pFileDetails = _ILGetRecycleStruct(pidl); - if (pFileDetails == NULL) - goto fallback; + CComPtr<IEnumIDList> spEnumFiles; + HRESULT hr = pSF->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &spEnumFiles); + CComHeapPtr<ITEMIDLIST> spPidl; + ULONG itemcount; + return FAILED(hr) || spEnumFiles->Next(1, &spPidl, &itemcount) != S_OK; +} - // Try to obtain the file - SEARCH_CONTEXT Context; - Context.pFileDetails = pFileDetails; - Context.bFound = FALSE; +static void CRecycleBin_ChangeNotifyBBItem(_In_ LONG Event, _In_opt_ LPCITEMIDLIST BBItem) +{ + LPITEMIDLIST pidlFolder = SHCloneSpecialIDList(NULL, CSIDL_BITBUCKET, FALSE); + if (!pidlFolder) + return; + if (BBItem) + { + assert(ValidateItem(BBItem)); + if (LPITEMIDLIST pidlFull = ILCombine(pidlFolder, BBItem)) + { + // Send notification for [Desktop][RecycleBin][BBItem] + // FIXME: Windows monitors each RecycleBin FS folder on every drive + // instead of manually sending these? + SHChangeNotify(Event, SHCNF_IDLIST, pidlFull, NULL); + ILFree(pidlFull); + } + } + else + { + SHChangeNotify(Event, SHCNF_IDLIST, pidlFolder, NULL); + } + ILFree(pidlFolder); +} - EnumerateRecycleBinW(NULL, CBSearchRecycleBin, &Context); - if (Context.bFound) +EXTERN_C void CRecycleBin_NotifyRecycled(LPCWSTR OrigPath, const WIN32_FIND_DATAW *pFind, + const RECYCLEBINFILEIDENTITY *pFI) +{ + DELETED_FILE_INFO info; + info.LastModification = pFind->ftLastWriteTime; + info.DeletionTime = pFI->DeletionTime; + info.FileSize = pFind->nFileSizeLow; + info.Attributes = pFind->dwFileAttributes; + if (LPITEMIDLIST pidl = CreateItem(pFI->RecycledFullPath, OrigPath, info)) { - // This should be executed any time, if not, there are some errors in the implementation - IRecycleBinFile* pRecycleFile = (IRecycleBinFile*)Context.hDeletedFile; + CRecycleBin_ChangeNotifyBBItem(IsFolder(pidl) ? SHCNE_MKDIR : SHCNE_CREATE, pidl); + ILFree(pidl); + } +} - // Query the interface from the private interface - HRESULT hr = pRecycleFile->QueryInterface(riid, ppvOut); +static void CRecycleBin_NotifyRemovedFromRecycleBin(LPCITEMIDLIST BBItem) +{ + CRecycleBin_ChangeNotifyBBItem(IsFolder(BBItem) ? SHCNE_RMDIR : SHCNE_DELETE, BBItem); - // Close the file handle as we don't need it anymore - CloseRecycleBinHandle(Context.hDeletedFile); + CComHeapPtr<ITEMIDLIST> pidlBB(SHCloneSpecialIDList(NULL, CSIDL_BITBUCKET, FALSE)); + CComPtr<IShellFolder> pSF; + if (pidlBB && SUCCEEDED(SHBindToObject(NULL, pidlBB, IID_PPV_ARG(IShellFolder, &pSF)))) + { + if (IsRecycleBinEmpty(pSF)) + SHUpdateRecycleBinIcon(); + } +} +static HRESULT CRecyclerExtractIcon_CreateInstance( + IShellFolder &FSFolder, LPCITEMIDLIST pidl, REFIID riid, LPVOID *ppvOut) +{ + HRESULT hr = FSFolder.GetUIObjectOf(NULL, 1, &pidl, riid, NULL, ppvOut); + if (SUCCEEDED(hr)) return hr; - } -fallback: // In case the search fails we use a default icon ERR("Recycler could not retrieve the icon, this shouldn't happen\n"); - CComPtr<IDefaultExtractIconInit> initIcon; - HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon)); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - initIcon->SetNormalIcon(swShell32Name, 0); - - return initIcon->QueryInterface(riid, ppvOut); + if (IsFolder(pidl)) + return SHELL_CreateFallbackExtractIconForFolder(riid, ppvOut); + else + return SHELL_CreateFallbackExtractIconForNoAssocFile(riid, ppvOut); } -class CRecycleBinEnum : - public CEnumIDListBase -{ - private: - public: - CRecycleBinEnum(); - ~CRecycleBinEnum(); - HRESULT WINAPI Initialize(DWORD dwFlags); - static BOOL WINAPI CBEnumRecycleBin(IN PVOID Context, IN HDELFILE hDeletedFile); - BOOL WINAPI CBEnumRecycleBin(IN HDELFILE hDeletedFile); - - BEGIN_COM_MAP(CRecycleBinEnum) - COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) - END_COM_MAP() -}; - class CRecycleBinItemContextMenu : public CComObjectRootEx<CComMultiThreadModelNoCS>, public IContextMenu2 @@ -155,63 +336,23 @@ class CRecycleBinItemContextMenu : END_COM_MAP() }; -BOOL WINAPI CBSearchRecycleBin(IN PVOID Context, IN HDELFILE 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) +class CRecycleBinEnum : + public CEnumIDListBase { - LPPIDLDATA pdata = _ILGetDataPointer(pidl); - - if (pdata && pdata->type == 0x00) - return (PIDLRecycleStruct*) & (pdata->u.crecycle); + public: + CRecycleBinEnum(); + ~CRecycleBinEnum(); + HRESULT WINAPI Initialize(DWORD dwFlags); + BOOL CBEnumRecycleBin(IN HDELFILE hDeletedFile); + static BOOL CALLBACK CBEnumRecycleBin(IN PVOID Context, IN HDELFILE hDeletedFile) + { + return static_cast<CRecycleBinEnum*>(Context)->CBEnumRecycleBin(hDeletedFile); + } - return NULL; -} + BEGIN_COM_MAP(CRecycleBinEnum) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) + END_COM_MAP() +}; CRecycleBinEnum::CRecycleBinEnum() { @@ -223,14 +364,7 @@ CRecycleBinEnum::~CRecycleBinEnum() HRESULT WINAPI CRecycleBinEnum::Initialize(DWORD dwFlags) { - WCHAR szDrive[8]; - if (!GetEnvironmentVariableW(L"SystemDrive", szDrive, _countof(szDrive) - 1)) - { - ERR("GetEnvironmentVariableW failed\n"); - return E_FAIL; - } - PathAddBackslashW(szDrive); - + LPCWSTR szDrive = GetGlobalRecycleBinPath(); if (dwFlags & SHCONTF_NONFOLDERS) { TRACE("Starting Enumeration\n"); @@ -248,83 +382,25 @@ HRESULT WINAPI CRecycleBinEnum::Initialize(DWORD dwFlags) 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 CRecycleBinEnum::CBEnumRecycleBin(IN PVOID Context, IN HDELFILE hDeletedFile) +BOOL CRecycleBinEnum::CBEnumRecycleBin(IN HDELFILE hDeletedFile) { - return static_cast<CRecycleBinEnum *>(Context)->CBEnumRecycleBin(hDeletedFile); -} - -BOOL WINAPI CRecycleBinEnum::CBEnumRecycleBin(IN HDELFILE hDeletedFile) -{ - PDELETED_FILE_DETAILS_W pFileDetails; - DWORD dwSize; LPITEMIDLIST pidl = NULL; - BOOL ret; - - if (!GetDeletedFileDetailsW(hDeletedFile, - 0, - NULL, - &dwSize) && - GetLastError() != ERROR_INSUFFICIENT_BUFFER) + DELETED_FILE_INFO info; + IRecycleBinFile *pRBF = IRecycleBinFileFromHDELFILE(hDeletedFile); + BOOL ret = SUCCEEDED(pRBF->GetInfo(&info)); + if (ret) { - ERR("GetDeletedFileDetailsW failed\n"); - return FALSE; - } - - pFileDetails = (DELETED_FILE_DETAILS_W *)SHAlloc(dwSize); - if (!pFileDetails) - { - ERR("No memory\n"); - return FALSE; + pidl = CreateItem(info.RecycledFullPath.String, info.OriginalFullPath.String, info); + ret = pidl != NULL; + FreeRecycleBinString(&info.OriginalFullPath); + FreeRecycleBinString(&info.RecycledFullPath); } - - if (!GetDeletedFileDetailsW(hDeletedFile, - dwSize, - pFileDetails, - NULL)) + if (pidl) { - ERR("GetDeletedFileDetailsW failed\n"); - SHFree(pFileDetails); - return FALSE; + ret = AddToEnumList(pidl); + if (!ret) + ILFree(pidl); } - - 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; } @@ -351,99 +427,122 @@ HRESULT WINAPI CRecycleBinItemContextMenu::Initialize(LPCITEMIDLIST pidl) return S_OK; } +enum { IDC_BB_RESTORE = 1, IDC_BB_CUT, IDC_BB_DELETE, IDC_BB_PROPERTIES }; +static const CMVERBMAP g_BBItemVerbMap[] = +{ + { "undelete", IDC_BB_RESTORE }, + { "cut", IDC_BB_CUT }, + { "delete", IDC_BB_DELETE }, + { "properties", IDC_BB_PROPERTIES }, + { NULL } +}; + HRESULT WINAPI CRecycleBinItemContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { - WCHAR szBuffer[30] = {0}; - ULONG Count = 1; + UINT idHigh = 0, id; 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, _countof(szBuffer))) + id = idCmdFirst + IDC_BB_RESTORE; + if (_InsertMenuItemW(hMenu, indexMenu, TRUE, id, MFT_STRING, MAKEINTRESOURCEW(IDS_RESTORE), 0)) { - szBuffer[_countof(szBuffer)-1] = L'\0'; - _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED); - Count++; + idHigh = max(idHigh, id); + indexMenu++; } - - if (LoadStringW(shell32_hInstance, IDS_CUT, szBuffer, _countof(szBuffer))) + id = idCmdFirst + IDC_BB_CUT; + if (_InsertMenuItemW(hMenu, indexMenu, TRUE, id, MFT_STRING, MAKEINTRESOURCEW(IDS_CUT), MFS_DISABLED)) { - _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); - szBuffer[_countof(szBuffer)-1] = L'\0'; - _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED); + idHigh = max(idHigh, id); + if (_InsertMenuItemW(hMenu, indexMenu++, TRUE, -1, MFT_SEPARATOR, NULL, 0)) + indexMenu++; } - - if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, _countof(szBuffer))) + id = idCmdFirst + IDC_BB_DELETE; + if (_InsertMenuItemW(hMenu, indexMenu, TRUE, id, MFT_STRING, MAKEINTRESOURCEW(IDS_DELETE), 0)) { - szBuffer[_countof(szBuffer)-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); + idHigh = max(idHigh, id); + if (_InsertMenuItemW(hMenu, indexMenu++, TRUE, -1, MFT_SEPARATOR, NULL, 0)) + indexMenu++; } - - if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, _countof(szBuffer))) + id = idCmdFirst + IDC_BB_PROPERTIES; + if (_InsertMenuItemW(hMenu, indexMenu, TRUE, id, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), 0)) { - szBuffer[_countof(szBuffer)-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); + idHigh = max(idHigh, id); + if (_InsertMenuItemW(hMenu, indexMenu++, TRUE, -1, MFT_SEPARATOR, NULL, 0)) + indexMenu++; } + return idHigh ? MAKE_HRESULT(SEVERITY_SUCCESS, 0, idHigh - idCmdFirst + 1) : S_OK; +} - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count); +static BOOL ConfirmDelete(LPCMINVOKECOMMANDINFO lpcmi, UINT cidl, LPCITEMIDLIST pidl, const BBITEMDATA &Data) +{ + if (lpcmi->fMask & CMIC_MASK_FLAG_NO_UI) + { + return TRUE; + } + else if (cidl == 1) + { + const UINT ask = IsFolder(pidl) ? ASK_DELETE_FOLDER : ASK_DELETE_FILE; + return SHELL_ConfirmYesNoW(lpcmi->hwnd, ask, GetItemOriginalFileName(Data)); + } + WCHAR buf[MAX_PATH]; + wsprintfW(buf, L"%d", cidl); + return SHELL_ConfirmYesNoW(lpcmi->hwnd, ASK_DELETE_MULTIPLE_ITEM, buf); } HRESULT WINAPI CRecycleBinItemContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) { - SEARCH_CONTEXT Context; - WCHAR szDrive[8]; - 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; + int CmdId = SHELL_MapContextMenuVerbToCmdId(lpcmi, g_BBItemVerbMap); - if (!GetEnvironmentVariableW(L"SystemDrive", szDrive, _countof(szDrive) - 1)) - { - ERR("GetEnvironmentVariableW failed\n"); - return E_FAIL; - } - PathAddBackslashW(szDrive); + // Handle DefView accelerators + if ((SIZE_T)lpcmi->lpVerb == FCIDM_SHVIEW_CUT) + CmdId = IDC_BB_CUT; + if ((SIZE_T)lpcmi->lpVerb == FCIDM_SHVIEW_DELETE) + CmdId = IDC_BB_DELETE; + if ((SIZE_T)lpcmi->lpVerb == FCIDM_SHVIEW_PROPERTIES) + CmdId = IDC_BB_PROPERTIES; - EnumerateRecycleBinW(szDrive, CBSearchRecycleBin, (PVOID)&Context); - if (!Context.bFound) + if (CmdId == IDC_BB_RESTORE || CmdId == IDC_BB_DELETE) + { + BBITEMDATA *pData = ValidateItem(apidl); + if (!pData && FAILED_UNEXPECTEDLY(E_FAIL)) + return E_FAIL; + HDELFILE hDelFile = GetRecycleBinFileHandleFromItem(*pData); + if (!hDelFile && FAILED_UNEXPECTEDLY(E_FAIL)) return E_FAIL; - BOOL ret = TRUE; - - /* restore file */ - if (lpcmi->lpVerb == MAKEINTRESOURCEA(1)) - ret = RestoreFile(Context.hDeletedFile); - /* delete file */ - else - DeleteFileHandleToRecycleBin(Context.hDeletedFile); + HRESULT hr = S_FALSE; + if (CmdId == IDC_BB_RESTORE) + hr = RestoreFileFromRecycleBin(hDelFile) ? S_OK : E_FAIL; + else if (ConfirmDelete(lpcmi, 1, apidl, *pData)) + hr = DeleteFileInRecycleBin(hDelFile) ? S_OK : E_FAIL; - CloseRecycleBinHandle(Context.hDeletedFile); + if (hr == S_OK) + CRecycleBin_NotifyRemovedFromRecycleBin(apidl); - return (ret ? S_OK : E_FAIL); + CloseRecycleBinHandle(hDelFile); + return hr; } - else if (lpcmi->lpVerb == MAKEINTRESOURCEA(3)) + else if (CmdId == IDC_BB_CUT) { FIXME("implement cut\n"); + SHELL_ErrorBox(lpcmi->hwnd, ERROR_NOT_SUPPORTED); return E_NOTIMPL; } - else if (lpcmi->lpVerb == MAKEINTRESOURCEA(7)) + else if (CmdId == IDC_BB_PROPERTIES) { FIXME("implement properties\n"); + SHELL_ErrorBox(lpcmi->hwnd, ERROR_NOT_SUPPORTED); return E_NOTIMPL; } - - return S_OK; + return E_UNEXPECTED; } HRESULT WINAPI CRecycleBinItemContextMenu::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; + return SHELL_GetCommandStringImpl(idCommand, uFlags, lpszName, uMaxNameLen, g_BBItemVerbMap); } HRESULT WINAPI CRecycleBinItemContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -456,11 +555,47 @@ HRESULT WINAPI CRecycleBinItemContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wPara CRecycleBin::CRecycleBin() { pidl = NULL; + ZeroMemory(m_pFSFolders, sizeof(m_pFSFolders)); } CRecycleBin::~CRecycleBin() { SHFree(pidl); + for (SIZE_T i = 0; i < _countof(m_pFSFolders); ++i) + { + if (m_pFSFolders[i]) + m_pFSFolders[i]->Release(); + } +} + +IShellFolder* CRecycleBin::GetFSFolderForItem(LPCITEMIDLIST pidl) +{ + int drive = GetItemDriveNumber(pidl); + if (drive < 0) + drive = GetDefaultRecycleDriveNumber(); + if ((UINT)drive >= _countof(m_pFSFolders) && FAILED_UNEXPECTEDLY(E_FAIL)) + return NULL; + + if (!m_pFSFolders[drive]) + { + HRESULT hr; + PERSIST_FOLDER_TARGET_INFO pfti = {}; + if (FAILED_UNEXPECTEDLY(hr = GetRecycleBinPathFromDriveNumber(drive, pfti.szTargetParsingName))) + return NULL; + pfti.dwAttributes = FILE_ATTRIBUTE_DIRECTORY; + pfti.csidl = -1; + CComHeapPtr<ITEMIDLIST> pidlRoot; + pidlRoot.Attach(SHELL32_CreateSimpleIDListFromPath(pfti.szTargetParsingName, pfti.dwAttributes)); + if (!pidlRoot && FAILED_UNEXPECTEDLY(E_FAIL)) + return NULL; + IShellFolder *psf; + hr = SHELL32_CoCreateInitSF(pidlRoot, &pfti, NULL, &CLSID_ShellFSFolder, IID_PPV_ARG(IShellFolder, &psf)); + if (FAILED(hr)) + return NULL; + m_pFSFolders[drive] = psf; // Reference count is 1 (for the m_pFSFolders cache) + } + m_pFSFolders[drive]->AddRef(); // AddRef for the caller + return m_pFSFolders[drive]; } /************************************************************************* @@ -472,7 +607,7 @@ HRESULT WINAPI CRecycleBin::GetClassID(CLSID *pClassID) TRACE("(%p, %p)\n", this, pClassID); if (pClassID == NULL) return E_INVALIDARG; - memcpy(pClassID, &CLSID_RecycleBin, sizeof(CLSID)); + *pClassID = GetClassID(); return S_OK; } @@ -490,8 +625,7 @@ HRESULT WINAPI CRecycleBin::Initialize(PCIDLIST_ABSOLUTE pidl) HRESULT WINAPI CRecycleBin::GetCurFolder(PIDLIST_ABSOLUTE *ppidl) { TRACE("\n"); - *ppidl = ILClone(pidl); - return S_OK; + return SHILClone((LPCITEMIDLIST)pidl, ppidl); } /************************************************************************* @@ -503,14 +637,7 @@ HRESULT WINAPI CRecycleBin::ParseDisplayName(HWND hwnd, LPBC pbc, ULONG *pdwAttributes) { FIXME("stub\n"); - return E_NOTIMPL; -} - - -PDELETED_FILE_DETAILS_W -UnpackDetailsFromPidl(LPCITEMIDLIST pidl) -{ - return (PDELETED_FILE_DETAILS_W)&pidl->mkid.abID; + return E_NOTIMPL; // FIXME: Parse "D<Drive><UniqueId>.ext" } HRESULT WINAPI CRecycleBin::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) @@ -530,40 +657,82 @@ HRESULT WINAPI CRecycleBin::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbc, REF return E_NOTIMPL; } -HRESULT WINAPI CRecycleBin::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) +static HRESULT CompareCanonical(const BBITEMDATA &Data1, const BBITEMDATA &Data2) { - PIDLRecycleStruct* pData1 = _ILGetRecycleStruct(pidl1); - PIDLRecycleStruct* pData2 = _ILGetRecycleStruct(pidl2); - LPWSTR pName1, pName2; + // This assumes two files with the same original path cannot be deleted at + // the same time (within the FAT/NTFS FILETIME resolution). + int result = CompareFileTime(&Data1.DeletionTime, &Data2.DeletionTime); + if (result == 0) + result = _wcsicmp(GetItemOriginalFullPath(Data1), GetItemOriginalFullPath(Data2)); + return MAKE_COMPARE_HRESULT(result); +} - if(!pData1 || !pData2 || LOWORD(lParam) >= COLUMNS_COUNT) +HRESULT WINAPI CRecycleBin::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) +{ + UINT column = UINT(lParam & SHCIDS_COLUMNMASK); + if (column >= COLUMNS_COUNT || !_ILGetFSType(pidl1) || !_ILGetFSType(pidl2)) + return E_INVALIDARG; + BBITEMDATA *pData1 = ValidateItem(pidl1), *pData2 = ValidateItem(pidl2); + if ((!pData1 || !pData2) && column != COLUMN_NAME) return E_INVALIDARG; - SHORT result; - LONGLONG diff; - switch (LOWORD(lParam)) + LPCWSTR pName1, pName2; + FILETIME ft1, ft2; + SHFILEINFOW shfi1, shfi2; + int result; + HRESULT hr = CFSFolder::CompareSortFoldersFirst(pidl1, pidl2); + if (SUCCEEDED(hr)) + return hr; + switch (column) { - case 0: /* Name */ - pName1 = PathFindFileNameW(pData1->szName); - pName2 = PathFindFileNameW(pData2->szName); - result = _wcsicmp(pName1, pName2); - break; - case 1: /* Orig. Location */ - result = _wcsicmp(pData1->szName, pData2->szName); + case COLUMN_NAME: + if (pData1 && pData2) + { + if (lParam & SHCIDS_CANONICALONLY) + return CompareCanonical(*pData1, *pData2); + pName1 = GetItemOriginalFileName(*pData1); + pName2 = GetItemOriginalFileName(*pData2); + result = CFSFolder::CompareUiStrings(pName1, pName2); + } + else + { + // We support comparing names even for non-Recycle items because + // SHChangeNotify can broadcast regular FS items. + if (IShellFolder *pSF = GetFSFolderForItem(pidl1)) + { + hr = pSF->CompareIDs(lParam, pidl1, pidl2); + pSF->Release(); + return hr; + } + return E_INVALIDARG; + } break; - case 2: /* Date Deleted */ + case COLUMN_DELFROM: + if (SUCCEEDED(hr = GetItemOriginalFolder(*pData1, const_cast<LPWSTR&>(pName1)))) + { + if (SUCCEEDED(hr = GetItemOriginalFolder(*pData2, const_cast<LPWSTR&>(pName2)))) + { + result = CFSFolder::CompareUiStrings(pName1, pName2); + SHFree(const_cast<LPWSTR>(pName2)); + } + SHFree(const_cast<LPWSTR>(pName1)); + } + return SUCCEEDED(hr) ? MAKE_COMPARE_HRESULT(result) : hr; + case COLUMN_DATEDEL: result = CompareFileTime(&pData1->DeletionTime, &pData2->DeletionTime); break; - case 3: /* Size */ - diff = pData1->FileSize.QuadPart - pData2->FileSize.QuadPart; - return MAKE_COMPARE_HRESULT(diff); - case 4: /* Type */ - pName1 = PathFindExtensionW(pData1->szName); - pName2 = PathFindExtensionW(pData2->szName); - result = _wcsicmp(pName1, pName2); + case COLUMN_SIZE: + result = GetItemFileSize(pidl1) - GetItemFileSize(pidl2); + break; + case COLUMN_TYPE: + GetItemTypeName(pidl1, *pData1, shfi1); + GetItemTypeName(pidl2, *pData2, shfi2); + result = CFSFolder::CompareUiStrings(shfi1.szTypeName, shfi2.szTypeName); break; - case 5: /* Modified */ - result = CompareFileTime(&pData1->LastModification, &pData2->LastModification); + case COLUMN_MTIME: + _ILGetFileDateTime(pidl1, &ft1); + _ILGetFileDateTime(pidl2, &ft2); + result = CompareFileTime(&ft1, &ft2); break; } return MAKE_COMPARE_HRESULT(result); @@ -578,7 +747,6 @@ HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void * if (!ppv) return hr; - *ppv = NULL; if (IsEqualIID (riid, IID_IDropTarget)) @@ -587,11 +755,12 @@ HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void * } else if (IsEqualIID (riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2)) { + m_IsBackgroundMenu = true; hr = this->QueryInterface(riid, ppv); } else if (IsEqualIID (riid, IID_IShellView)) { - SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; + SFV_CREATE sfvparams = { sizeof(SFV_CREATE), this }; hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppv); } else @@ -606,8 +775,26 @@ HRESULT WINAPI CRecycleBin::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY api SFGAOF *rgfInOut) { TRACE("(%p, %d, {%p, ...}, {%x})\n", this, cidl, apidl ? apidl[0] : NULL, (unsigned int)*rgfInOut); - *rgfInOut &= SFGAO_FOLDER|SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANLINK; - return S_OK; + HRESULT hr = S_OK; + const SFGAOF ThisFolder = SFGAO_FOLDER | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET | SFGAO_CANRENAME | SFGAO_CANLINK; + if (!cidl) + { + *rgfInOut &= ThisFolder; + if (SHRestricted(REST_BITBUCKNOPROP)) + *rgfInOut &= ~SFGAO_HASPROPSHEET; + return hr; + } + SFGAOF remain = SFGAO_LINK & *rgfInOut; + *rgfInOut &= remain | SFGAO_HASPROPSHEET | SFGAO_CANDELETE | SFGAO_FILESYSTEM; // TODO: SFGAO_CANMOVE + for (UINT i = 0; (*rgfInOut & remain) && i < cidl && SUCCEEDED(hr); ++i) + { + if (IShellFolder* pSF = GetFSFolderForItem(apidl[i])) + { + hr = pSF->GetAttributesOf(1, &apidl[i], rgfInOut); + pSF->Release(); + } + } + return hr; } HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, @@ -623,14 +810,20 @@ HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_C return hr; *ppv = NULL; + assert(!cidl || (apidl && apidl[0])); if ((IsEqualIID (riid, IID_IContextMenu) || IsEqualIID(riid, IID_IContextMenu2)) && (cidl >= 1)) { + // FIXME: Handle multiple items hr = ShellObjectCreatorInit<CRecycleBinItemContextMenu>(apidl[0], riid, &pObj); } else if((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1)) { - hr = CRecyclerExtractIcon_CreateInstance(apidl[0], riid, &pObj); + if (IShellFolder *pSF = GetFSFolderForItem(apidl[0])) + { + hr = CRecyclerExtractIcon_CreateInstance(*pSF, apidl[0], riid, &pObj); + pSF->Release(); + } } else hr = E_NOINTERFACE; @@ -645,33 +838,36 @@ HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_C HRESULT WINAPI CRecycleBin::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET *pName) { - PIDLRecycleStruct *pFileDetails; - LPWSTR pFileName; - TRACE("(%p, %p, %x, %p)\n", this, pidl, (unsigned int)uFlags, pName); + const BBITEMDATA *pData = ValidateItem(pidl); + if (!pData) + return E_INVALIDARG; - pFileDetails = _ILGetRecycleStruct(pidl); - if (!pFileDetails) + if (IS_SHGDN_FOR_PARSING(uFlags)) { - pName->cStr[0] = 0; - pName->uType = STRRET_CSTR; - return E_INVALIDARG; + LPCWSTR pszName = GetItemRecycledFullPath(*pData); + if (uFlags & SHGDN_INFOLDER) + pszName = PathFindFileNameW(pszName); + pName->pOleStr = SHStrDupW(pszName); } - - pFileName = wcsrchr(pFileDetails->szName, L'\\'); - if (!pFileName) + else { - pName->cStr[0] = 0; - pName->uType = STRRET_CSTR; - return E_UNEXPECTED; + if (uFlags & SHGDN_INFOLDER) + pName->pOleStr = SHStrDupW(GetItemOriginalFileName(*pData)); + else + pName->pOleStr = SHStrDupW(GetItemOriginalFullPath(*pData)); } - pName->pOleStr = StrDupW(pFileName + 1); - if (pName->pOleStr == NULL) - return E_OUTOFMEMORY; - - pName->uType = STRRET_WSTR; - return S_OK; + if (pName->pOleStr) + { + pName->uType = STRRET_WSTR; + if (!IsFolder(pidl)) + SHELL_FS_ProcessDisplayFilename(pName->pOleStr, uFlags); + return S_OK; + } + pName->uType = STRRET_CSTR; + pName->cStr[0] = '\0'; + return E_OUTOFMEMORY; } HRESULT WINAPI CRecycleBin::SetNameOf(HWND hwnd, PCUITEMID_CHILD pidl, LPCOLESTR pszName, @@ -719,33 +915,12 @@ HRESULT WINAPI CRecycleBin::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID 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 < size) - { - /* Append space + time without seconds */ - buffer[ret-1] = ' '; - GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &buffer[ret], size - ret); - } - - return (ret != 0 ? E_FAIL : S_OK); -} - HRESULT WINAPI CRecycleBin::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, LPSHELLDETAILS pDetails) { - PIDLRecycleStruct * pFileDetails; + HRESULT hr; + FILETIME ft; + SHFILEINFOW shfi; WCHAR buffer[MAX_PATH]; - WCHAR szTypeName[100]; - LPWSTR pszBackslash; - UINT Length; TRACE("(%p, %p, %d, %p)\n", this, pidl, iColumn, pDetails); if (iColumn >= COLUMNS_COUNT) @@ -759,66 +934,36 @@ HRESULT WINAPI CRecycleBin::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, LPS } if (iColumn == COLUMN_NAME) - return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str); + return GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &pDetails->str); - pFileDetails = _ILGetRecycleStruct(pidl); - if (!pFileDetails && FAILED_UNEXPECTEDLY(E_INVALIDARG)) + const BBITEMDATA *pData = ValidateItem(pidl); + if (!pData && FAILED_UNEXPECTEDLY(E_INVALIDARG)) return E_INVALIDARG; + switch (iColumn) { case COLUMN_DATEDEL: - FormatDateTime(buffer, MAX_PATH, &pFileDetails->DeletionTime); + CFSFolder::FormatDateTime(pData->DeletionTime, buffer, _countof(buffer)); break; case COLUMN_DELFROM: - pszBackslash = wcsrchr(pFileDetails->szName, L'\\'); - if (!pszBackslash) - { - ERR("Filename '%ls' not a valid path?\n", pFileDetails->szName); - Length = 0; - } - else - { - Length = (pszBackslash - pFileDetails->szName); - memcpy((LPVOID)buffer, pFileDetails->szName, Length * sizeof(WCHAR)); - } - buffer[Length] = UNICODE_NULL; - if (buffer[0] && buffer[1] == L':' && !buffer[2]) - { - buffer[2] = L'\\'; - buffer[3] = UNICODE_NULL; - } - break; + if (SUCCEEDED(hr = GetItemOriginalFolder(*pData, pDetails->str.pOleStr))) + pDetails->str.uType = STRRET_WSTR; + return hr; case COLUMN_SIZE: - StrFormatKBSizeW(pFileDetails->FileSize.QuadPart, buffer, MAX_PATH); + *buffer = UNICODE_NULL; + if (!IsFolder(pidl)) + CFSFolder::FormatSize(GetItemFileSize(pidl), buffer, _countof(buffer)); break; case COLUMN_MTIME: - FormatDateTime(buffer, MAX_PATH, &pFileDetails->LastModification); + _ILGetFileDateTime(pidl, &ft); + CFSFolder::FormatDateTime(ft, buffer, _countof(buffer)); break; case COLUMN_TYPE: - { - SEARCH_CONTEXT Context; - Context.pFileDetails = pFileDetails; - Context.bFound = FALSE; - EnumerateRecycleBinW(NULL, CBSearchRecycleBin, (PVOID)&Context); - - if (Context.bFound) - { - GetDeletedFileTypeNameW(Context.hDeletedFile, buffer, _countof(buffer), NULL); - - CloseRecycleBinHandle(Context.hDeletedFile); - } - /* load localized file string */ - else if (LoadStringW(shell32_hInstance, IDS_ANY_FILE, szTypeName, _countof(szTypeName))) - { - StringCchPrintfW(buffer, _countof(buffer), szTypeName, PathFindExtensionW(pFileDetails->szName)); - } - - return SHSetStrRet(&pDetails->str, buffer); - } + GetItemTypeName(pidl, *pData, shfi); + return SHSetStrRet(&pDetails->str, shfi.szTypeName); default: return E_FAIL; } - return SHSetStrRet(&pDetails->str, buffer); } @@ -832,85 +977,75 @@ HRESULT WINAPI CRecycleBin::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid) return S_OK; } -BOOL CRecycleBin::RecycleBinIsEmpty() -{ - CComPtr<IEnumIDList> spEnumFiles; - HRESULT hr = EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &spEnumFiles); - if (FAILED(hr)) - return TRUE; - CComHeapPtr<ITEMIDLIST> spPidl; - ULONG itemcount; - return spEnumFiles->Next(1, &spPidl, &itemcount) != S_OK; - } - /************************************************************************* * RecycleBin IContextMenu interface */ -HRESULT WINAPI CRecycleBin::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) +enum { IDC_EMPTYRECYCLEBIN = 1, IDC_PROPERTIES }; +static const CMVERBMAP g_BBFolderVerbMap[] = { - WCHAR szBuffer[100]; - MENUITEMINFOW mii; - int id = 1; + { "empty", IDC_EMPTYRECYCLEBIN }, + { "properties", IDC_PROPERTIES }, + { NULL } +}; +HRESULT WINAPI CRecycleBin::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) +{ TRACE("QueryContextMenu %p %p %u %u %u %u\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags ); if (!hMenu) return E_INVALIDARG; - ZeroMemory(&mii, sizeof(mii)); - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; - mii.fState = RecycleBinIsEmpty() ? MFS_DISABLED : MFS_ENABLED; - szBuffer[0] = L'\0'; - LoadStringW(shell32_hInstance, IDS_EMPTY_BITBUCKET, szBuffer, _countof(szBuffer)); - 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; + UINT idHigh = 0, id; - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id); + WORD state = IsRecycleBinEmpty(this) ? MFS_DISABLED : MFS_ENABLED; + id = idCmdFirst + IDC_EMPTYRECYCLEBIN; + if (_InsertMenuItemW(hMenu, indexMenu, TRUE, id, MFT_STRING, MAKEINTRESOURCEW(IDS_EMPTY_BITBUCKET), state)) + { + idHigh = max(idHigh, id); + if (m_IsBackgroundMenu && !SHRestricted(REST_BITBUCKNOPROP)) + { + id = idCmdFirst + IDC_PROPERTIES; + if (_InsertMenuItemW(hMenu, ++indexMenu, TRUE, id, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), 0)) + { + idHigh = max(idHigh, id); + _InsertMenuItemW(hMenu, indexMenu++, TRUE, -1, MFT_SEPARATOR, NULL, 0); + } + } + } + return idHigh ? MAKE_HRESULT(SEVERITY_SUCCESS, 0, idHigh - idCmdFirst + 1) : S_OK; } HRESULT WINAPI CRecycleBin::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) { - HRESULT hr; - LPSHELLBROWSER lpSB; - IShellView * lpSV = NULL; - WCHAR szDrive[8]; - - TRACE("%p %p verb %p\n", this, lpcmi, lpcmi->lpVerb); - - if (LOWORD(lpcmi->lpVerb) == iIdEmpty) + TRACE("%p %p verb %p\n", this, lpcmi, lpcmi ? lpcmi->lpVerb : NULL); + int CmdId = SHELL_MapContextMenuVerbToCmdId(lpcmi, g_BBFolderVerbMap); + if (CmdId == IDC_EMPTYRECYCLEBIN) { - if (!GetEnvironmentVariableW(L"SystemDrive", szDrive, _countof(szDrive) - 1)) - { - ERR("GetEnvironmentVariableW failed\n"); - return E_FAIL; - } - PathAddBackslashW(szDrive); - - hr = SHEmptyRecycleBinW(lpcmi->hwnd, szDrive, 0); + HRESULT hr = SHEmptyRecycleBinW(lpcmi->hwnd, NULL, 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(); +#if 0 // This is a nasty hack because lpcmi->hwnd might not be a shell browser. + // Not required with working SHChangeNotify. + CComPtr<IShellView> pSV; + LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessage(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0); + if (lpSB && SUCCEEDED(lpSB->QueryActiveShellView(&pSV))) + pSV->Refresh(); +#endif + return hr; } - return S_OK; + else if (CmdId == IDC_PROPERTIES) + { + return SHELL_ShowItemIDListProperties((LPITEMIDLIST)CSIDL_BITBUCKET); + } + return E_INVALIDARG; } HRESULT WINAPI CRecycleBin::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; + TRACE("%p %lu %u %p %p %u\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); + return SHELL_GetCommandStringImpl(idCommand, uFlags, lpszName, uMaxNameLen, g_BBFolderVerbMap); } /************************************************************************* @@ -937,6 +1072,7 @@ HRESULT WINAPI CRecycleBin::ReplacePage(EXPPS uPageID, LPFNSVADDPROPSHEETPAGE pf HRESULT WINAPI CRecycleBin::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID) { TRACE("%p %p %p %p\n", this, pidlFolder, pdtobj, hkeyProgID ); + m_IsBackgroundMenu = false; return S_OK; } @@ -982,7 +1118,7 @@ TRASH_CanTrashFile(LPCWSTR wszPath) 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) + if (RegCreateKeyExW(HKEY_CURRENT_USER, szKey, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) { ERR("RegCreateKeyExW failed\n"); return FALSE; @@ -996,8 +1132,6 @@ TRASH_CanTrashFile(LPCWSTR wszPath) /* per default unlimited size */ dwSize = -1; RegSetValueExW(hKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&dwSize, sizeof(DWORD)); - RegCloseKey(hKey); - return TRUE; } else { @@ -1005,27 +1139,18 @@ TRASH_CanTrashFile(LPCWSTR wszPath) ret = RegQueryValueExW(hKey, L"NukeOnDelete", NULL, &dwType, (LPBYTE)&dwNukeOnDelete, &dwSize); if (ret != ERROR_SUCCESS) { - if (ret == ERROR_FILE_NOT_FOUND) + dwNukeOnDelete = 0; + 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 bCanTrash = !dwNukeOnDelete; + // FIXME: Check if bitbucket is full (CORE-13743) + RegCloseKey(hKey); + return bCanTrash; } BOOL @@ -1178,7 +1303,7 @@ HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags) while (penumFiles->Next(1, &pidl, NULL) == S_OK) { count++; - pRecycleBin->GetDisplayNameOf(pidl, SHGDN_NORMAL, &StrRet); + pRecycleBin->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &StrRet); StrRetToBuf(&StrRet, pidl, szBuffer, _countof(szBuffer)); CoTaskMemFree(pidl); } @@ -1228,6 +1353,7 @@ HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags) if (!ret) return HRESULT_FROM_WIN32(GetLastError()); + CRecycleBin_ChangeNotifyBBItem(SHCNE_UPDATEDIR, NULL); if (!(dwFlags & SHERB_NOSOUND)) { TRASH_PlayEmptyRecycleBinSound(); diff --git a/dll/win32/shell32/folders/CRecycleBin.h b/dll/win32/shell32/folders/CRecycleBin.h index ecf56699447..7d676cd6875 100644 --- a/dll/win32/shell32/folders/CRecycleBin.h +++ b/dll/win32/shell32/folders/CRecycleBin.h @@ -37,12 +37,15 @@ class CRecycleBin : { private: LPITEMIDLIST pidl; - INT iIdEmpty; - BOOL RecycleBinIsEmpty(); + IShellFolder *m_pFSFolders[RECYCLEBINMAXDRIVECOUNT]; + bool m_IsBackgroundMenu; + + IShellFolder* GetFSFolderForItem(LPCITEMIDLIST pidl); public: CRecycleBin(); ~CRecycleBin(); + static inline REFCLSID GetClassID() { return CLSID_RecycleBin; } // IPersistFolder STDMETHOD(GetClassID)(CLSID *pClassID) override; diff --git a/dll/win32/shell32/precomp.h b/dll/win32/shell32/precomp.h index a28c023d244..48c636fe9f1 100644 --- a/dll/win32/shell32/precomp.h +++ b/dll/win32/shell32/precomp.h @@ -262,6 +262,12 @@ SHBindToObjectEx( _In_ REFIID riid, _Out_ void **ppvObj); +EXTERN_C HRESULT +SHELL_GetUIObjectOfAbsoluteItem( + _In_opt_ HWND hWnd, + _In_ PCIDLIST_ABSOLUTE pidl, + _In_ REFIID riid, _Out_ void **ppvObj); + DWORD SHGetAttributes(_In_ IShellFolder *psf, _In_ LPCITEMIDLIST pidl, _In_ DWORD dwAttributes); HRESULT SHELL_GetIDListTarget(_In_ LPCITEMIDLIST pidl, _Out_ PIDLIST_ABSOLUTE *ppidl); diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin.c b/dll/win32/shell32/shellrecyclebin/recyclebin.c index 88221b0da99..5a0153bacf5 100644 --- a/dll/win32/shell32/shellrecyclebin/recyclebin.c +++ b/dll/win32/shell32/shellrecyclebin/recyclebin.c @@ -12,7 +12,7 @@ BOOL WINAPI CloseRecycleBinHandle( IN HDELFILE hDeletedFile) { - IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile; + IRecycleBinFile *rbf = IRecycleBinFileFromHDELFILE(hDeletedFile); HRESULT hr; TRACE("(%p)\n", hDeletedFile); @@ -90,7 +90,7 @@ cleanup: } BOOL WINAPI -DeleteFileHandleToRecycleBin( +DeleteFileInRecycleBin( IN HDELFILE hDeletedFile) { IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile; @@ -231,9 +231,10 @@ EnumerateRecycleBinW( } else if (!SUCCEEDED(hr)) goto cleanup; - if (!pFnCallback(Context, (HANDLE)prbf)) + if (!pFnCallback(Context, (HDELFILE)prbf)) { - hr = HRESULT_FROM_WIN32(GetLastError()); + UINT error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); goto cleanup; } } @@ -252,132 +253,38 @@ cleanup: return FALSE; } -BOOL WINAPI -GetDeletedFileTypeNameW( - IN HDELFILE hDeletedFile, - OUT LPWSTR pTypeName, - IN DWORD BufferSize, - OUT LPDWORD RequiredSize OPTIONAL) +typedef struct _BBENUMFILECONTEXT { - IRecycleBinFile *prbf = (IRecycleBinFile *)hDeletedFile; - SIZE_T FinalSize; - - HRESULT hr = IRecycleBinFile_GetTypeName(prbf, BufferSize, pTypeName, &FinalSize); - - if (SUCCEEDED(hr)) - { - if (RequiredSize) - *RequiredSize = (DWORD)FinalSize; + const RECYCLEBINFILEIDENTITY *pFI; + HDELFILE hDelFile; +} BBENUMFILECONTEXT; - return TRUE; - } - if (HRESULT_FACILITY(hr) == FACILITY_WIN32) - SetLastError(HRESULT_CODE(hr)); - else - SetLastError(ERROR_GEN_FAILURE); - return FALSE; -} - -BOOL WINAPI -GetDeletedFileDetailsA( - IN HDELFILE hDeletedFile, - IN DWORD BufferSize, - IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL, - OUT LPDWORD RequiredSize OPTIONAL) +static BOOL CALLBACK +GetRecycleBinFileHandleCallback(IN PVOID Context, IN HDELFILE hDeletedFile) { - PDELETED_FILE_DETAILS_W FileDetailsW = NULL; - DWORD BufferSizeW = 0; - BOOL ret = FALSE; - - TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize); - - if (BufferSize >= FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) + BBENUMFILECONTEXT *pCtx = (BBENUMFILECONTEXT*)Context; + IRecycleBinFile *pRBF = IRecycleBinFileFromHDELFILE(hDeletedFile); + if (IRecycleBinFile_IsEqualIdentity(pRBF, pCtx->pFI) == S_OK) { - BufferSizeW = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) - + (BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)) * sizeof(WCHAR); + pCtx->hDelFile = hDeletedFile; + return FALSE; } - if (FileDetails && BufferSizeW) - { - FileDetailsW = HeapAlloc(GetProcessHeap(), 0, BufferSizeW); - if (!FileDetailsW) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - } - - ret = GetDeletedFileDetailsW(hDeletedFile, BufferSizeW, FileDetailsW, RequiredSize); - if (!ret) - goto cleanup; - - if (FileDetails) - { - CopyMemory(FileDetails, FileDetailsW, FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName)); - if (0 == WideCharToMultiByte(CP_ACP, 0, FileDetailsW->FileName, -1, FileDetails->FileName, BufferSize - FIELD_OFFSET(DELETED_FILE_DETAILS_A, FileName), NULL, NULL)) - goto cleanup; - } - ret = TRUE; - -cleanup: - HeapFree(GetProcessHeap(), 0, FileDetailsW); - return ret; + CloseRecycleBinHandle(hDeletedFile); + return TRUE; } -BOOL WINAPI -GetDeletedFileDetailsW( - IN HDELFILE hDeletedFile, - IN DWORD BufferSize, - IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL, - OUT LPDWORD RequiredSize OPTIONAL) +EXTERN_C HDELFILE +GetRecycleBinFileHandle( + IN LPCWSTR pszRoot OPTIONAL, + IN const RECYCLEBINFILEIDENTITY *pFI) { - IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile; - HRESULT hr; - SIZE_T NameSize, Needed; - - TRACE("(%p, %lu, %p, %p)\n", hDeletedFile, BufferSize, FileDetails, RequiredSize); - - hr = IRecycleBinFile_GetFileName(rbf, 0, NULL, &NameSize); - if (!SUCCEEDED(hr)) - goto cleanup; - Needed = FIELD_OFFSET(DELETED_FILE_DETAILS_W, FileName) + NameSize; - if (RequiredSize) - *RequiredSize = (DWORD)Needed; - if (Needed > BufferSize) - { - hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); - goto cleanup; - } - hr = IRecycleBinFile_GetFileName(rbf, NameSize, FileDetails->FileName, NULL); - if (!SUCCEEDED(hr)) - goto cleanup; - hr = IRecycleBinFile_GetLastModificationTime(rbf, &FileDetails->LastModification); - if (!SUCCEEDED(hr)) - goto cleanup; - hr = IRecycleBinFile_GetDeletionTime(rbf, &FileDetails->DeletionTime); - if (!SUCCEEDED(hr)) - goto cleanup; - hr = IRecycleBinFile_GetFileSize(rbf, &FileDetails->FileSize); - if (!SUCCEEDED(hr)) - goto cleanup; - hr = IRecycleBinFile_GetPhysicalFileSize(rbf, &FileDetails->PhysicalFileSize); - if (!SUCCEEDED(hr)) - goto cleanup; - hr = IRecycleBinFile_GetAttributes(rbf, &FileDetails->Attributes); - if (!SUCCEEDED(hr)) - goto cleanup; - -cleanup: - if (SUCCEEDED(hr)) - return TRUE; - if (HRESULT_FACILITY(hr) == FACILITY_WIN32) - SetLastError(HRESULT_CODE(hr)); - else - SetLastError(ERROR_GEN_FAILURE); - return FALSE; + BBENUMFILECONTEXT context = { pFI, NULL }; + EnumerateRecycleBinW(pszRoot, GetRecycleBinFileHandleCallback, &context); + return context.hDelFile; } BOOL WINAPI -RestoreFile( +RestoreFileFromRecycleBin( IN HDELFILE hDeletedFile) { IRecycleBinFile *rbf = (IRecycleBinFile *)hDeletedFile; @@ -395,7 +302,7 @@ RestoreFile( return FALSE; } -HRESULT WINAPI +EXTERN_C HRESULT GetDefaultRecycleBin( IN LPCWSTR pszVolume OPTIONAL, OUT IRecycleBin **pprb) @@ -425,3 +332,17 @@ GetDefaultRecycleBin( IUnknown_Release(pUnk); return hr; } + +EXTERN_C HRESULT +GetRecycleBinPathFromDriveNumber(UINT Drive, LPWSTR Path) +{ + const WCHAR volume[] = { LOWORD('A' + Drive), ':', '\\', '\0' }; + IRecycleBin *pRB; + HRESULT hr = GetDefaultRecycleBin(volume, &pRB); + if (SUCCEEDED(hr)) + { + hr = IRecycleBin_GetDirectory(pRB, Path); + IRecycleBin_Release(pRB); + } + return hr; +} diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin.h b/dll/win32/shell32/shellrecyclebin/recyclebin.h index a48f49264cf..b3795b04ebc 100644 --- a/dll/win32/shell32/shellrecyclebin/recyclebin.h +++ b/dll/win32/shell32/shellrecyclebin/recyclebin.h @@ -17,48 +17,64 @@ extern "C" { #include <shellapi.h> #include <objbase.h> -#define ANY_SIZE 1 +#define RECYCLEBINMAXDRIVECOUNT 26 /* Structures used by the API Interface */ -typedef struct _DELETED_FILE_DETAILS_A +typedef UINT RECYCLEBINFILESIZETYPE; + +typedef struct _RECYCLEBINFILEIDENTITY { - FILETIME LastModification; - FILETIME DeletionTime; - ULARGE_INTEGER FileSize; - ULARGE_INTEGER PhysicalFileSize; - DWORD Attributes; - CHAR FileName[ANY_SIZE]; -} DELETED_FILE_DETAILS_A, *PDELETED_FILE_DETAILS_A; -typedef struct _DELETED_FILE_DETAILS_W + FILETIME DeletionTime; + LPCWSTR RecycledFullPath; /* "C:\Recycled\Dc1.ext" etc. */ +} RECYCLEBINFILEIDENTITY, *PRECYCLEBINFILEIDENTITY; + +typedef struct _RECYCLEBINSTRING { - FILETIME LastModification; - FILETIME DeletionTime; - ULARGE_INTEGER FileSize; - ULARGE_INTEGER PhysicalFileSize; - DWORD Attributes; - WCHAR FileName[ANY_SIZE]; -} DELETED_FILE_DETAILS_W, *PDELETED_FILE_DETAILS_W; -#ifdef UNICODE -#define DELETED_FILE_DETAILS DELETED_FILE_DETAILS_W -#define PDELETED_FILE_DETAILS PDELETED_FILE_DETAILS_W -#else -#define DELETED_FILE_DETAILS DELETED_FILE_DETAILS_A -#define PDELETED_FILE_DETAILS PDELETED_FILE_DETAILS_A -#endif + LPCWSTR String; + LPWSTR Alloc; +} RECYCLEBINSTRING, *PRECYCLEBINSTRING; + +typedef struct _DELETED_FILE_INFO +{ + FILETIME LastModification; + FILETIME DeletionTime; + RECYCLEBINFILESIZETYPE FileSize; + DWORD Attributes; + RECYCLEBINSTRING OriginalFullPath; + RECYCLEBINSTRING RecycledFullPath; +} DELETED_FILE_INFO, *PDELETED_FILE_INFO; /* Distinct handle type for deleted file/folder */ DECLARE_HANDLE(HDELFILE); +#define IRecycleBinFileFromHDELFILE(hDF) ( (IRecycleBinFile*)(hDF) ) /* API Interface */ +static inline void +FreeRecycleBinString(PRECYCLEBINSTRING pRBS) +{ + SHFree(pRBS->Alloc); + pRBS->String = pRBS->Alloc = NULL; +} + +static inline void +InitializeRecycleBinStringRef(PRECYCLEBINSTRING pRBS, LPCWSTR String) +{ + pRBS->String = String; + pRBS->Alloc = NULL; +} + +EXTERN_C HRESULT +GetRecycleBinPathFromDriveNumber(UINT Drive, LPWSTR Path); + /* Function called for each deleted file in the recycle bin * Context: value given by the caller of the EnumerateRecycleBin function * hDeletedFile: a handle to the deleted file * Returning FALSE stops the enumeration. * Remarks: the handle must be closed with the CloseRecycleBinHandle function */ -typedef BOOL (WINAPI *PENUMERATE_RECYCLEBIN_CALLBACK)(IN PVOID Context, IN HDELFILE hDeletedFile); +typedef BOOL (CALLBACK *PENUMERATE_RECYCLEBIN_CALLBACK)(IN PVOID Context, IN HDELFILE hDeletedFile); /* Closes a file deleted handle. * hDeletedFile: the handle to close @@ -85,13 +101,13 @@ DeleteFileToRecycleBinW( #define DeleteFileToRecycleBin DeleteFileToRecycleBinA #endif -/* Moves a file to the recycle bin. +/* Deletes a file in the recycle bin. * hDeletedFile: handle of the deleted file to delete * Returns TRUE if operation succeeded, FALSE otherwise. * Remark: The handle is obtained in the PENUMERATE_RECYCLEBIN_CALLBACK callback */ BOOL WINAPI -DeleteFileHandleToRecycleBin( +DeleteFileInRecycleBin( IN HDELFILE hDeletedFile); /* Removes all elements contained in a recycle bin @@ -134,38 +150,10 @@ EnumerateRecycleBinW( #define EnumerateRecycleBin EnumerateRecycleBinA #endif -BOOL WINAPI -GetDeletedFileTypeNameW( - IN HDELFILE hDeletedFile, - OUT LPWSTR pTypeName, - IN DWORD BufferSize, - OUT LPDWORD RequiredSize OPTIONAL); - -/* Gets details about a deleted file - * hDeletedFile: handle of the deleted file to get details about - * BufferSize: size of the 'FileDetails' buffer, in bytes - * FileDetails: if the function succeeded, contains details about the deleted file - * RequiredSize: contains the minimal buffer size required to get file information details - * Returns TRUE if operation succeeded, FALSE otherwise. - * Remark: The handle is obtained in the PENUMERATE_RECYCLEBIN_CALLBACK callback - */ -BOOL WINAPI -GetDeletedFileDetailsA( - IN HDELFILE hDeletedFile, - IN DWORD BufferSize, - IN OUT PDELETED_FILE_DETAILS_A FileDetails OPTIONAL, - OUT LPDWORD RequiredSize OPTIONAL); -BOOL WINAPI -GetDeletedFileDetailsW( - IN HDELFILE hDeletedFile, - IN DWORD BufferSize, - IN OUT PDELETED_FILE_DETAILS_W FileDetails OPTIONAL, - OUT LPDWORD RequiredSize OPTIONAL); -#ifdef UNICODE -#define GetDeletedFileDetails GetDeletedFileDetailsW -#else -#define GetDeletedFileDetails GetDeletedFileDetailsA -#endif +EXTERN_C HDELFILE +GetRecycleBinFileHandle( + IN LPCWSTR pszRoot OPTIONAL, + IN const RECYCLEBINFILEIDENTITY *pFI); /* Restores a deleted file * hDeletedFile: handle of the deleted file to restore @@ -173,7 +161,7 @@ GetDeletedFileDetailsW( * Remarks: if the function succeeds, the handle is not valid anymore. */ BOOL WINAPI -RestoreFile( +RestoreFileFromRecycleBin( IN HDELFILE hDeletedFile); /* COM interface */ @@ -189,13 +177,14 @@ DECLARE_INTERFACE_(IRecycleBinFile, IUnknown) STDMETHOD_(ULONG, Release)(THIS) PURE; /* IRecycleBinFile methods */ + STDMETHOD(IsEqualIdentity)(THIS_ const RECYCLEBINFILEIDENTITY *pFI) PURE; + STDMETHOD(GetInfo)(THIS_ PDELETED_FILE_INFO pInfo) PURE; STDMETHOD(GetLastModificationTime)(THIS_ FILETIME *pLastModificationTime) PURE; STDMETHOD(GetDeletionTime)(THIS_ FILETIME *pDeletionTime) PURE; STDMETHOD(GetFileSize)(THIS_ ULARGE_INTEGER *pFileSize) PURE; STDMETHOD(GetPhysicalFileSize)(THIS_ ULARGE_INTEGER *pPhysicalFileSize) PURE; STDMETHOD(GetAttributes)(THIS_ DWORD *pAttributes) PURE; STDMETHOD(GetFileName)(THIS_ SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) PURE; - STDMETHOD(GetTypeName)(THIS_ SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) PURE; STDMETHOD(Delete)(THIS) PURE; STDMETHOD(Restore)(THIS) PURE; @@ -233,9 +222,10 @@ DECLARE_INTERFACE_(IRecycleBin, IUnknown) STDMETHOD_(ULONG, Release)(THIS) PURE; /* IRecycleBin methods */ - STDMETHOD(DeleteFile)(THIS_ LPCWSTR szFileName); - STDMETHOD(EmptyRecycleBin)(THIS); - STDMETHOD(EnumObjects)(THIS_ IRecycleBinEnumList **ppEnumList); + STDMETHOD(DeleteFile)(THIS_ LPCWSTR szFileName) PURE; + STDMETHOD(EmptyRecycleBin)(THIS) PURE; + STDMETHOD(EnumObjects)(THIS_ IRecycleBinEnumList **ppEnumList) PURE; + STDMETHOD(GetDirectory)(THIS_ LPWSTR szPath) PURE; END_INTERFACE }; @@ -252,6 +242,10 @@ EXTERN_C const IID IID_IRecycleBin; (This)->lpVtbl->AddRef(This) #define IRecycleBinFile_Release(This) \ (This)->lpVtbl->Release(This) +#define IRecycleBinFile_IsEqualIdentity(This, pFI) \ + (This)->lpVtbl->IsEqualIdentity(This, pFI) +#define IRecycleBinFile_GetInfo(This, pInfo) \ + (This)->lpVtbl->GetInfo(This, pInfo) #define IRecycleBinFile_GetLastModificationTime(This, pLastModificationTime) \ (This)->lpVtbl->GetLastModificationTime(This, pLastModificationTime) #define IRecycleBinFile_GetDeletionTime(This, pDeletionTime) \ @@ -264,8 +258,6 @@ EXTERN_C const IID IID_IRecycleBin; (This)->lpVtbl->GetAttributes(This, pAttributes) #define IRecycleBinFile_GetFileName(This, BufferSize, Buffer, RequiredSize) \ (This)->lpVtbl->GetFileName(This, BufferSize, Buffer, RequiredSize) -#define IRecycleBinFile_GetTypeName(This, BufferSize, Buffer, RequiredSize) \ - (This)->lpVtbl->GetTypeName(This, BufferSize, Buffer, RequiredSize) #define IRecycleBinFile_Delete(This) \ (This)->lpVtbl->Delete(This) #define IRecycleBinFile_Restore(This) \ @@ -296,13 +288,20 @@ EXTERN_C const IID IID_IRecycleBin; (This)->lpVtbl->EmptyRecycleBin(This) #define IRecycleBin_EnumObjects(This, ppEnumList) \ (This)->lpVtbl->EnumObjects(This, ppEnumList) +#define IRecycleBin_GetDirectory(This, szPath) \ + (This)->lpVtbl->GetDirectory(This, szPath) #endif -HRESULT WINAPI +EXTERN_C HRESULT GetDefaultRecycleBin( IN LPCWSTR pszVolume OPTIONAL, OUT IRecycleBin **pprb); +/* Recycle Bin shell folder internal API */ +void CRecycleBin_NotifyRecycled(LPCWSTR OrigPath, const WIN32_FIND_DATAW *pFind, + const RECYCLEBINFILEIDENTITY *pFI); + + #ifdef __cplusplus } #endif diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_generic.cpp b/dll/win32/shell32/shellrecyclebin/recyclebin_generic.cpp index a7ad1b00de0..09f561f40b6 100644 --- a/dll/win32/shell32/shellrecyclebin/recyclebin_generic.cpp +++ b/dll/win32/shell32/shellrecyclebin/recyclebin_generic.cpp @@ -23,6 +23,10 @@ public: STDMETHODIMP DeleteFile(LPCWSTR szFileName) override; STDMETHODIMP EmptyRecycleBin() override; STDMETHODIMP EnumObjects(IRecycleBinEnumList **ppEnumList) override; + STDMETHODIMP GetDirectory(LPWSTR szPath) override + { + return E_UNEXPECTED; + } protected: LONG m_ref; @@ -183,3 +187,11 @@ HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown) *ppUnknown = static_cast<IRecycleBin *>(pThis); return S_OK; } + +EXTERN_C +BOOL RecycleBinGeneric_IsEqualFileIdentity(const RECYCLEBINFILEIDENTITY *p1, const RECYCLEBINFILEIDENTITY *p2) +{ + return p1->DeletionTime.dwLowDateTime == p2->DeletionTime.dwLowDateTime && + p1->DeletionTime.dwHighDateTime == p2->DeletionTime.dwHighDateTime && + _wcsicmp(p1->RecycledFullPath, p2->RecycledFullPath) == 0; +} diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_private.h b/dll/win32/shell32/shellrecyclebin/recyclebin_private.h index 42cffd22656..57e440d3899 100644 --- a/dll/win32/shell32/shellrecyclebin/recyclebin_private.h +++ b/dll/win32/shell32/shellrecyclebin/recyclebin_private.h @@ -13,11 +13,20 @@ #include <wine/debug.h> WINE_DEFAULT_DEBUG_CHANNEL(recyclebin); +#ifdef __cplusplus +static inline HRESULT HResultFromWin32(DWORD hr) +{ + // HRESULT_FROM_WIN32 will evaluate its parameter twice, this function will not. + return HRESULT_FROM_WIN32(hr); +} +#endif + /* Defines */ #define RECYCLE_BIN_DIRECTORY_WITH_ACL L"RECYCLER" #define RECYCLE_BIN_DIRECTORY_WITHOUT_ACL L"RECYCLED" #define RECYCLE_BIN_FILE_NAME L"INFO2" +#define RECYCLE_BIN_FILE_NAME_V1 L"INFO" #define ROUND_UP(N, S) ((( (N) + (S) - 1) / (S) ) * (S) ) @@ -43,6 +52,9 @@ typedef struct _INFO2_HEADER EXTERN_C HRESULT RecycleBinGeneric_Constructor(OUT IUnknown **ppUnknown); +EXTERN_C +BOOL RecycleBinGeneric_IsEqualFileIdentity(const RECYCLEBINFILEIDENTITY *p1, const RECYCLEBINFILEIDENTITY *p2); + /* recyclebin_generic_enumerator.c */ EXTERN_C diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_v5.cpp b/dll/win32/shell32/shellrecyclebin/recyclebin_v5.cpp index c7009f94d9d..b040851d011 100644 --- a/dll/win32/shell32/shellrecyclebin/recyclebin_v5.cpp +++ b/dll/win32/shell32/shellrecyclebin/recyclebin_v5.cpp @@ -143,6 +143,13 @@ public: STDMETHODIMP DeleteFile(_In_ LPCWSTR szFileName) override; STDMETHODIMP EmptyRecycleBin() override; STDMETHODIMP EnumObjects(_Out_ IRecycleBinEnumList **ppEnumList) override; + STDMETHODIMP GetDirectory(LPWSTR szPath) override + { + if (!m_Folder[0]) + return E_UNEXPECTED; + lstrcpynW(szPath, m_Folder, MAX_PATH); + return S_OK; + } /* IRecycleBin5 interface */ STDMETHODIMP Delete( @@ -226,6 +233,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) SYSTEMTIME SystemTime; DWORD ClusterSize, BytesPerSector, SectorsPerCluster; HRESULT hr; + WIN32_FIND_DATAW wfd = {}; TRACE("(%p, %s)\n", this, debugstr_w(szFileName)); @@ -240,7 +248,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) { if (szFullName) CoTaskMemFree(szFullName); - return HRESULT_FROM_WIN32(GetLastError()); + return HResultFromWin32(GetLastError()); } else if (len < dwBufferLength) break; @@ -257,7 +265,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) if (dwAttributes == INVALID_FILE_ATTRIBUTES) { CoTaskMemFree(szFullName); - return HRESULT_FROM_WIN32(GetLastError()); + return HResultFromWin32(GetLastError()); } if (dwBufferLength < 2 || szFullName[1] != ':') @@ -270,7 +278,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) hFile = CreateFileW(szFullName, 0, 0, NULL, OPEN_EXISTING, (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS : 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); goto cleanup; } @@ -281,7 +289,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) m_hInfoMapped = CreateFileMappingW(m_hInfo, NULL, PAGE_READWRITE | SEC_COMMIT, 0, 0, NULL); if (!m_hInfoMapped) { - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); goto cleanup; } @@ -289,7 +297,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) pHeader = (PINFO2_HEADER)MapViewOfFile(m_hInfoMapped, FILE_MAP_WRITE, 0, 0, 0); if (!pHeader) { - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); goto cleanup; } @@ -297,7 +305,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart); if (FileSize.u.LowPart < sizeof(INFO2_HEADER)) { - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); goto cleanup; } dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD)) - 1; @@ -307,14 +315,14 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) #if 0 if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&FileSize)) { - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); goto cleanup; } #else FileSize.u.LowPart = GetFileSize(hFile, &FileSize.u.HighPart); if (FileSize.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); goto cleanup; } #endif @@ -350,7 +358,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) /* Get cluster size */ if (!GetDiskFreeSpaceW(m_VolumePath, &SectorsPerCluster, &BytesPerSector, NULL, NULL)) { - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); goto cleanup; } ClusterSize = BytesPerSector * SectorsPerCluster; @@ -359,7 +367,7 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) GetSystemTime(&SystemTime); if (!SystemTimeToFileTime(&SystemTime, &pDeletedFile->DeletionTime)) { - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); goto cleanup; } pDeletedFile->dwPhysicalFileSize = ROUND_UP(FileSize.u.LowPart, ClusterSize); @@ -373,11 +381,21 @@ STDMETHODIMP RecycleBin5::DeleteFile(_In_ LPCWSTR szFileName) goto cleanup; } + wfd.dwFileAttributes = dwAttributes; + wfd.nFileSizeLow = FileSize.u.LowPart; + GetFileTime(hFile, &wfd.ftCreationTime, &wfd.ftLastAccessTime, &wfd.ftLastWriteTime); + /* Move file */ if (MoveFileW(szFullName, DeletedFileName)) hr = S_OK; else - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); + + if (SUCCEEDED(hr)) + { + RECYCLEBINFILEIDENTITY ident = { pDeletedFile->DeletionTime, DeletedFileName }; + CRecycleBin_NotifyRecycled(szFullName, &wfd, &ident); + } cleanup: if (pHeader) diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_v5.h b/dll/win32/shell32/shellrecyclebin/recyclebin_v5.h index f33b3adbe54..2461e0bdbca 100644 --- a/dll/win32/shell32/shellrecyclebin/recyclebin_v5.h +++ b/dll/win32/shell32/shellrecyclebin/recyclebin_v5.h @@ -28,7 +28,7 @@ typedef interface IRecycleBin5 IRecycleBin5; EXTERN_C const IID IID_IRecycleBin5; #define INTERFACE IRecycleBin5 -DECLARE_INTERFACE_(IRecycleBin5, IUnknown) +DECLARE_INTERFACE_(IRecycleBin5, IRecycleBin) { BEGIN_INTERFACE @@ -41,6 +41,7 @@ DECLARE_INTERFACE_(IRecycleBin5, IUnknown) STDMETHOD(DeleteFile)(THIS_ IN LPCWSTR szFileName) PURE; STDMETHOD(EmptyRecycleBin)(THIS); STDMETHOD(EnumObjects)(THIS_ OUT IRecycleBinEnumList **ppEnumList) PURE; + STDMETHOD(GetDirectory)(THIS_ LPWSTR szPath) PURE; /* IRecycleBin5 interface */ STDMETHOD(Delete)( diff --git a/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp b/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp index ff2593fe84d..ae5c6d5e5e6 100644 --- a/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp +++ b/dll/win32/shell32/shellrecyclebin/recyclebin_v5_enumerator.cpp @@ -28,13 +28,18 @@ public: STDMETHODIMP_(ULONG) Release() override; /* IRecycleBinFile methods */ + STDMETHODIMP IsEqualIdentity(const RECYCLEBINFILEIDENTITY *pFI) override + { + RECYCLEBINFILEIDENTITY self = { m_deletedFile.DeletionTime, m_FullName }; + return RecycleBinGeneric_IsEqualFileIdentity(pFI, &self) ? S_OK : S_FALSE; + } + STDMETHODIMP GetInfo(PDELETED_FILE_INFO pInfo) override; STDMETHODIMP GetLastModificationTime(FILETIME *pLastModificationTime) override; STDMETHODIMP GetDeletionTime(FILETIME *pDeletionTime) override; STDMETHODIMP GetFileSize(ULARGE_INTEGER *pFileSize) override; STDMETHODIMP GetPhysicalFileSize(ULARGE_INTEGER *pPhysicalFileSize) override; STDMETHODIMP GetAttributes(DWORD *pAttributes) override; STDMETHODIMP GetFileName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) override; - STDMETHODIMP GetTypeName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) override; STDMETHODIMP Delete() override; STDMETHODIMP Restore() override; @@ -53,14 +58,8 @@ STDMETHODIMP RecycleBin5File::QueryInterface(REFIID riid, void **ppvObject) return E_POINTER; if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IRecycleBinFile)) - *ppvObject = static_cast<IRecycleBinFile *>(this); - else if (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) { - DWORD dwAttributes; - if (GetAttributes(&dwAttributes) == S_OK) - return SHCreateFileExtractIconW(m_FullName, dwAttributes, riid, ppvObject); - else - return S_FALSE; + *ppvObject = static_cast<IRecycleBinFile *>(this); } else { @@ -94,13 +93,29 @@ STDMETHODIMP_(ULONG) RecycleBin5File::Release() return refCount; } +STDMETHODIMP RecycleBin5File::GetInfo(PDELETED_FILE_INFO pInfo) +{ + HRESULT hr = S_OK; + ULARGE_INTEGER uli; + if (FAILED(GetLastModificationTime(&pInfo->LastModification))) + ZeroMemory(&pInfo->LastModification, sizeof(pInfo->LastModification)); + pInfo->DeletionTime = m_deletedFile.DeletionTime; + C_ASSERT(sizeof(pInfo->FileSize) <= sizeof(UINT)); + pInfo->FileSize = FAILED(GetFileSize(&uli)) ? INVALID_FILE_SIZE : uli.LowPart; + if (FAILED(hr = GetAttributes(&pInfo->Attributes))) + pInfo->Attributes = 0; + InitializeRecycleBinStringRef(&pInfo->OriginalFullPath, m_deletedFile.FileNameW); + InitializeRecycleBinStringRef(&pInfo->RecycledFullPath, m_FullName); + return hr; +} + STDMETHODIMP RecycleBin5File::GetLastModificationTime(FILETIME *pLastModificationTime) { TRACE("(%p, %p)\n", this, pLastModificationTime); DWORD dwAttributes = ::GetFileAttributesW(m_FullName); if (dwAttributes == INVALID_FILE_ATTRIBUTES) - return HRESULT_FROM_WIN32(GetLastError()); + return HResultFromWin32(GetLastError()); HANDLE hFile; hFile = CreateFileW(m_FullName, @@ -112,13 +127,13 @@ STDMETHODIMP RecycleBin5File::GetLastModificationTime(FILETIME *pLastModificatio (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) ? FILE_FLAG_BACKUP_SEMANTICS : 0, NULL); if (hFile == INVALID_HANDLE_VALUE) - return HRESULT_FROM_WIN32(GetLastError()); + return HResultFromWin32(GetLastError()); HRESULT hr; if (GetFileTime(hFile, NULL, NULL, pLastModificationTime)) hr = S_OK; else - hr = HRESULT_FROM_WIN32(GetLastError()); + hr = HResultFromWin32(GetLastError()); CloseHandle(hFile); return hr; } @@ -174,7 +189,7 @@ STDMETHODIMP RecycleBin5File::GetAttributes(DWORD *pAttributes) dwAttributes = GetFileAttributesW(m_FullName); if (dwAttributes == INVALID_FILE_ATTRIBUTES) - return HRESULT_FROM_WIN32(GetLastError()); + return HResultFromWin32(GetLastError()); *pAttributes = dwAttributes; return S_OK; @@ -199,36 +214,6 @@ STDMETHODIMP RecycleBin5File::GetFileName(SIZE_T BufferSize, LPWSTR Buffer, SIZE return S_OK; } -STDMETHODIMP RecycleBin5File::GetTypeName(SIZE_T BufferSize, LPWSTR Buffer, SIZE_T *RequiredSize) -{ - HRESULT hr; - DWORD dwRequired; - DWORD dwAttributes; - SHFILEINFOW shFileInfo; - - TRACE("(%p, %u, %p, %p)\n", this, BufferSize, Buffer, RequiredSize); - - hr = GetAttributes(&dwAttributes); - if (!SUCCEEDED(hr)) - return hr; - - hr = SHGetFileInfoW(m_FullName, dwAttributes, &shFileInfo, sizeof(shFileInfo), SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES); - if (!SUCCEEDED(hr)) - return hr; - - dwRequired = (DWORD)(wcslen(shFileInfo.szTypeName) + 1) * sizeof(WCHAR); - if (RequiredSize) - *RequiredSize = dwRequired; - - if (BufferSize == 0 && !Buffer) - return S_OK; - - if (BufferSize < dwRequired) - return E_OUTOFMEMORY; - CopyMemory(Buffer, shFileInfo.szTypeName, dwRequired); - return S_OK; -} - STDMETHODIMP RecycleBin5File::Delete() { TRACE("(%p)\n", this); @@ -390,7 +375,7 @@ STDMETHODIMP RecycleBin5Enum::Next(DWORD celt, IRecycleBinFile **rgelt, DWORD *p ULARGE_INTEGER FileSize; FileSize.u.LowPart = GetFileSize(m_hInfo, &FileSize.u.HighPart); if (FileSize.u.LowPart == 0) - return HRESULT_FROM_WIN32(GetLastError()); + return HResultFromWin32(GetLastError()); DWORD dwEntries = (DWORD)((FileSize.QuadPart - sizeof(INFO2_HEADER)) / sizeof(DELETED_FILE_RECORD)); @@ -455,7 +440,7 @@ RecycleBin5Enum::Init( m_hInfo = hInfo; m_pInfo = (PINFO2_HEADER)MapViewOfFile(hInfoMapped, FILE_MAP_READ, 0, 0, 0); if (!m_pInfo) - return HRESULT_FROM_WIN32(GetLastError()); + return HResultFromWin32(GetLastError()); if (m_pInfo->dwVersion != 5 || m_pInfo->dwRecordSize != sizeof(DELETED_FILE_RECORD)) return E_FAIL; diff --git a/dll/win32/shell32/shlexec.cpp b/dll/win32/shell32/shlexec.cpp index 3a665288535..68befd32925 100644 --- a/dll/win32/shell32/shlexec.cpp +++ b/dll/win32/shell32/shlexec.cpp @@ -1390,14 +1390,7 @@ static HRESULT shellex_get_dataobj( LPSHELLEXECUTEINFOW sei, CComPtr<IDataObject pidl = ILCreateFromPathW(fullpath); allocatedPidl.Attach(pidl); } - - CComPtr<IShellFolder> shf; - LPCITEMIDLIST pidllast = NULL; - HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &shf), &pidllast); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - return shf->GetUIObjectOf(NULL, 1, &pidllast, IID_NULL_PPV_ARG(IDataObject, &dataObj)); + return SHELL_GetUIObjectOfAbsoluteItem(NULL, pidl, IID_PPV_ARG(IDataObject, &dataObj)); } static HRESULT shellex_run_context_menu_default(IShellExtInit *obj, @@ -1582,6 +1575,7 @@ static HRESULT ShellExecute_ContextMenuVerb(LPSHELLEXECUTEINFOW sei) enum { idFirst = 1, idLast = 0x7fff }; HMENU hMenu = CreatePopupMenu(); + // Note: Windows does not pass CMF_EXTENDEDVERBS so "hidden" verbs cannot be executed hr = cm->QueryContextMenu(hMenu, 0, idFirst, idLast, fDefault ? CMF_DEFAULTONLY : 0); if (!FAILED_UNEXPECTEDLY(hr)) { diff --git a/dll/win32/shell32/utils.cpp b/dll/win32/shell32/utils.cpp index ce2f6f40834..a384c6c4925 100644 --- a/dll/win32/shell32/utils.cpp +++ b/dll/win32/shell32/utils.cpp @@ -259,6 +259,32 @@ HRESULT SHBindToObject( return SHBindToObjectEx(psf, pidl, NULL, riid, ppvObj); } +EXTERN_C HRESULT +SHELL_GetUIObjectOfAbsoluteItem( + _In_opt_ HWND hWnd, + _In_ PCIDLIST_ABSOLUTE pidl, + _In_ REFIID riid, _Out_ void **ppvObj) +{ + if (!ppvObj) + return E_INVALIDARG; + *ppvObj = NULL; + IShellFolder *psf; + PCUITEMID_CHILD pidlChild; + HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild); + if (SUCCEEDED(hr)) + { + hr = psf->GetUIObjectOf(hWnd, 1, &pidlChild, riid, NULL, ppvObj); + psf->Release(); + if (SUCCEEDED(hr)) + { + if (*ppvObj) + return hr; + hr = E_FAIL; + } + } + return hr; +} + HRESULT Shell_DisplayNameOf( _In_ IShellFolder *psf, @@ -1429,3 +1455,71 @@ GetDfmCmd(_In_ IContextMenu *pCM, _In_ LPCSTR verba) } return MapVerbToDfmCmd(verba); // Returns DFM_CMD_* or 0 } + +HRESULT +SHELL_MapContextMenuVerbToCmdId(LPCMINVOKECOMMANDINFO pICI, const CMVERBMAP *pMap) +{ + LPCSTR pVerbA = pICI->lpVerb; + CHAR buf[MAX_PATH]; + LPCMINVOKECOMMANDINFOEX pICIX = (LPCMINVOKECOMMANDINFOEX)pICI; + if (IsUnicode(*pICIX) && !IS_INTRESOURCE(pICIX->lpVerbW)) + { + if (SHUnicodeToAnsi(pICIX->lpVerbW, buf, _countof(buf))) + pVerbA = buf; + } + + if (IS_INTRESOURCE(pVerbA)) + return LOWORD(pVerbA); + for (SIZE_T i = 0; pMap[i].Verb; ++i) + { + assert(SUCCEEDED((int)(pMap[i].CmdId))); // The id must be >= 0 and ideally in the 0..0x7fff range + if (!lstrcmpiA(pMap[i].Verb, pVerbA) && pVerbA[0]) + return pMap[i].CmdId; + } + return E_FAIL; +} + +static const CMVERBMAP* +FindVerbMapEntry(UINT_PTR CmdId, const CMVERBMAP *pMap) +{ + for (SIZE_T i = 0; pMap[i].Verb; ++i) + { + if (pMap[i].CmdId == CmdId) + return &pMap[i]; + } + return NULL; +} + +HRESULT +SHELL_GetCommandStringImpl(SIZE_T CmdId, UINT uFlags, LPSTR Buf, UINT cchBuf, const CMVERBMAP *pMap) +{ + const CMVERBMAP* pEntry; + switch (uFlags | GCS_UNICODE) + { + case GCS_VALIDATEW: + case GCS_VERBW: + pEntry = FindVerbMapEntry(CmdId, pMap); + if ((uFlags | GCS_UNICODE) == GCS_VERBW) + { + if (!pEntry) + return E_INVALIDARG; + else if (uFlags & GCS_UNICODE) + return SHAnsiToUnicode(pEntry->Verb, (LPWSTR)Buf, cchBuf) ? S_OK : E_FAIL; + else + return StringCchCopyA(Buf, cchBuf, pEntry->Verb); + } + return pEntry ? S_OK : S_FALSE; // GCS_VALIDATE + } + return E_NOTIMPL; +} + +HRESULT +SHELL_CreateShell32DefaultExtractIcon(int IconIndex, REFIID riid, LPVOID *ppvOut) +{ + CComPtr<IDefaultExtractIconInit> initIcon; + HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + initIcon->SetNormalIcon(swShell32Name, IconIndex); + return initIcon->QueryInterface(riid, ppvOut); +} diff --git a/dll/win32/shell32/utils.h b/dll/win32/shell32/utils.h index 92a96888c5d..5591eb6a463 100644 --- a/dll/win32/shell32/utils.h +++ b/dll/win32/shell32/utils.h @@ -7,7 +7,16 @@ #pragma once -inline BOOL +#ifdef __cplusplus +static inline LPWSTR +SHStrDupW(LPCWSTR Src) +{ + LPWSTR Dup; + return SUCCEEDED(SHStrDupW(Src, &Dup)) ? Dup : NULL; +} +#endif + +static inline BOOL RegValueExists(HKEY hKey, LPCWSTR Name) { return RegQueryValueExW(hKey, Name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS; @@ -31,12 +40,22 @@ RegSetOrDelete(HKEY hKey, LPCWSTR Name, DWORD Type, LPCVOID Data, DWORD Size) return RegDeleteValueW(hKey, Name); } -inline DWORD +static inline DWORD RegSetString(HKEY hKey, LPCWSTR Name, LPCWSTR Str, DWORD Type = REG_SZ) { return RegSetValueExW(hKey, Name, 0, Type, LPBYTE(Str), (lstrlenW(Str) + 1) * sizeof(WCHAR)); } +typedef struct { + LPCSTR Verb; + WORD CmdId; +} CMVERBMAP; + +HRESULT +SHELL_MapContextMenuVerbToCmdId(LPCMINVOKECOMMANDINFO pICI, const CMVERBMAP *pMap); +HRESULT +SHELL_GetCommandStringImpl(SIZE_T CmdId, UINT uFlags, LPSTR Buf, UINT cchBuf, const CMVERBMAP *pMap); + // SHExtractIconsW is a forward, use this function instead inside shell32 inline HICON SHELL32_SHExtractIcon(LPCWSTR File, int Index, int cx, int cy) @@ -45,3 +64,20 @@ SHELL32_SHExtractIcon(LPCWSTR File, int Index, int cx, int cy) int r = PrivateExtractIconsW(File, Index, cx, cy, &hIco, NULL, 1, 0); return r > 0 ? hIco : NULL; } + +HRESULT +SHELL_CreateShell32DefaultExtractIcon(int IconIndex, REFIID riid, LPVOID *ppvOut); + +static inline HRESULT +SHELL_CreateFallbackExtractIconForFolder(REFIID riid, LPVOID *ppvOut) +{ + const int id = IDI_SHELL_FOLDER; + return SHELL_CreateShell32DefaultExtractIcon(id > 1 ? -id : 0, riid, ppvOut); +} + +static inline HRESULT +SHELL_CreateFallbackExtractIconForNoAssocFile(REFIID riid, LPVOID *ppvOut) +{ + const int id = IDI_SHELL_DOCUMENT; + return SHELL_CreateShell32DefaultExtractIcon(id > 1 ? -id : 0, riid, ppvOut); +} diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c index de484982b15..2bca7cdd436 100644 --- a/dll/win32/shell32/wine/pidl.c +++ b/dll/win32/shell32/wine/pidl.c @@ -2112,32 +2112,22 @@ BOOL _ILIsSpecialFolder (LPCITEMIDLIST pidl) 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)); + const BYTE type = _ILGetType(pidl); + const BYTE fldrtype = (PT_DRIVE & PT_FOLDERTYPEMASK); + return (type & PT_FOLDERTYPEMASK) == fldrtype && type != PT_COMPUTER_REGITEM; } BOOL _ILIsFolder(LPCITEMIDLIST pidl) { - LPPIDLDATA lpPData = _ILGetDataPointer(pidl); - - TRACE("(%p)\n",pidl); - - return (pidl && lpPData && (PT_FOLDER == lpPData->type || PT_FOLDER1 == lpPData->type)); + /* A folder or a simple PT_FS with a child */ + const BYTE type = _ILGetFSType(pidl); + return (type & PT_FS_FOLDER_FLAG) != 0 || (type == PT_FS && ILGetNext(pidl)); } BOOL _ILIsValue(LPCITEMIDLIST pidl) { - LPPIDLDATA lpPData = _ILGetDataPointer(pidl); - - TRACE("(%p)\n",pidl); - - return (pidl && lpPData && PT_VALUE == lpPData->type); + const BYTE type = _ILGetFSType(pidl); + return type && !(type & PT_FS_FOLDER_FLAG); } BOOL _ILIsCPanelStruct(LPCITEMIDLIST pidl) @@ -2281,6 +2271,9 @@ static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) if (!pdata) return NULL; + if (_ILGetFSType(pidl) & PT_FS_UNICODE_FLAG) + return (LPWSTR)pdata->u.file.szNames; + switch (pdata->type) { case PT_GUID: @@ -2311,9 +2304,6 @@ static LPWSTR _ILGetTextPointerW(LPCITEMIDLIST pidl) /*return (LPSTR)&(pdata->u.network.szNames);*/ return NULL; - case PT_VALUEW: - return (LPWSTR)pdata->u.file.szNames; - #ifdef __REACTOS__ /* r54423 */ case PT_CPLAPPLET: return pdata->u.cpanel.szName; @@ -2439,7 +2429,7 @@ FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) { FileStructW *pFileStructW; WORD cbOffset; - if (!(_ILIsValue(pidl) || _ILIsFolder(pidl))) + if (!_ILIsFolderOrFile(pidl)) return NULL; cbOffset = *(const WORD *)((const BYTE *)pidl + pidl->mkid.cb - sizeof(WORD)); @@ -2479,48 +2469,12 @@ FileStructW* _ILGetFileStructW(LPCITEMIDLIST pidl) { */ BOOL _ILGetFileDateTime(LPCITEMIDLIST pidl, FILETIME *pFt) { - LPPIDLDATA pdata = _ILGetDataPointer(pidl); - - if (!pdata) - return FALSE; - - switch (pdata->type) + if (_ILGetFSType(pidl) > PT_FS) /* Only non-simple FS items have a date */ { - 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, LPWSTR pOut, UINT uOutSize) -{ - FILETIME ft,lft; - SYSTEMTIME time; - BOOL ret; - - if (_ILGetFileDateTime( pidl, &ft )) - { - FileTimeToLocalFileTime(&ft, &lft); - FileTimeToSystemTime (&lft, &time); - - ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, pOut, uOutSize); - if (ret) - { - /* Append space + time without seconds */ - pOut[ret - 1] = L' '; - GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &pOut[ret], uOutSize - ret); - } - } - else - { - pOut[0] = UNICODE_NULL; - ret = FALSE; + LPPIDLDATA pdata = _ILGetDataPointer(pidl); + return DosDateTimeToFileTime(pdata->u.file.uFileDate, pdata->u.file.uFileTime, pFt); } - return ret; + return FALSE; } /************************************************************************* @@ -2543,15 +2497,13 @@ BOOL _ILGetFileDate(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DWORD _ILGetFileSize(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) { LPPIDLDATA pdata = _ILGetDataPointer(pidl); - DWORD dwSize; - if (!pdata) return 0; - switch (pdata->type) + if (_ILGetFSType(pidl) & PT_FS_FILE_FLAG) { - case PT_VALUE: - dwSize = pdata->u.file.dwFileSize; + /* FIXME: Handle INVALID_FILE_SIZE (get size from disk) */ + DWORD dwSize = pdata->u.file.dwFileSize; if (pOut) StrFormatKBSizeW(dwSize, pOut, uOutSize); return dwSize; diff --git a/dll/win32/shell32/wine/pidl.h b/dll/win32/shell32/wine/pidl.h index 28fff42feb4..bd8e34ea4bd 100644 --- a/dll/win32/shell32/wine/pidl.h +++ b/dll/win32/shell32/wine/pidl.h @@ -157,16 +157,6 @@ typedef struct tagPIDLPrinterStruct WCHAR szName[1]; } PIDLPrinterStruct; -typedef struct tagPIDLRecycleStruct -{ - FILETIME LastModification; - FILETIME DeletionTime; - ULARGE_INTEGER FileSize; - ULARGE_INTEGER PhysicalFileSize; - DWORD Attributes; - WCHAR szName[1]; -} PIDLRecycleStruct; - #endif /* !__REACTOS__ */ typedef struct tagGUIDStruct @@ -233,7 +223,6 @@ typedef struct tagPIDLDATA #ifdef __REACTOS__ struct tagPIDLFontStruct cfont; struct tagPIDLPrinterStruct cprinter; - struct tagPIDLRecycleStruct crecycle; #endif }u; } PIDLDATA, *LPPIDLDATA; @@ -243,7 +232,6 @@ typedef struct tagPIDLDATA * getting special values from simple pidls */ DWORD _ILSimpleGetTextW (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN; -BOOL _ILGetFileDate (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN; DWORD _ILGetFileSize (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN; BOOL _ILGetExtension (LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN; DWORD _ILGetFileAttributes(LPCITEMIDLIST pidl, LPWSTR pOut, UINT uOutSize) DECLSPEC_HIDDEN; @@ -261,6 +249,7 @@ BOOL _ILIsMyDocuments (LPCITEMIDLIST pidl); BOOL _ILIsBitBucket (LPCITEMIDLIST pidl); BOOL _ILIsNetHood (LPCITEMIDLIST pidl); BOOL _ILIsControlPanel (LPCITEMIDLIST pidl); +#define _ILIsFolderOrFile _ILGetFSType #endif BOOL _ILIsDrive (LPCITEMIDLIST pidl) DECLSPEC_HIDDEN; BOOL _ILIsFolder (LPCITEMIDLIST pidl) DECLSPEC_HIDDEN; diff --git a/dll/win32/shell32/wine/shell32_main.h b/dll/win32/shell32/wine/shell32_main.h index d40e1a164b3..fa5bafd8880 100644 --- a/dll/win32/shell32/wine/shell32_main.h +++ b/dll/win32/shell32/wine/shell32_main.h @@ -139,7 +139,7 @@ void FreeChangeNotifications(void) DECLSPEC_HIDDEN; BOOL SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pwszDir, BOOL bShowUI); BOOL SHELL_ConfirmYesNoW(HWND hWnd, int nKindOfDialog, LPCWSTR szDir); -void WINAPI _InsertMenuItemW (HMENU hmenu, UINT indexMenu, BOOL fByPosition, +BOOL WINAPI _InsertMenuItemW (HMENU hmenu, UINT indexMenu, BOOL fByPosition, UINT wID, UINT fType, LPCWSTR dwTypeData, UINT fState); static __inline BOOL SHELL_OsIsUnicode(void)
5 days, 18 hours
1
0
0
0
[reactos] 01/01: [NTOS:CM] Add some more configuration options.
by Hermès Bélusca-Maïto
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a18424267bf35061809d1…
commit a18424267bf35061809d1198f0616e280504fd91 Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org> AuthorDate: Sun Aug 11 16:39:28 2024 +0200 Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org> CommitDate: Thu Dec 19 11:52:13 2024 +0100 [NTOS:CM] Add some more configuration options. Add support for configuring the CM lazy-flush and delay-close variables: `CmpLazyFlushIntervalInSeconds`, `CmpLazyFlushHiveCount`, and `CmpDelayedCloseSize`, using REG_DWORD values named respectively: `RegistryLazyFlushInterval`, `RegistryLazyFlushHiveCount`, and `DelayCloseSize`, in the registry key `HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Configuration Manager` . Extra observations: - While delay-close support exists in Windows 2003, configuring the delay-close size is possible only in Windows Vista and later. - The possibility of configuring the lazy-flush hive count has been removed in Windows 8+. See the comparison tables at:
https://redplait.blogspot.com/2011/07/cmcontrolvector.html
https://redplait.blogspot.com/2012/06/cmcontrolvector-for-w8.html
https://redplait.blogspot.com/2016/03/cmcontrolvector-from-windows-10-build…
In addition: Remove `CmpDelayedCloseIndex` from cm.h as it is not used anymore in our code. --- ntoskrnl/config/cmdata.c | 21 +++++++++++++++++++++ ntoskrnl/config/cmlazy.c | 6 +++--- ntoskrnl/include/internal/cm.h | 4 +++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ntoskrnl/config/cmdata.c b/ntoskrnl/config/cmdata.c index e428377a6fc..47f166f56c2 100644 --- a/ntoskrnl/config/cmdata.c +++ b/ntoskrnl/config/cmdata.c @@ -675,6 +675,27 @@ DATA_SEG("INITDATA") CM_SYSTEM_CONTROL_VECTOR CmControlVector[] = NULL, NULL }, + { + L"Session Manager\\Configuration Manager", + L"RegistryLazyFlushInterval", + &CmpLazyFlushIntervalInSeconds, + NULL, + NULL + }, + { + L"Session Manager\\Configuration Manager", + L"RegistryLazyFlushHiveCount", + &CmpLazyFlushHiveCount, + NULL, + NULL + }, + { + L"Session Manager\\Configuration Manager", + L"DelayCloseSize", + &CmpDelayedCloseSize, + NULL, + NULL + }, { L"Session Manager\\Configuration Manager", L"VolatileBoot", diff --git a/ntoskrnl/config/cmlazy.c b/ntoskrnl/config/cmlazy.c index ebac8a20532..201f719a3a4 100644 --- a/ntoskrnl/config/cmlazy.c +++ b/ntoskrnl/config/cmlazy.c @@ -22,7 +22,7 @@ BOOLEAN CmpLazyFlushPending; BOOLEAN CmpForceForceFlush; BOOLEAN CmpHoldLazyFlush = TRUE; ULONG CmpLazyFlushIntervalInSeconds = 5; -static ULONG CmpLazyFlushHiveCount = 7; +ULONG CmpLazyFlushHiveCount = 7; ULONG CmpLazyFlushCount = 1; LONG CmpFlushStarveWriters; @@ -60,7 +60,7 @@ CmpDoFlushNextHive(_In_ BOOLEAN ForceFlush, if (!(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH) && (CmHive->FlushCount != CmpLazyFlushCount)) { - /* Great sucess! */ + /* Great success! */ Result = TRUE; /* One less to flush */ @@ -80,7 +80,7 @@ CmpDoFlushNextHive(_In_ BOOLEAN ForceFlush, DPRINT("Flushing: %wZ\n", &CmHive->FileFullPath); DPRINT("Handle: %p\n", CmHive->FileHandles[HFILE_TYPE_PRIMARY]); Status = HvSyncHive(&CmHive->Hive); - if(!NT_SUCCESS(Status)) + if (!NT_SUCCESS(Status)) { /* Let them know we failed */ DPRINT1("Failed to flush %wZ on handle %p (status 0x%08lx)\n", diff --git a/ntoskrnl/include/internal/cm.h b/ntoskrnl/include/internal/cm.h index 02d8b9e177c..7aed5fef6e4 100644 --- a/ntoskrnl/include/internal/cm.h +++ b/ntoskrnl/include/internal/cm.h @@ -1460,7 +1460,7 @@ extern HANDLE CmpRegistryRootHandle; extern BOOLEAN ExpInTextModeSetup; extern BOOLEAN InitIsWinPEMode; extern ULONG CmpHashTableSize; -extern ULONG CmpDelayedCloseSize, CmpDelayedCloseIndex; +extern ULONG CmpDelayedCloseSize; extern BOOLEAN CmpNoWrite; extern BOOLEAN CmpForceForceFlush; extern BOOLEAN CmpWasSetupBoot; @@ -1468,6 +1468,8 @@ extern BOOLEAN CmpProfileLoaded; extern PCMHIVE CmiVolatileHive; extern LIST_ENTRY CmiKeyObjectListHead; extern BOOLEAN CmpHoldLazyFlush; +extern ULONG CmpLazyFlushIntervalInSeconds; +extern ULONG CmpLazyFlushHiveCount; extern BOOLEAN HvShutdownComplete; //
5 days, 21 hours
1
0
0
0
[reactos] 01/01: [SETUPAPI][PSDK] Implement SetupDiGetCustomDevicePropertyW
by Eric Kohl
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d44ed03b6c3783369b0f2…
commit d44ed03b6c3783369b0f25cd368f598757705165 Author: Eric Kohl <eric.kohl(a)reactos.org> AuthorDate: Wed Dec 18 23:18:36 2024 +0100 Commit: Eric Kohl <eric.kohl(a)reactos.org> CommitDate: Wed Dec 18 23:18:36 2024 +0100 [SETUPAPI][PSDK] Implement SetupDiGetCustomDevicePropertyW --- dll/win32/setupapi/devinst.c | 80 ++++++++++++++++++++++++++++++++++++++++ dll/win32/setupapi/setupapi.spec | 2 +- sdk/include/psdk/setupapi.h | 1 + 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/dll/win32/setupapi/devinst.c b/dll/win32/setupapi/devinst.c index 47e2bf8beaa..53e99ba5d29 100644 --- a/dll/win32/setupapi/devinst.c +++ b/dll/win32/setupapi/devinst.c @@ -6150,3 +6150,83 @@ SetupDiRestartDevices( return TRUE; } + +/*********************************************************************** + * SetupDiGetCustomDevicePropertyW (SETUPAPI.@) + */ +BOOL +WINAPI +SetupDiGetCustomDevicePropertyW( + IN HDEVINFO DeviceInfoSet, + IN PSP_DEVINFO_DATA DeviceInfoData, + IN PCWSTR CustomPropertyName, + IN DWORD Flags, + OUT PDWORD PropertyRegDataType OPTIONAL, + OUT PBYTE PropertyBuffer, + IN DWORD PropertyBufferSize, + OUT PDWORD RequiredSize OPTIONAL) +{ + struct DeviceInfoSet *set = (struct DeviceInfoSet *)DeviceInfoSet; + struct DeviceInfo *deviceInfo; + DWORD ConfigFlags = 0, PropertySize; + CONFIGRET cr; + + TRACE("%s(%p %p %s 0x%lx %p %p %lu %p)\n", __FUNCTION__, DeviceInfoSet, DeviceInfoData, + debugstr_w(CustomPropertyName), Flags, PropertyRegDataType, PropertyBuffer, PropertyBufferSize, RequiredSize); + + if (!DeviceInfoSet || DeviceInfoSet == INVALID_HANDLE_VALUE) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + if (set->magic != SETUP_DEVICE_INFO_SET_MAGIC) + { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + if (!DeviceInfoData || DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA) + || !DeviceInfoData->Reserved) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if (Flags & ~DICUSTOMDEVPROP_MERGE_MULTISZ) + { + SetLastError(ERROR_INVALID_FLAGS); + return FALSE; + } + + deviceInfo = (struct DeviceInfo *)DeviceInfoData->Reserved; + if (deviceInfo->set != set) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (Flags & DICUSTOMDEVPROP_MERGE_MULTISZ) + { + ConfigFlags |= CM_CUSTOMDEVPROP_MERGE_MULTISZ; + } + + PropertySize = PropertyBufferSize; + cr = CM_Get_DevInst_Custom_Property_ExW(deviceInfo->dnDevInst, + CustomPropertyName, + PropertyRegDataType, + PropertyBuffer, + &PropertySize, + ConfigFlags, + set->hMachine); + if ((cr == CR_SUCCESS) || (cr == CR_BUFFER_SMALL)) + { + if (RequiredSize) + *RequiredSize = PropertySize; + } + + if (cr != CR_SUCCESS) + { + SetLastError(GetErrorCodeFromCrCode(cr)); + return FALSE; + } + + return TRUE; +} diff --git a/dll/win32/setupapi/setupapi.spec b/dll/win32/setupapi/setupapi.spec index 1c86bb655ac..3a15bffab48 100644 --- a/dll/win32/setupapi/setupapi.spec +++ b/dll/win32/setupapi/setupapi.spec @@ -316,7 +316,7 @@ @ stdcall SetupDiGetClassRegistryPropertyA(ptr long ptr ptr long ptr str ptr) @ stdcall SetupDiGetClassRegistryPropertyW(ptr long ptr ptr long ptr wstr ptr) @ stub SetupDiGetCustomDevicePropertyA -@ stub SetupDiGetCustomDevicePropertyW +@ stdcall SetupDiGetCustomDevicePropertyW(ptr ptr wstr long ptr ptr long ptr) @ stdcall SetupDiGetDeviceInfoListClass(ptr ptr) @ stdcall SetupDiGetDeviceInfoListDetailA(ptr ptr) @ stdcall SetupDiGetDeviceInfoListDetailW(ptr ptr) diff --git a/sdk/include/psdk/setupapi.h b/sdk/include/psdk/setupapi.h index efe15a7b0bf..b209c8f00bb 100644 --- a/sdk/include/psdk/setupapi.h +++ b/sdk/include/psdk/setupapi.h @@ -117,6 +117,7 @@ extern "C" { #define DICS_START 4 #define DICS_FLAG_CONFIGGENERAL 4 #define DICS_STOP 5 +#define DICUSTOMDEVPROP_MERGE_MULTISZ 0x00000001 #define DIF_SELECTDEVICE 1 #define DIF_INSTALLDEVICE 2 #define DIF_ASSIGNRESOURCES 3
6 days, 9 hours
1
0
0
0
[reactos] 04/04: [NTOS:PS] Add query support for QUOTA_LIMITS_EX
by Thamatip Chitpong
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=1e06829961cb597f7e192…
commit 1e06829961cb597f7e1927a5e35b66febe674a96 Author: Thamatip Chitpong <thamatip.chitpong(a)reactos.org> AuthorDate: Wed Dec 11 01:50:30 2024 +0700 Commit: Thamatip Chitpong <thamatip.chitpong(a)reactos.org> CommitDate: Wed Dec 18 09:53:21 2024 +0700 [NTOS:PS] Add query support for QUOTA_LIMITS_EX --- ntoskrnl/include/internal/ps_i.h | 4 ++- ntoskrnl/ps/query.c | 77 ++++++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/ntoskrnl/include/internal/ps_i.h b/ntoskrnl/include/internal/ps_i.h index 21f8368fa88..04d564bd36a 100644 --- a/ntoskrnl/include/internal/ps_i.h +++ b/ntoskrnl/include/internal/ps_i.h @@ -27,7 +27,9 @@ static const INFORMATION_CLASS_INFO PsProcessInfoClass[] = ( QUOTA_LIMITS, ULONG, - ICIF_QUERY | ICIF_SET | ICIF_SET_SIZE_VARIABLE + + /* NOTE: ICIF_SIZE_VARIABLE is for QUOTA_LIMITS_EX support */ + ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE ), /* ProcessIoCounters */ diff --git a/ntoskrnl/ps/query.c b/ntoskrnl/ps/query.c index 4613d7404b0..01aa0361af8 100644 --- a/ntoskrnl/ps/query.c +++ b/ntoskrnl/ps/query.c @@ -153,15 +153,19 @@ NtQueryInformationProcess( /* Process quota limits */ case ProcessQuotaLimits: { - PQUOTA_LIMITS QuotaLimits = (PQUOTA_LIMITS)ProcessInformation; + QUOTA_LIMITS_EX QuotaLimits; + BOOLEAN Extended; - if (ProcessInformationLength != sizeof(QUOTA_LIMITS)) + if (ProcessInformationLength != sizeof(QUOTA_LIMITS) && + ProcessInformationLength != sizeof(QUOTA_LIMITS_EX)) { Status = STATUS_INFO_LENGTH_MISMATCH; break; } - Length = sizeof(QUOTA_LIMITS); + /* Set return length */ + Length = ProcessInformationLength; + Extended = (Length == sizeof(QUOTA_LIMITS_EX)); /* Reference the process */ Status = ObReferenceObjectByHandle(ProcessHandle, @@ -175,36 +179,49 @@ NtQueryInformationProcess( /* Indicate success */ Status = STATUS_SUCCESS; - _SEH2_TRY + RtlZeroMemory(&QuotaLimits, sizeof(QuotaLimits)); + + /* Get max/min working set sizes */ + QuotaLimits.MaximumWorkingSetSize = + Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT; + QuotaLimits.MinimumWorkingSetSize = + Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT; + + /* Get default time limits */ + QuotaLimits.TimeLimit.QuadPart = -1LL; + + /* Is quota block a default one? */ + if (Process->QuotaBlock == &PspDefaultQuotaBlock) { - /* Set max/min working set sizes */ - QuotaLimits->MaximumWorkingSetSize = - Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT; - QuotaLimits->MinimumWorkingSetSize = - Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT; + /* Get default pools and pagefile limits */ + QuotaLimits.PagedPoolLimit = (SIZE_T)-1; + QuotaLimits.NonPagedPoolLimit = (SIZE_T)-1; + QuotaLimits.PagefileLimit = (SIZE_T)-1; + } + else + { + /* Get limits from non-default quota block */ + QuotaLimits.PagedPoolLimit = + Process->QuotaBlock->QuotaEntry[PsPagedPool].Limit; + QuotaLimits.NonPagedPoolLimit = + Process->QuotaBlock->QuotaEntry[PsNonPagedPool].Limit; + QuotaLimits.PagefileLimit = + Process->QuotaBlock->QuotaEntry[PsPageFile].Limit; + } - /* Set default time limits */ - QuotaLimits->TimeLimit.LowPart = MAXULONG; - QuotaLimits->TimeLimit.HighPart = MAXULONG; + /* Get additional information, if needed */ + if (Extended) + { + /* FIXME: Get the correct information */ + //QuotaLimits.WorkingSetLimit = (SIZE_T)-1; // Not used on Win2k3, it is set to 0 + QuotaLimits.Flags = QUOTA_LIMITS_HARDWS_MIN_DISABLE | QUOTA_LIMITS_HARDWS_MAX_DISABLE; + QuotaLimits.CpuRateLimit.RateData = 0; + } - /* Is quota block a default one? */ - if (Process->QuotaBlock == &PspDefaultQuotaBlock) - { - /* Set default pools and pagefile limits */ - QuotaLimits->PagedPoolLimit = (SIZE_T)-1; - QuotaLimits->NonPagedPoolLimit = (SIZE_T)-1; - QuotaLimits->PagefileLimit = (SIZE_T)-1; - } - else - { - /* Get limits from non-default quota block */ - QuotaLimits->PagedPoolLimit = - Process->QuotaBlock->QuotaEntry[PsPagedPool].Limit; - QuotaLimits->NonPagedPoolLimit = - Process->QuotaBlock->QuotaEntry[PsNonPagedPool].Limit; - QuotaLimits->PagefileLimit = - Process->QuotaBlock->QuotaEntry[PsPageFile].Limit; - } + /* Protect writes with SEH */ + _SEH2_TRY + { + RtlCopyMemory(ProcessInformation, &QuotaLimits, Length); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1 week
1
0
0
0
← Newer
1
2
3
4
5
6
7
8
9
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
Results per page:
10
25
50
100
200