Browse Source
- Also properly fixed the logon delay on 22000. - Removed the logon delay option.pull/3235/head
11 changed files with 512 additions and 147 deletions
@ -1,29 +0,0 @@ |
|||||||
#include "StartupSound.h" |
|
||||||
|
|
||||||
DWORD PlayStartupSound(PlayStartupSoundParams* unused) |
|
||||||
{ |
|
||||||
Sleep(2000); |
|
||||||
printf("Started \"Play startup sound\" thread.\n"); |
|
||||||
|
|
||||||
HRESULT hr = CoInitialize(NULL); |
|
||||||
|
|
||||||
// this checks Software\\Microsoft\\Windows\\CurrentVersion\\Authentication\\LogonUI\\LogonSoundPlayed
|
|
||||||
// and then plays the startup sound
|
|
||||||
|
|
||||||
AuthUILogonSound* ppv; |
|
||||||
hr = CoCreateInstance( |
|
||||||
&__uuidof_AuthUILogonSound, |
|
||||||
NULL, |
|
||||||
CLSCTX_INPROC_SERVER, |
|
||||||
&__uuidof_IAuthUILogonSound, |
|
||||||
&ppv |
|
||||||
); |
|
||||||
if (SUCCEEDED(hr)) |
|
||||||
{ |
|
||||||
ppv->lpVtbl->PlayIfNecessary(ppv, 1); |
|
||||||
ppv->lpVtbl->Release(ppv); |
|
||||||
} |
|
||||||
|
|
||||||
printf("Ended \"Play startup sound\" thread.\n"); |
|
||||||
return 0; |
|
||||||
} |
|
||||||
@ -0,0 +1,390 @@ |
|||||||
|
#include "StartupSound.h" |
||||||
|
|
||||||
|
#include <Shlwapi.h> |
||||||
|
#pragma comment(lib, "Shlwapi.lib") |
||||||
|
#include <stdio.h> |
||||||
|
#include <strsafe.h> |
||||||
|
#pragma comment(lib, "Winmm.lib") |
||||||
|
#include <Wtsapi32.h> |
||||||
|
#pragma comment(lib, "Wtsapi32.lib") |
||||||
|
#include <tchar.h> |
||||||
|
#include <wrl/client.h> |
||||||
|
#include <wil/result_macros.h> |
||||||
|
|
||||||
|
#include "def.h" |
||||||
|
|
||||||
|
BOOL AreLogonLogoffShutdownSoundsEnabled() |
||||||
|
{ |
||||||
|
#if 0 |
||||||
|
DWORD dwValue = 0; |
||||||
|
DWORD dwSize = sizeof(dwValue); |
||||||
|
RegGetValueW(HKEY_CURRENT_USER, _T(REGPATH), L"LogonLogoffShutdownSounds", RRF_RT_DWORD, nullptr, &dwValue, &dwSize); |
||||||
|
return dwValue != 0; |
||||||
|
#else |
||||||
|
return FALSE; |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
DWORD GetLastErrorError() |
||||||
|
{ |
||||||
|
DWORD result = GetLastError(); |
||||||
|
return result == ERROR_SUCCESS ? 1 : result; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT HRESULTFromLastErrorError() |
||||||
|
{ |
||||||
|
DWORD error = GetLastError(); |
||||||
|
if (error != ERROR_SUCCESS && (int)error <= 0) |
||||||
|
return (HRESULT)GetLastErrorError(); |
||||||
|
else |
||||||
|
return (HRESULT)((GetLastErrorError() & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000); |
||||||
|
} |
||||||
|
|
||||||
|
DWORD PlaySoundFileThreadProc(LPVOID pvData) |
||||||
|
{ |
||||||
|
PlaySoundW((LPCWSTR)pvData, nullptr, SND_NODEFAULT | SND_MEMORY | SND_SYSTEM); |
||||||
|
LocalFree(pvData); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT PlaySoundFile(HANDLE* phThread, const WCHAR* pszPath) |
||||||
|
{ |
||||||
|
HRESULT hr; |
||||||
|
|
||||||
|
void* pvData = nullptr; |
||||||
|
HANDLE hFile = CreateFileW( |
||||||
|
pszPath, |
||||||
|
GENERIC_READ, |
||||||
|
FILE_SHARE_READ | FILE_SHARE_DELETE, |
||||||
|
nullptr, |
||||||
|
OPEN_EXISTING, |
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, |
||||||
|
nullptr |
||||||
|
); |
||||||
|
if (hFile != INVALID_HANDLE_VALUE) |
||||||
|
{ |
||||||
|
DWORD dwSize = GetFileSize(hFile, nullptr); |
||||||
|
hr = E_OUTOFMEMORY; |
||||||
|
if (dwSize != (DWORD)-1 && dwSize) |
||||||
|
{ |
||||||
|
if (dwSize < 0x400000) |
||||||
|
{ |
||||||
|
pvData = LocalAlloc(0, dwSize); |
||||||
|
if (pvData) |
||||||
|
{ |
||||||
|
DWORD dwRead; |
||||||
|
if (ReadFile(hFile, pvData, dwSize, &dwRead, nullptr)) |
||||||
|
hr = dwSize == dwRead ? S_OK : HRESULT_FROM_WIN32(ERROR_IO_PENDING); |
||||||
|
else |
||||||
|
hr = HRESULTFromLastErrorError(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
hr = HRESULTFromLastErrorError(); |
||||||
|
} |
||||||
|
CloseHandle(hFile); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
hr = HRESULTFromLastErrorError(); |
||||||
|
} |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
HANDLE hThread = CreateThread(nullptr, 0, PlaySoundFileThreadProc, pvData, 0, nullptr); |
||||||
|
if (hThread) |
||||||
|
{ |
||||||
|
if (phThread) |
||||||
|
*phThread = hThread; |
||||||
|
else |
||||||
|
CloseHandle(hThread); |
||||||
|
return hr; |
||||||
|
} |
||||||
|
hr = HRESULTFromLastErrorError(); |
||||||
|
} |
||||||
|
if (pvData) |
||||||
|
LocalFree(pvData); |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
typedef enum LOGONOFFSOUNDTYPE |
||||||
|
{ |
||||||
|
LOGONOFFSOUNDTYPE_LOGON, |
||||||
|
LOGONOFFSOUNDTYPE_LOGOFF, |
||||||
|
LOGONOFFSOUNDTYPE_EXIT, |
||||||
|
} LOGONOFFSOUNDTYPE; |
||||||
|
|
||||||
|
HRESULT PlayLogonLogoffSound(HANDLE* phThread, LOGONOFFSOUNDTYPE type) |
||||||
|
{ |
||||||
|
const WCHAR* szEventName; |
||||||
|
switch (type) |
||||||
|
{ |
||||||
|
case LOGONOFFSOUNDTYPE_LOGON: |
||||||
|
szEventName = L"WindowsLogon"; |
||||||
|
break; |
||||||
|
case LOGONOFFSOUNDTYPE_LOGOFF: |
||||||
|
szEventName = L"WindowsLogoff"; |
||||||
|
break; |
||||||
|
default: |
||||||
|
szEventName = L"SystemExit"; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
WCHAR szSubKey[MAX_PATH]; |
||||||
|
HRESULT hr = StringCchPrintfW(szSubKey, ARRAYSIZE(szSubKey), L"AppEvents\\Schemes\\Apps\\.Default\\%ws\\.Current", szEventName); |
||||||
|
if (FAILED(hr)) |
||||||
|
return hr; |
||||||
|
|
||||||
|
WCHAR szPath[MAX_PATH]; |
||||||
|
DWORD cbData = sizeof(szPath); |
||||||
|
LSTATUS lStat = RegGetValueW(HKEY_CURRENT_USER, szSubKey, nullptr, REG_EXPAND_SZ, nullptr, szPath, &cbData); |
||||||
|
if (lStat != ERROR_SUCCESS) |
||||||
|
return HRESULT_FROM_WIN32(lStat); |
||||||
|
|
||||||
|
return PlaySoundFile(phThread, szPath); |
||||||
|
} |
||||||
|
|
||||||
|
// https://stackoverflow.com/a/59810748
|
||||||
|
bool IsSessionLocked() |
||||||
|
{ |
||||||
|
WTSINFOEXW* pInfo = NULL; |
||||||
|
WTS_INFO_CLASS wtsic = WTSSessionInfoEx; |
||||||
|
LPTSTR ppBuffer = NULL; |
||||||
|
DWORD dwBytesReturned = 0; |
||||||
|
LONG sessionFlags = WTS_SESSIONSTATE_UNKNOWN; |
||||||
|
|
||||||
|
DWORD dwSessionID = WTSGetActiveConsoleSessionId(); |
||||||
|
|
||||||
|
if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, dwSessionID, wtsic, &ppBuffer, &dwBytesReturned)) |
||||||
|
{ |
||||||
|
if (dwBytesReturned > 0) |
||||||
|
{ |
||||||
|
pInfo = (WTSINFOEXW*)ppBuffer; |
||||||
|
if (pInfo->Level == 1) |
||||||
|
{ |
||||||
|
sessionFlags = pInfo->Data.WTSInfoExLevel1.SessionFlags; |
||||||
|
} |
||||||
|
} |
||||||
|
WTSFreeMemory(ppBuffer); |
||||||
|
ppBuffer = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
return (sessionFlags == WTS_SESSIONSTATE_LOCK); |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT (*CLogonSound_PlayIfNecessaryFunc)(void* _this, LOGON_SOUND_CLIENT client); |
||||||
|
HRESULT CLogonSound_PlayIfNecessaryHook(void* _this, LOGON_SOUND_CLIENT client) |
||||||
|
{ |
||||||
|
HRESULT hr = CLogonSound_PlayIfNecessaryFunc(_this, client); |
||||||
|
if (hr != S_OK && client == LSC_EXPLORER) |
||||||
|
{ |
||||||
|
if (!IsSessionLocked()) |
||||||
|
PlayLogonLogoffSound(nullptr, LOGONOFFSOUNDTYPE_LOGON); |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT HookLogonSound() |
||||||
|
{ |
||||||
|
RETURN_IF_FAILED(CoInitialize(nullptr)); |
||||||
|
|
||||||
|
Microsoft::WRL::ComPtr<IAuthUILogonSound> logonSound; |
||||||
|
RETURN_IF_FAILED(CoCreateInstance(__uuidof_AuthUILogonSound, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&logonSound))); |
||||||
|
|
||||||
|
void** vtable = *(void***)logonSound.Get(); |
||||||
|
DWORD flOldProtect; |
||||||
|
RETURN_HR_IF(E_FAIL, !VirtualProtect(&vtable[3], sizeof(void*), PAGE_EXECUTE_READWRITE, &flOldProtect)); |
||||||
|
|
||||||
|
CLogonSound_PlayIfNecessaryFunc = (decltype(CLogonSound_PlayIfNecessaryFunc))vtable[3]; |
||||||
|
vtable[3] = (void*)CLogonSound_PlayIfNecessaryHook; |
||||||
|
VirtualProtect(&vtable[3], sizeof(void*), flOldProtect, &flOldProtect); |
||||||
|
|
||||||
|
return S_OK; |
||||||
|
} |
||||||
|
|
||||||
|
LRESULT SHDefWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
||||||
|
{ |
||||||
|
if (IsWindowUnicode(hwnd)) |
||||||
|
{ |
||||||
|
return DefWindowProcW(hwnd, uMsg, wParam, lParam); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
return DefWindowProcA(hwnd, uMsg, wParam, lParam); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
HWND g_hwndSound; |
||||||
|
|
||||||
|
class CSoundWnd |
||||||
|
{ |
||||||
|
public: |
||||||
|
CSoundWnd(); |
||||||
|
|
||||||
|
BOOL Init(); |
||||||
|
DWORD Release(); |
||||||
|
|
||||||
|
protected: |
||||||
|
static LRESULT CALLBACK s_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); |
||||||
|
LRESULT v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); |
||||||
|
|
||||||
|
private: |
||||||
|
static DWORD s_CreateWindow(void* pvParam); |
||||||
|
static DWORD s_ThreadProc(void* pvParam); |
||||||
|
|
||||||
|
LONG m_refCount; |
||||||
|
HWND m_hwnd; |
||||||
|
HANDLE m_thread; |
||||||
|
}; |
||||||
|
|
||||||
|
CSoundWnd::CSoundWnd() |
||||||
|
: m_refCount(1) |
||||||
|
, m_hwnd(nullptr) |
||||||
|
, m_thread(nullptr) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
BOOL CSoundWnd::Init() |
||||||
|
{ |
||||||
|
SHCreateThread(s_ThreadProc, this, CTF_THREAD_REF | CTF_COINIT_STA | CTF_REF_COUNTED | CTF_NOADDREFLIB, s_CreateWindow); |
||||||
|
g_hwndSound = m_hwnd; |
||||||
|
return m_hwnd != nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
DWORD CSoundWnd::Release() |
||||||
|
{ |
||||||
|
LONG refCount = InterlockedDecrement(&m_refCount); |
||||||
|
if (refCount == 0 && this) |
||||||
|
operator delete(this); |
||||||
|
return refCount; |
||||||
|
} |
||||||
|
|
||||||
|
LRESULT CSoundWnd::s_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
||||||
|
{ |
||||||
|
CSoundWnd* pThis = (CSoundWnd*)GetWindowLongPtrW(hwnd, 0); |
||||||
|
if (pThis) |
||||||
|
return pThis->v_WndProc(hwnd, uMsg, wParam, lParam); |
||||||
|
else |
||||||
|
return SHDefWindowProc(hwnd, uMsg, wParam, lParam); |
||||||
|
} |
||||||
|
|
||||||
|
LRESULT CSoundWnd::v_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
||||||
|
{ |
||||||
|
switch (uMsg) |
||||||
|
{ |
||||||
|
case WM_QUERYENDSESSION: |
||||||
|
{ |
||||||
|
if ((lParam & ENDSESSION_CRITICAL) == 0) |
||||||
|
{ |
||||||
|
WCHAR sz[256]; |
||||||
|
LoadStringW(GetModuleHandleW(nullptr), 731, sz, ARRAYSIZE(sz)); // Playing logoff sound...
|
||||||
|
ShutdownBlockReasonCreate(m_hwnd, sz); |
||||||
|
PlayLogonLogoffSound(&m_thread, (lParam & ENDSESSION_LOGOFF) != 0 ? LOGONOFFSOUNDTYPE_LOGOFF : LOGONOFFSOUNDTYPE_EXIT); |
||||||
|
if (m_thread) |
||||||
|
{ |
||||||
|
WaitForSingleObject(m_thread, INFINITE); // @MOD
|
||||||
|
CloseHandle(m_thread); // @MOD
|
||||||
|
} |
||||||
|
} |
||||||
|
return 1; |
||||||
|
} |
||||||
|
case WM_ENDSESSION: |
||||||
|
{ |
||||||
|
/*if (wParam && (lParam & ENDSESSION_CRITICAL) == 0 && m_thread) // @MOD This doesn't work
|
||||||
|
{ |
||||||
|
WaitForSingleObject(m_thread, INFINITE); |
||||||
|
CloseHandle(m_thread); |
||||||
|
}*/ |
||||||
|
DestroyWindow(m_hwnd); |
||||||
|
break; |
||||||
|
} |
||||||
|
case WM_NCDESTROY: |
||||||
|
{ |
||||||
|
SetWindowLongW(hwnd, 0, 0); |
||||||
|
g_hwndSound = nullptr; |
||||||
|
m_hwnd = nullptr; |
||||||
|
PostQuitMessage(0); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
return SHDefWindowProc(hwnd, uMsg, wParam, lParam); |
||||||
|
} |
||||||
|
|
||||||
|
extern "C" HWND (__stdcall *explorerframe_SHCreateWorkerWindowFunc)( |
||||||
|
WNDPROC wndProc, |
||||||
|
HWND hWndParent, |
||||||
|
DWORD dwExStyle, |
||||||
|
DWORD dwStyle, |
||||||
|
HMENU hMenu, |
||||||
|
LONG_PTR wnd_extra |
||||||
|
); |
||||||
|
|
||||||
|
DWORD CSoundWnd::s_CreateWindow(void* pvParam) |
||||||
|
{ |
||||||
|
CSoundWnd* pThis = (CSoundWnd*)pvParam; |
||||||
|
InterlockedIncrement(&pThis->m_refCount); |
||||||
|
pThis->m_hwnd = explorerframe_SHCreateWorkerWindowFunc(s_WndProc, nullptr, 0, 0, nullptr, (LONG_PTR)pThis); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
DWORD CSoundWnd::s_ThreadProc(void* pvParam) |
||||||
|
{ |
||||||
|
CSoundWnd* pThis = (CSoundWnd*)pvParam; |
||||||
|
if (pThis->m_hwnd) |
||||||
|
{ |
||||||
|
MSG Msg; |
||||||
|
while (GetMessageW(&Msg, nullptr, 0, 0)) |
||||||
|
{ |
||||||
|
TranslateMessage(&Msg); |
||||||
|
DispatchMessageW(&Msg); |
||||||
|
} |
||||||
|
} |
||||||
|
pThis->Release(); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
BOOL InitSoundWindow() |
||||||
|
{ |
||||||
|
BOOL bSuccess = FALSE; |
||||||
|
CSoundWnd* soundWnd = new CSoundWnd(); |
||||||
|
if (soundWnd) |
||||||
|
{ |
||||||
|
bSuccess = soundWnd->Init(); |
||||||
|
soundWnd->Release(); |
||||||
|
} |
||||||
|
return bSuccess; |
||||||
|
} |
||||||
|
|
||||||
|
void TermSoundWindow() |
||||||
|
{ |
||||||
|
if (g_hwndSound) |
||||||
|
{ |
||||||
|
PostMessageW(g_hwndSound, WM_CLOSE, 0, 0); |
||||||
|
g_hwndSound = nullptr; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
HRESULT SHPlaySound(LPCWSTR pszSound, DWORD dwFlags) |
||||||
|
{ |
||||||
|
HRESULT hr; |
||||||
|
BOOL bDefault = (dwFlags & 1) != 0; |
||||||
|
BOOL bSecondAttempt = FALSE; |
||||||
|
while (true) |
||||||
|
{ |
||||||
|
WCHAR szKey[MAX_PATH]; |
||||||
|
hr = StringCchPrintfW(szKey, MAX_PATH, L"AppEvents\\Schemes\\Apps\\%s\\%s\\.current", bDefault ? L".Default" : L"Explorer", pszSound); |
||||||
|
if (SUCCEEDED(hr)) |
||||||
|
{ |
||||||
|
WCHAR pvData[MAX_PATH]; |
||||||
|
DWORD cbData = sizeof(pvData); |
||||||
|
if (SHGetValueW(HKEY_CURRENT_USER, szKey, nullptr, nullptr, pvData, &cbData) == ERROR_SUCCESS && cbData && pvData[0]) |
||||||
|
hr = PlaySoundW(pszSound, nullptr, (!bDefault ? 0x400000 : 0) | (SND_ASYNC | SND_NODEFAULT | SND_NOSTOP | SND_NOWAIT | SND_ALIAS | SND_SENTRY | SND_SYSTEM)) ? S_OK : S_FALSE; |
||||||
|
} |
||||||
|
if (hr == S_OK || (dwFlags & 2) == 0 || bSecondAttempt) |
||||||
|
break; |
||||||
|
bDefault = !bDefault; |
||||||
|
bSecondAttempt = TRUE; |
||||||
|
} |
||||||
|
return hr; |
||||||
|
} |
||||||
Loading…
Reference in new issue