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 @@
@@ -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 @@
@@ -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