diff --git a/Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj b/Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj index cc384e6..1c94a8b 100644 --- a/Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj +++ b/Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj @@ -184,6 +184,7 @@ + @@ -240,6 +241,7 @@ + @@ -278,7 +280,7 @@ - + @@ -286,6 +288,6 @@ - + \ No newline at end of file diff --git a/Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj.filters b/Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj.filters index a2a0939..ded2b8a 100644 --- a/Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj.filters +++ b/Source/KNSoft.MakeLifeEasier/KNSoft.MakeLifeEasier.vcxproj.filters @@ -177,6 +177,9 @@ PE + + Shell + @@ -326,6 +329,9 @@ PE + + Shell + diff --git a/Source/KNSoft.MakeLifeEasier/MakeLifeEasier.h b/Source/KNSoft.MakeLifeEasier/MakeLifeEasier.h index 476ec67..413323e 100644 --- a/Source/KNSoft.MakeLifeEasier/MakeLifeEasier.h +++ b/Source/KNSoft.MakeLifeEasier/MakeLifeEasier.h @@ -20,7 +20,7 @@ #define MLE_API DECLSPEC_IMPORT #endif -typedef _Return_type_success_(return == 0) ULONG W32ERROR; +typedef _Return_type_success_(return == ERROR_SUCCESS) ULONG W32ERROR; /* * Core Header @@ -60,6 +60,7 @@ typedef _Return_type_success_(return == 0) ULONG W32ERROR; #include "Process/Environment.h" #include "Process/Loader.h" #include "Process/Token.h" +#include "Shell/Desktop.h" #include "Shell/Shell.h" #include "String/Convert.h" #include "String/Encoding.h" diff --git a/Source/KNSoft.MakeLifeEasier/Shell/Desktop.c b/Source/KNSoft.MakeLifeEasier/Shell/Desktop.c new file mode 100644 index 0000000..aca7ae7 --- /dev/null +++ b/Source/KNSoft.MakeLifeEasier/Shell/Desktop.c @@ -0,0 +1,158 @@ +#include "../MakeLifeEasier.inl" + +/* Reversed from Explorer.exe!CTray::_DoExitExplorer */ +W32ERROR +NTAPI +Shell_QuitShellWindow( + _In_ HWND ShellWindow) +{ + W32ERROR Ret; + HWND ShellTray; + + Ret = PostMessageW(ShellWindow, WM_QUIT, 0, 0) ? ERROR_SUCCESS : NtGetLastError(); + ShellTray = Shell_GetTrayWindow(); + if (ShellTray != NULL && PostMessageW(ShellTray, WM_QUIT, 0, 0)) + { + return ERROR_SUCCESS; + } + if (!Ret) + { + Ret = EndTask(ShellWindow, FALSE, TRUE) ? ERROR_SUCCESS : NtGetLastError(); + } + return Ret; +} + +W32ERROR +NTAPI +Shell_ExitExplorerEx( + _In_opt_ ULONG Timeout, + _Out_opt_ PULONG OldProcessId) +{ + W32ERROR Ret; + HWND ShellWindow; + ULONG ProcessId; + HANDLE ProcessHandle; + NTSTATUS Status; + + /* Get shell window and process id */ + ShellWindow = GetShellWindow(); + if (ShellWindow == NULL) + { + ProcessId = 0; + goto _Done; + } + Ret = UI_GetWindowThreadProcessId(ShellWindow, NULL, &ProcessId); + if (Ret != ERROR_SUCCESS) + { + return Ret; + } + + /* Open process handle if need wait it */ + if (Timeout == 0) + { + ProcessHandle = NULL; + } else if (!NT_SUCCESS(PS_OpenProcess(&ProcessHandle, SYNCHRONIZE, ProcessId))) + { + goto _Force_Kill; + } + + /* Quit shell */ + Ret = Shell_QuitShellWindow(ShellWindow); + if (Ret == ERROR_SUCCESS) + { + if (ProcessHandle == NULL) + { + goto _Done; + } + } else + { + if (ProcessHandle != NULL) + { + NtClose(ProcessHandle); + } + goto _Force_Kill; + } + + /* Wait shell exit */ + Status = PS_WaitForObject(ProcessHandle, Timeout); + NtClose(ProcessHandle); + if (Status == STATUS_WAIT_0) + { + goto _Done; + } + +_Force_Kill: + Status = PS_OpenProcess(&ProcessHandle, PROCESS_TERMINATE, ProcessId); + if (!NT_SUCCESS(Status)) + { + return RtlNtStatusToDosError(Status); + } + Status = NtTerminateProcess(ProcessHandle, STATUS_SUCCESS); + NtClose(ProcessHandle); + if (!NT_SUCCESS(Status)) + { + return RtlNtStatusToDosError(Status); + } + +_Done: + if (OldProcessId != NULL) + { + *OldProcessId = ProcessId; + } + return ERROR_SUCCESS; +} + +#define SHELL_WAIT_EXPLORER_START_UNIT 300 + +W32ERROR +NTAPI +Shell_StartExplorerEx( + _In_opt_ ULONG Timeout, + _In_opt_ ULONG OldProcessId) +{ + W32ERROR Ret; + HWND ShellWindow; + WCHAR Path[MAX_PATH]; + ULONG u; + + /* Check if shell window already exists */ + ShellWindow = GetShellWindow(); + if (ShellWindow != NULL) + { + Ret = UI_GetWindowThreadProcessId(ShellWindow, NULL, &u); + if (Ret != ERROR_SUCCESS) + { + return Ret; + } else + { + return u != OldProcessId ? ERROR_SUCCESS : ERROR_ALREADY_EXISTS; + } + } + + /* Run explorer.exe */ + u = Str_CopyW(Path, SharedUserData->NtSystemRoot); + if (u + 1 >= ARRAYSIZE(Path)) + { + return ERROR_INSUFFICIENT_BUFFER; + } + Path[u++] = L'\\'; + Str_CopyExW(Path + u, ARRAYSIZE(Path) - u, L"explorer.exe"); + Ret = Shell_Exec(Path, NULL, L"open", SW_SHOWNORMAL, NULL); + if (Timeout == 0 || Ret != ERROR_SUCCESS) + { + return Ret; + } + + /* Wait shell windows start */ + u = 0; + do + { + PS_DelayExec(SHELL_WAIT_EXPLORER_START_UNIT); + if (GetShellWindow() != NULL && GetTaskmanWindow() != NULL) + { + return ERROR_SUCCESS; + } + u += SHELL_WAIT_EXPLORER_START_UNIT; + } while (u < Timeout); + return ERROR_TIMEOUT; +} diff --git a/Source/KNSoft.MakeLifeEasier/Shell/Desktop.h b/Source/KNSoft.MakeLifeEasier/Shell/Desktop.h new file mode 100644 index 0000000..79873d0 --- /dev/null +++ b/Source/KNSoft.MakeLifeEasier/Shell/Desktop.h @@ -0,0 +1,58 @@ +#pragma once + +#include "../MakeLifeEasier.h" + +/* + * Reversed from the latest Win11 Explorer.exe. + * + * v_hwndDesktop = GetShellWindow(); + * CTrayStatic c_ctrayStatic; + * c_ctrayStatic + 8 = Shell_TrayWnd = GetAncestor(GetTaskmanWindow(), GA_ROOT); + */ + +EXTERN_C_START + +FORCEINLINE +W32ERROR +Shell_GetExplorerProcessId( + _Out_ PULONG ProcessId) +{ + HWND ShellWindow; + + ShellWindow = GetShellWindow(); + if (ShellWindow == NULL) + { + return ERROR_NOT_FOUND; + } + return GetWindowThreadProcessId(ShellWindow, ProcessId) != 0 ? ERROR_SUCCESS : NtGetLastError(); +} + +FORCEINLINE +HWND +Shell_GetTrayWindow(VOID) +{ + HWND Window = GetTaskmanWindow(); + return Window != NULL ? GetAncestor(Window, GA_ROOT) : NULL; +} + +MLE_API +W32ERROR +NTAPI +Shell_QuitShellWindow( + _In_ HWND ShellWindow); + +MLE_API +W32ERROR +NTAPI +Shell_ExitExplorerEx( + _In_opt_ ULONG Timeout, + _Out_opt_ PULONG OldProcessId); + +MLE_API +W32ERROR +NTAPI +Shell_StartExplorerEx( + _In_opt_ ULONG Timeout, + _In_opt_ ULONG OldProcessId); + +EXTERN_C_END diff --git a/Source/KNSoft.MakeLifeEasier/String/Convert.cpp b/Source/KNSoft.MakeLifeEasier/String/Convert.cpp index a238b09..9c9dbdf 100644 --- a/Source/KNSoft.MakeLifeEasier/String/Convert.cpp +++ b/Source/KNSoft.MakeLifeEasier/String/Convert.cpp @@ -243,8 +243,8 @@ Str_ToIntExA( template static -_Success_(return != FALSE) -LOGICAL +_Success_(return > 0) +ULONG NTAPI Str_FromIntEx_Impl( _In_ INT64 Value, @@ -277,12 +277,12 @@ Str_FromIntEx_Impl( uPowerFlag = 4; } else { - return FALSE; + return 0; } if (DestCchSize <= 1) { - return FALSE; + return 0; } // Find max divisor @@ -329,11 +329,11 @@ Str_FromIntEx_Impl( }; *psz = (TChar)'\0'; - return lRet; + return PtrOffset(StrValue, psz) / sizeof(TChar); } -_Success_(return != FALSE) -LOGICAL +_Success_(return > 0) +ULONG NTAPI Str_FromIntExW( _In_ INT64 Value, @@ -345,8 +345,8 @@ Str_FromIntExW( return Str_FromIntEx_Impl(Value, Unsigned, Base, StrValue, DestCchSize); } -_Success_(return != FALSE) -LOGICAL +_Success_(return > 0) +ULONG NTAPI Str_FromIntExA( _In_ INT64 Value, diff --git a/Source/KNSoft.MakeLifeEasier/String/Convert.h b/Source/KNSoft.MakeLifeEasier/String/Convert.h index ca75afe..695e750 100644 --- a/Source/KNSoft.MakeLifeEasier/String/Convert.h +++ b/Source/KNSoft.MakeLifeEasier/String/Convert.h @@ -55,8 +55,8 @@ Str_ToIntExA( #pragma region String From Integer MLE_API -_Success_(return != FALSE) -LOGICAL +_Success_(return > 0) +ULONG NTAPI Str_FromIntExW( _In_ INT64 Value, @@ -66,8 +66,8 @@ Str_FromIntExW( _In_ ULONG DestCchSize); MLE_API -_Success_(return != FALSE) -LOGICAL +_Success_(return > 0) +ULONG NTAPI Str_FromIntExA( _In_ INT64 Value, diff --git a/Source/KNSoft.MakeLifeEasier/String/Core.h b/Source/KNSoft.MakeLifeEasier/String/Core.h index 4e38f72..18904e8 100644 --- a/Source/KNSoft.MakeLifeEasier/String/Core.h +++ b/Source/KNSoft.MakeLifeEasier/String/Core.h @@ -131,41 +131,28 @@ Str_EqualW( #pragma endregion -FORCEINLINE -LOGICAL -Str_TestCchRet( - _In_ unsigned long CchRet, - _In_ size_t const BufferCount) -{ - return CchRet > 0 && CchRet < BufferCount; -} - #pragma region String PrintF -_Success_( - return > 0 && return < BufferCount -) +_Success_(return > 0) FORCEINLINE ULONG Str_VPrintfExW( - _Out_writes_opt_(BufferCount) _Always_(_Post_z_) wchar_t* const Buffer, - _In_ size_t const BufferCount, - _In_z_ _Printf_format_string_ const wchar_t* Format, - va_list ArgList) + _Out_writes_(BufferCount) _Always_(_Post_z_) PWSTR Buffer, + _In_ ULONG BufferCount, + _In_z_ _Printf_format_string_ PCWSTR Format, + _In_opt_ va_list ArgList) { return StrSafe_CchVPrintfW(Buffer, BufferCount, Format, ArgList); } -_Success_( - return > 0 && return < BufferCount -) +_Success_(return > 0) FORCEINLINE ULONG Str_VPrintfExA( - _Out_writes_opt_(BufferCount) _Always_(_Post_z_) char* const Buffer, - _In_ size_t const BufferCount, - _In_z_ _Printf_format_string_ const char* Format, - va_list ArgList) + _Out_writes_(BufferCount) _Always_(_Post_z_) PSTR Buffer, + _In_ ULONG const BufferCount, + _In_z_ _Printf_format_string_ PCSTR Format, + _In_opt_ va_list ArgList) { return StrSafe_CchVPrintfA(Buffer, BufferCount, Format, ArgList); } @@ -191,28 +178,24 @@ Str_VPrintfExA( #pragma region String Copy -_Success_( - return > 0 && return < BufferCount -) +_Success_(return > 0) FORCEINLINE -SIZE_T +ULONG Str_CopyExW( - _Out_writes_opt_(BufferCount) _When_(BufferCount > 0, _Notnull_) _Always_(_Post_z_) wchar_t* const Buffer, - _In_ size_t const BufferCount, - _In_z_ const wchar_t* Source) + _Out_writes_(BufferCount) _Always_(_Post_z_) PWSTR Buffer, + _In_range_(>, 0) ULONG BufferCount, + _In_z_ PCWSTR Source) { return StrSafe_CchCopyW(Buffer, BufferCount, Source); } -_Success_( - return > 0 && return < BufferCount -) +_Success_(return > 0) FORCEINLINE -SIZE_T +ULONG Str_CopyExA( - _Out_writes_opt_(BufferCount) _When_(BufferCount > 0, _Notnull_) _Always_(_Post_z_) char* const Buffer, - _In_ size_t const BufferCount, - _In_z_ const char* Source) + _Out_writes_(BufferCount) _Always_(_Post_z_) PSTR Buffer, + _In_range_(>, 0) ULONG BufferCount, + _In_z_ PCSTR Source) { return StrSafe_CchCopyA(Buffer, BufferCount, Source); } diff --git a/Source/KNSoft.MakeLifeEasier/UI/DialogBox/RectEditor.c b/Source/KNSoft.MakeLifeEasier/UI/DialogBox/RectEditor.c index f33ed52..75f32eb 100644 --- a/Source/KNSoft.MakeLifeEasier/UI/DialogBox/RectEditor.c +++ b/Source/KNSoft.MakeLifeEasier/UI/DialogBox/RectEditor.c @@ -22,7 +22,7 @@ Dlg_RectEditor_SetValue( { WCHAR Num[MAX_INT32_IN_DEC_CCH]; - UI_SetWindowTextW(Edit, Str_DecFromIntW(Value, Num) ? Num : NULL); + UI_SetWindowTextW(Edit, Str_DecFromIntW(Value, Num) > 0 ? Num : NULL); } static diff --git a/Source/KNSoft.MakeLifeEasier/UI/DialogBox/ValueEditor.c b/Source/KNSoft.MakeLifeEasier/UI/DialogBox/ValueEditor.c index 81fe0ed..e817ac6 100644 --- a/Source/KNSoft.MakeLifeEasier/UI/DialogBox/ValueEditor.c +++ b/Source/KNSoft.MakeLifeEasier/UI/DialogBox/ValueEditor.c @@ -88,7 +88,7 @@ UI_ValueEditor_FormatValue( return FALSE; } - return i > 0 && i < BufferCount; + return i > 0; } static diff --git a/Source/KNSoft.MakeLifeEasier/UI/Window.c b/Source/KNSoft.MakeLifeEasier/UI/Window.c index 3da1352..302105c 100644 --- a/Source/KNSoft.MakeLifeEasier/UI/Window.c +++ b/Source/KNSoft.MakeLifeEasier/UI/Window.c @@ -185,7 +185,7 @@ UI_FlashWindow_Thread( Status = NTSTATUS_FROM_WIN32(NtGetLastError()); } ReleaseDC(NULL, ScreenDC); - UI_Redraw(Window); + RedrawWindow(NULL, &Rect, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW); return Status; } diff --git a/Source/KNSoft.MakeLifeEasier/UI/Window.h b/Source/KNSoft.MakeLifeEasier/UI/Window.h index 87b6a20..f9bed8d 100644 --- a/Source/KNSoft.MakeLifeEasier/UI/Window.h +++ b/Source/KNSoft.MakeLifeEasier/UI/Window.h @@ -298,4 +298,31 @@ NTAPI UI_FlashWindow( _In_ HWND Window); +/* Window Process */ + +FORCEINLINE +W32ERROR +UI_GetWindowThreadProcessId( + _In_ HWND Window, + _Out_opt_ PULONG ThreadId, + _Out_opt_ PULONG ProcessId) +{ + DWORD TID, PID; + + TID = GetWindowThreadProcessId(Window, &PID); + if (TID == 0) + { + return NtGetLastError(); + } + if (ThreadId != NULL) + { + *ThreadId = TID; + } + if (ProcessId != NULL) + { + *ProcessId = PID; + } + return ERROR_SUCCESS; +} + EXTERN_C_END diff --git a/Source/KNSoft.MakeLifeEasier/packages.config b/Source/KNSoft.MakeLifeEasier/packages.config index 4c47f46..a763f52 100644 --- a/Source/KNSoft.MakeLifeEasier/packages.config +++ b/Source/KNSoft.MakeLifeEasier/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/Source/Test/Test.vcxproj b/Source/Test/Test.vcxproj index 9f629e0..c5c2919 100644 --- a/Source/Test/Test.vcxproj +++ b/Source/Test/Test.vcxproj @@ -189,12 +189,12 @@ - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + \ No newline at end of file diff --git a/Source/Test/packages.config b/Source/Test/packages.config index 2d94f9b..65cc8dc 100644 --- a/Source/Test/packages.config +++ b/Source/Test/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file