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