From: unknown Date: Thu, 10 Jul 2014 13:20:49 +0000 (+0200) Subject: Initial commit to github (WinMute Version 1.4) X-Git-Tag: 1.4 X-Git-Url: https://repos.lx-s.de/gitweb/?a=commitdiff_plain;h=afeb0f86ee6f1d0eb7989db633f9fdf9c982bf35;p=winmute.git Initial commit to github (WinMute Version 1.4) --- diff --git a/Bin/changelog.txt b/Bin/changelog.txt new file mode 100644 index 0000000..9a27f75 --- /dev/null +++ b/Bin/changelog.txt @@ -0,0 +1,40 @@ + +Version 1.4 (2014-07-10) + + * WinMute can now also mute if the screensaver starts + Due to windows restrictions, unmuting the audio can take up to one second + after the screensaver resumes. + + * Added a toggle switch to configure if WinMute should unmute at all after + a workstation lock or a screensaver run + + +Version 1.3 (2012-02-23) + + * Right-click menu is now correctly dismissed if the user clicks somewhere + outside of the menu. + + * Embedded Visual C++ 2010 DLLs. This increases file size by about 100kb, but + enables the usage of this tool in workplaces that do not have deployed the + Visual C++ 2010 Runtime Environment yet. + + * Vista/7/8: Correctly mute the new device, if the default audio endpoint + changes. + + * XP: Greatly improved hardware detection code. WinMute now mutes all devices, + instead of just setting the volume of the first device it finds to zero. + If the Mute-Button is locked via Group Policies, WinMute will try to + use the Volume Slider to "emulate" sound muting. + + * XP: Actively tries to prevent other programs from unmuting the system. + + +Version 1.2 (2011-05-30) + + * Fixed a bug where WinMute could malfunction if the audio + device was changed or disconnected during a windows session. + + +Version 0.0 - 1.1 + + * These documents have been lost forever... \ No newline at end of file diff --git a/Bin/license.txt b/Bin/license.txt new file mode 100644 index 0000000..c1cf7a9 --- /dev/null +++ b/Bin/license.txt @@ -0,0 +1,29 @@ + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE \ No newline at end of file diff --git a/Bin/liesmich.html b/Bin/liesmich.html new file mode 100644 index 0000000..6121380 --- /dev/null +++ b/Bin/liesmich.html @@ -0,0 +1,78 @@ + + + + + WinMute 1.4 - Readme + + + + +

WinMute 1.4

+ + +

About

+

WinMute schaltet Windows stumm, sobald sie ihren PC sperren oder sich der Screensaver einschaltet.

+ +

+ Das ist vor allem in einer Büroumgebung nützlich, wenn Sie Ihren + Schreibtisch verlassen, aber die Kollegen nicht mit Musik oder + sonstigen Geräuschen aus Ihrem Computer stören möchten. +

+ + +

Systemvorraussetzungen

+ + +

Installation

+

Einfach WinMute in ein Verzeichnis Ihrer Wahl kopieren und das war's!

+

+ Wenn sie WinMute automatisch mit Windows starten möchten, + kopieren sie eine Verknüpfung zur WinMute.exe in den "Autostart" + Ordner, den sie im Startmenü unter "Programme" finden (um diesen + Ordner zu finden drücken sie Windows+R auf ihrer Tastatur und tippen dann + "Shell:Startup" in das Textfeld ein. Bestätigen sie das Fenster mit OK). +

+ +

Deinstallation

+

+ Einfach die WinMute.exe und ScreensaverNotify.dll löschen*. Zusätzlich legt WinMute in der Registry (regedit.exe) + im Verzeichnis HKEY_CURRENT_USER\Software\lx-systems\WinMute ab. Sollten sie die von WinMute + gespeicherten Einstellungen nichtmehr benötigen, können sie diese einfach entfernen. +

+

+ * Es kann sein, dass sich diese dll nicht sofort löschen lässt. Bei einem Fehler probieren sie es einfach + spätestens beim nächsten Neustart erneut. Diese Unannehmlichkeit ist leider eine Windows-Limitierung. +

+ +

Benutzung

+

Einfach starten - und fertig!

+

+ Sobald das Programm läuft, wird die + Lautstärke automatisch auf 0 gedreht, sobald Sie den PC sperren + oder sich der Bildschirmschoner aktiviert. + Wenn Sie wieder an den PC zurückkehren, wird die Lautstärke auf den + ursprünglichen Wert zurückgestellt. +

+ Wenn dieses Verhalten kurzzeitig deaktiviert werden soll, können + Sie dies über einen Rechtsklick auf das Taskbar-Icon bei der Uhr + erreichen, indem sie den Haken bei "Mute on Workstation lock" bzw. + "Mute on Screensaver start" tentfernen. +

+ + diff --git a/Bin/readme.html b/Bin/readme.html new file mode 100644 index 0000000..7cb5b0c --- /dev/null +++ b/Bin/readme.html @@ -0,0 +1,75 @@ + + + + + WinMute 1.4 - Readme + + + + +

WinMute 1.3

+ + +

About

+

WinMute automatically mutes your PC volume if you lock your screen or the screensaver is running.

+ +

+ This is very helpful e.g. if you leave your desk and don't want + to annoy your co-workers with random sounds or music from + your computer. +

+ + +

Requirements

+ + +

Installation

+

Unzip it to your favourite directory and you are all set up ;)

+

+ If you want WinMute to automatically start with your windows, + just create a shortcut to the winmute.exe file in the "Startup" + folder located in your Windows Startmenu (to open this folder, + press Win+R and enter "Shell:Startup", then click "OK"). +

+ +

Uninstalling WinMute

+

+ Just delete the WinMute.exe and ScreensaverNotify.dll* file from your hard drive. + If you want to also remove your personal WinMute settings, then open + the registry (regedit.exe) and delete the Folder located in + HKEY_CURRENT_USER\Software\lx-systems\WinMute. +

+

+ * It can happen, that you cannot remove this DLL file right away. + If you get an error trying to remove it, just wait until your next reboot + and delete it afterwards. This is unfortunately a windows limitation. +

+ +

Usage

+

Start it and that's it!

+

+ Whenever you lock your screen from now on or the screensaver starts, + WinMute will automatically mute your windows volume, and unmute it + right away when you come back to your pc.
+ If you want to disable this behaviour temporary, right-click + on the taskbar notification icon and uncheck the menu item + "Mute on Workstationlock" / "Mute on Screensaver start". +

+ + diff --git a/ScreensaverNotify/ScreensaverNotify.cpp b/ScreensaverNotify/ScreensaverNotify.cpp new file mode 100644 index 0000000..4d4a839 --- /dev/null +++ b/ScreensaverNotify/ScreensaverNotify.cpp @@ -0,0 +1,111 @@ +/* + ScreensaverNotify DLL + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include +#include "ScreensaverNotify.h" + + +/* ============================================================================= + DLL Globals + ========================================================================== */ + +#pragma data_seg(".shared") +static HHOOK hook_ = NULL; +static HWND hNotifyWnd_ = NULL; +static UINT notifyWndMsgId_ = 0; +#pragma data_seg() +#pragma comment(linker, "/SECTION:.shared,RWS") + +static HINSTANCE hglobInstance_ = NULL; + +/* ============================================================================= + Hook Function + ========================================================================== */ + +LRESULT CALLBACK MsgHookProc(UINT code, WPARAM wParam, LPARAM lParam) +{ + if (code >= 0) { + const LPMSG msg = reinterpret_cast(lParam); + if (msg->message == WM_SYSCOMMAND) { + if (msg->wParam == SC_SCREENSAVE) { + PostMessage(hNotifyWnd_, notifyWndMsgId_, wParam, lParam); + } + } + } + return CallNextHookEx(hook_, code, wParam, lParam); +} + +/* ============================================================================= + API + ========================================================================== */ + +extern "C" { + + WINMUTEDLL_API int RegisterScreensaverHook(HWND hNotifyWnd, UINT notifyWndMsgId) + { + if (hook_ != NULL) { + UnregisterScreensaverHook(); + } + hNotifyWnd_ = hNotifyWnd; + notifyWndMsgId_ = notifyWndMsgId; + hook_ = SetWindowsHookEx(WH_GETMESSAGE, + reinterpret_cast(MsgHookProc), + hglobInstance_, + 0); + return hook_ != NULL; + } + + WINMUTEDLL_API void UnregisterScreensaverHook() + { + if (hook_ != NULL) { + UnhookWindowsHookEx(hook_); + hook_ = NULL; + hNotifyWnd_ = NULL; + notifyWndMsgId_ = 0; + } + } + + BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD reason, LPVOID lpReserved) + { + UNREFERENCED_PARAMETER(lpReserved); + + if ((reason == DLL_PROCESS_ATTACH) && (hglobInstance_ == NULL)) { + hglobInstance_ = hInstance; + } + + return TRUE; + } + +} // extern "C" \ No newline at end of file diff --git a/ScreensaverNotify/ScreensaverNotify.h b/ScreensaverNotify/ScreensaverNotify.h new file mode 100644 index 0000000..90477d7 --- /dev/null +++ b/ScreensaverNotify/ScreensaverNotify.h @@ -0,0 +1,50 @@ +/* + ScreensaverNotify DLL + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include + +#ifdef WINMUTEDLL_EXPORTS + #define WINMUTEDLL_API __declspec(dllexport) +#else + #define WINMUTEDLL_API __declspec(dllimport) +#endif + +extern "C" { + + WINMUTEDLL_API int RegisterScreensaverHook(HWND hNotifyWnd, UINT notifyWndMsgId); + + WINMUTEDLL_API void UnregisterScreensaverHook(); + +} diff --git a/ScreensaverNotify/ScreensaverNotify.vcxproj b/ScreensaverNotify/ScreensaverNotify.vcxproj new file mode 100644 index 0000000..be6f26f --- /dev/null +++ b/ScreensaverNotify/ScreensaverNotify.vcxproj @@ -0,0 +1,95 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {A48C241D-70F5-4919-BE06-8C5BE99CCC23} + Win32Proj + ScreensaverNotify + ScreensaverNotify + + + + DynamicLibrary + true + v120 + Unicode + + + DynamicLibrary + false + v120_xp + true + Unicode + + + + + + + + + + + + + true + $(SolutionDir)Bin\ + $(ProjectName) + + + false + $(SolutionDir)Bin\ + $(ProjectName) + + + + NotUsing + Level4 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;WINMUTEDLL_EXPORTS;%(PreprocessorDefinitions) + true + true + + + Windows + true + + + + + Level4 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;WINMUTEDLL_EXPORTS;%(PreprocessorDefinitions) + true + true + MultiThreaded + + + Windows + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/ScreensaverNotify/ScreensaverNotify.vcxproj.filters b/ScreensaverNotify/ScreensaverNotify.vcxproj.filters new file mode 100644 index 0000000..96422cc --- /dev/null +++ b/ScreensaverNotify/ScreensaverNotify.vcxproj.filters @@ -0,0 +1,19 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/ScreensaverNotify/ScreensaverNotify.vcxproj.user b/ScreensaverNotify/ScreensaverNotify.vcxproj.user new file mode 100644 index 0000000..a375ae3 --- /dev/null +++ b/ScreensaverNotify/ScreensaverNotify.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/WinMute.sln b/WinMute.sln new file mode 100644 index 0000000..d7fd0f9 --- /dev/null +++ b/WinMute.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinMute", "WinMute\WinMute.vcxproj", "{488617F0-5DD3-42B5-81ED-A1E9B3117551}" + ProjectSection(ProjectDependencies) = postProject + {A48C241D-70F5-4919-BE06-8C5BE99CCC23} = {A48C241D-70F5-4919-BE06-8C5BE99CCC23} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScreensaverNotify", "ScreensaverNotify\ScreensaverNotify.vcxproj", "{A48C241D-70F5-4919-BE06-8C5BE99CCC23}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {488617F0-5DD3-42B5-81ED-A1E9B3117551}.Debug|Win32.ActiveCfg = Debug|Win32 + {488617F0-5DD3-42B5-81ED-A1E9B3117551}.Debug|Win32.Build.0 = Debug|Win32 + {488617F0-5DD3-42B5-81ED-A1E9B3117551}.Debug|x64.ActiveCfg = Debug|x64 + {488617F0-5DD3-42B5-81ED-A1E9B3117551}.Debug|x64.Build.0 = Debug|x64 + {488617F0-5DD3-42B5-81ED-A1E9B3117551}.Release|Win32.ActiveCfg = Release|Win32 + {488617F0-5DD3-42B5-81ED-A1E9B3117551}.Release|Win32.Build.0 = Release|Win32 + {488617F0-5DD3-42B5-81ED-A1E9B3117551}.Release|x64.ActiveCfg = Release|x64 + {488617F0-5DD3-42B5-81ED-A1E9B3117551}.Release|x64.Build.0 = Release|x64 + {A48C241D-70F5-4919-BE06-8C5BE99CCC23}.Debug|Win32.ActiveCfg = Debug|Win32 + {A48C241D-70F5-4919-BE06-8C5BE99CCC23}.Debug|Win32.Build.0 = Debug|Win32 + {A48C241D-70F5-4919-BE06-8C5BE99CCC23}.Debug|x64.ActiveCfg = Debug|Win32 + {A48C241D-70F5-4919-BE06-8C5BE99CCC23}.Release|Win32.ActiveCfg = Release|Win32 + {A48C241D-70F5-4919-BE06-8C5BE99CCC23}.Release|Win32.Build.0 = Release|Win32 + {A48C241D-70F5-4919-BE06-8C5BE99CCC23}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/WinMute/AboutDlg.cpp b/WinMute/AboutDlg.cpp new file mode 100644 index 0000000..a7ca22b --- /dev/null +++ b/WinMute/AboutDlg.cpp @@ -0,0 +1,68 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" + +INT_PTR CALLBACK AboutDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_INITDIALOG: + return TRUE; + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) { + EndDialog(hDlg, 0); + } + return 0; + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) { + case NM_CLICK: + case NM_RETURN: { + PNMLINK pNMLink = (PNMLINK)lParam; + LITEM item = pNMLink->item; + if ((((LPNMHDR)lParam)->idFrom == IDC_LINK_HOMEPAGE) && + (item.iLink == 0)) { + ShellExecute(nullptr, _T("open"), item.szUrl, nullptr, nullptr, + SW_SHOW); + } + break; + } + } + return TRUE; + case WM_CLOSE: + EndDialog(hDlg, 0); + return TRUE; + default: + break; + } + return FALSE; +} diff --git a/WinMute/MMNotificationClient.cpp b/WinMute/MMNotificationClient.cpp new file mode 100644 index 0000000..a95874a --- /dev/null +++ b/WinMute/MMNotificationClient.cpp @@ -0,0 +1,119 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" +#include "WinAudio.h" +#include "MMNotificationClient.h" + +class WinAudio; + +MMNotificationClient::MMNotificationClient(WinAudio* notifyParent) : + ref_(1), pEnumerator_(NULL), notifyParent_(notifyParent) +{ +} + +MMNotificationClient::~MMNotificationClient() +{ + SafeRelease(&pEnumerator_); +} + +ULONG STDMETHODCALLTYPE MMNotificationClient::AddRef() +{ + return InterlockedIncrement(&ref_); +} + +ULONG STDMETHODCALLTYPE MMNotificationClient::Release() +{ + ULONG ref = InterlockedDecrement(&ref_); + if (ref == 0) { + delete this; + } + return ref; +} + +HRESULT STDMETHODCALLTYPE MMNotificationClient::QueryInterface( + REFIID riid, + VOID **ppvInterface) +{ + if (IID_IUnknown == riid) { + AddRef(); + *ppvInterface = (IUnknown*)this; + } else if (__uuidof(IMMNotificationClient) == riid) { + AddRef(); + *ppvInterface = (IMMNotificationClient*)this; + } else { + *ppvInterface = NULL; + return E_NOINTERFACE; + } + return S_OK; +} + + +HRESULT STDMETHODCALLTYPE MMNotificationClient::OnDefaultDeviceChanged( + EDataFlow, + ERole, + LPCWSTR) +{ + if (notifyParent_) { + notifyParent_->ShouldReInit(); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE MMNotificationClient::OnDeviceAdded(LPCWSTR) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE MMNotificationClient::OnDeviceRemoved(LPCWSTR) +{ + if (notifyParent_) { + notifyParent_->ShouldReInit(); + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE MMNotificationClient::OnDeviceStateChanged(LPCWSTR, + DWORD) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE MMNotificationClient::OnPropertyValueChanged( + LPCWSTR, + const PROPERTYKEY) +{ + return S_OK; +} + + \ No newline at end of file diff --git a/WinMute/MMNotificationClient.h b/WinMute/MMNotificationClient.h new file mode 100644 index 0000000..53c46ef --- /dev/null +++ b/WinMute/MMNotificationClient.h @@ -0,0 +1,61 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" +#include + +class WinAudio; + +class MMNotificationClient : public IMMNotificationClient { +public: + MMNotificationClient(WinAudio* notifyParent); + ~MMNotificationClient(); + + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface); + + HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, + LPCWSTR pwstrDeviceId); + HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId); + HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId); + HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, + DWORD dwNewState); + HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, + const PROPERTYKEY key); + +private: + LONG ref_; + IMMDeviceEnumerator *pEnumerator_; + WinAudio* notifyParent_; +}; \ No newline at end of file diff --git a/WinMute/ScreensaverNotifier.cpp b/WinMute/ScreensaverNotifier.cpp new file mode 100644 index 0000000..0adee9c --- /dev/null +++ b/WinMute/ScreensaverNotifier.cpp @@ -0,0 +1,246 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" +#include "ScreensaverNotifier.h" + +/* ========================================================================== */ +/* Globals */ +/* ========================================================================== */ + +extern HINSTANCE hglobInstance; + +static LPCTSTR SCRSVER_NOTIFY_WND_CLASS = _T("ScreensaverNotify"); + +#define SCRSV_TIMER_ID 1 + +/* ========================================================================== */ +/* Window Helper */ +/* ========================================================================== */ + + +static LRESULT CALLBACK ScrsvrWndProc(HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + auto sn = reinterpret_cast( + GetWindowLongPtr(hWnd, GWLP_USERDATA)); + switch (msg) { + case WM_NCCREATE: { + LPCREATESTRUCTW cs = reinterpret_cast(lParam); + SetWindowLongPtr(hWnd, GWLP_USERDATA, + reinterpret_cast(cs->lpCreateParams)); + return TRUE; + } + default: + break; + } + return (sn) ? sn->WindowProc(hWnd, msg, wParam, lParam) + : DefWindowProc(hWnd, msg, wParam, lParam); +} + +/* ========================================================================== */ +/* Construction, Destruction */ +/* ========================================================================== */ + +ScreensaverNotifier::ScreensaverNotifier() : + hookDll_(nullptr), + regHook_(nullptr), + unregHook_(nullptr), + hookWndMsg_(0) +{ } + +ScreensaverNotifier::~ScreensaverNotifier() +{ + Unload(); +} + +/* ========================================================================== */ +/* Init, Unload */ +/* ========================================================================== */ + +bool ScreensaverNotifier::Init() +{ + if (hookDll_ != nullptr) { + return true; + } + return RegisterWindowClass() && + InitWindow() && + InitWindowMessage() && + InitHookDll(); +} + +bool ScreensaverNotifier::InitWindow() +{ + hWnd_ = CreateWindowEx(WS_EX_TOOLWINDOW, + SCRSVER_NOTIFY_WND_CLASS, + NULL, + WS_POPUP, + 0, 0, 0, 0, + HWND_MESSAGE, + 0, + hglobInstance, + this); + if (hWnd_ == NULL) { + PrintWindowsError(_T("CreateWindow")); + return false; + } + return true; +} + +bool ScreensaverNotifier::InitWindowMessage() +{ + hookWndMsg_ = RegisterWindowMessage(_T("WinMuteScreenSaveNotifyMsg")); + if (hookWndMsg_ == 0) { + PrintWindowsError(_T("RegisterWindowMessage")); + return false; + } + return true; +} + +bool ScreensaverNotifier::InitHookDll() +{ + if (hookDll_ == nullptr) { + hookDll_ = LoadLibrary(_T("ScreensaverNotify")); + if (hookDll_ == nullptr) { + PrintWindowsError(_T("LoadLibrary")); + } else { + regHook_ = reinterpret_cast( + GetProcAddress(hookDll_, "RegisterScreensaverHook")); + unregHook_ = reinterpret_cast( + GetProcAddress(hookDll_, "UnregisterScreensaverHook")); + if (regHook_ == NULL || unregHook_ == NULL) { + Unload(); + } + } + } + return hookDll_ != NULL; + +} + +bool ScreensaverNotifier::RegisterWindowClass() +{ + WNDCLASS wc = { 0 }; + wc.hIcon = LoadIcon(hglobInstance, MAKEINTRESOURCE(IDI_APP)); + wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); + wc.hInstance = hglobInstance; + wc.lpfnWndProc = ScrsvrWndProc; + wc.lpszClassName = SCRSVER_NOTIFY_WND_CLASS; + + if (!RegisterClass(&wc)) { + PrintWindowsError(_T("RegisterClass")); + return false; + } + return true; +} + +void ScreensaverNotifier::Unload() +{ + if (hookDll_) { + FreeLibrary(hookDll_); + regHook_ = nullptr; + unregHook_ = nullptr; + } +} + +/* ========================================================================== */ +/* Notifications */ +/* ========================================================================== */ + +bool ScreensaverNotifier::ActivateNotifications(HWND hNotifyWnd) +{ + hNotifyWnd_ = hNotifyWnd; + if (regHook_ != nullptr) { + return regHook_(hWnd_, hookWndMsg_) != 0; + } + return false; +} + +void ScreensaverNotifier::ClearNotifications() +{ + hNotifyWnd_ = nullptr; + if (unregHook_ != nullptr) { + unregHook_(); + } +} + +void ScreensaverNotifier::StartScreensaverPollTimer(bool start) +{ + if (start) { + if (SetTimer(hWnd_, SCRSV_TIMER_ID, 1000, NULL) == 0) { + PrintWindowsError(_T("SetTimer")); + } + } else { + KillTimer(hWnd_, SCRSV_TIMER_ID); + } +} + +/* ========================================================================== */ +/* Window Proc */ +/* ========================================================================== */ + +LRESULT CALLBACK ScreensaverNotifier::WindowProc(HWND hWnd, + UINT msg, + WPARAM wParam, + LPARAM lParam) +{ + static UINT uTaskbarRestart = 0; + switch (msg) { + case WM_CREATE: { + return TRUE; + } + case WM_TIMER: { + if (wParam == SCRSV_TIMER_ID) { + BOOL isRunning = FALSE; + if (SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, + 0, + &isRunning, + FALSE) == NULL) { + PrintWindowsError(_T("SystemParametersInfo")); + } else { + if (!isRunning) { + StartScreensaverPollTimer(false); + SendMessage(hNotifyWnd_, WM_SCRNSAVE_CHANGE, SCRNSAVE_STOP, 0); + } + } + } + return 0; + } + default: + if (hookWndMsg_ != 0 && msg == hookWndMsg_) { + SendMessage(hNotifyWnd_, WM_SCRNSAVE_CHANGE, SCRNSAVE_START, 0); + StartScreensaverPollTimer(); + } + break; + } + return DefWindowProc(hWnd, msg, wParam, lParam); +} \ No newline at end of file diff --git a/WinMute/ScreensaverNotifier.h b/WinMute/ScreensaverNotifier.h new file mode 100644 index 0000000..ef8ffb9 --- /dev/null +++ b/WinMute/ScreensaverNotifier.h @@ -0,0 +1,77 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "StdAfx.h" + +#define WM_SCRNSAVE_CHANGE (WM_APP + 100) + +#define SCRNSAVE_START 1 +#define SCRNSAVE_STOP 2 + +class ScreensaverNotifier { +public: + ScreensaverNotifier(); + ~ScreensaverNotifier(); + + ScreensaverNotifier(const ScreensaverNotifier&) = delete; + ScreensaverNotifier& operator= (const ScreensaverNotifier&) = delete; + + bool Init(); + void Unload(); + + bool ActivateNotifications(HWND hNotifyWnd); + void ClearNotifications(); + + + LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +private: + typedef int(*RegisterHook)(HWND, UINT); + typedef void(*UnregisterHook)(void); + + + HINSTANCE hookDll_; + HWND hWnd_, hNotifyWnd_; + UINT hookWndMsg_; + + RegisterHook regHook_; + UnregisterHook unregHook_; + + void StartScreensaverPollTimer(bool start = true); + + bool InitHookDll(); + bool RegisterWindowClass(); + bool InitWindow(); + bool InitWindowMessage(); +}; \ No newline at end of file diff --git a/WinMute/Settings.cpp b/WinMute/Settings.cpp new file mode 100644 index 0000000..6ccdfd4 --- /dev/null +++ b/WinMute/Settings.cpp @@ -0,0 +1,133 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" +#include "Settings.h" + +static const LPCWSTR LX_SYSTEMS_SUBKEY = _T("SOFTWARE\\lx-systems\\WinMute"); + + +static LPCWSTR KeyToStr(SettingsKey key) +{ + LPCWSTR keyStr = nullptr; + switch (key) { + case SettingsKey::MUTE_ON_LOCK: + keyStr = _T("MuteOnLock"); + break; + case SettingsKey::MUTE_ON_SCREENSAVER: + keyStr = _T("MuteOnScreensaver"); + break; + case SettingsKey::RESTORE_AUDIO: + keyStr = _T("RestoreAudio"); + break; + } + return keyStr; +} + + +Settings::Settings() : + hRegSettingsKey_(nullptr) +{ } + +Settings::~Settings() +{ + Unload(); +} + +bool Settings::Init() +{ + if (hRegSettingsKey_ == nullptr) { + DWORD regError = RegCreateKeyEx(HKEY_CURRENT_USER, + LX_SYSTEMS_SUBKEY, + 0, + NULL, + 0, + KEY_READ | KEY_WRITE, + NULL, + &hRegSettingsKey_, + NULL); + if (regError != ERROR_SUCCESS) { + PrintWindowsError(_T("RegCreateKeyEx"), regError); + return false; + } + } + + return true; +} + +void Settings::Unload() +{ + RegCloseKey(hRegSettingsKey_); + hRegSettingsKey_ = nullptr; +} + +DWORD Settings::QueryValue(SettingsKey key, DWORD defValue) +{ + auto keyStr = KeyToStr(key); + assert(keyStr != nullptr); + + DWORD value; + DWORD size = sizeof(DWORD); + DWORD regError = RegQueryValueEx(hRegSettingsKey_, + keyStr, + 0, + NULL, + reinterpret_cast(&value), + &size); + if (regError == ERROR_FILE_NOT_FOUND) { + return defValue; + } else if (regError != ERROR_SUCCESS) { + PrintWindowsError(_T("RegCreateKeyEx"), regError); + return defValue; + } + + return value; +} + +bool Settings::SetValue(SettingsKey key, DWORD value) +{ + auto keyStr = KeyToStr(key); + assert(keyStr != nullptr); + + DWORD regError = RegSetValueEx(hRegSettingsKey_, + keyStr, + 0, + REG_DWORD, + reinterpret_cast(&value), + sizeof(DWORD)); + if (regError != ERROR_SUCCESS) { + PrintWindowsError(_T("RegCreateKeyEx"), regError); + return false; + } + return true; +} \ No newline at end of file diff --git a/WinMute/Settings.h b/WinMute/Settings.h new file mode 100644 index 0000000..3471797 --- /dev/null +++ b/WinMute/Settings.h @@ -0,0 +1,60 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "StdAfx.h" + +enum class SettingsKey { + MUTE_ON_LOCK, + MUTE_ON_SCREENSAVER, + RESTORE_AUDIO +}; + +class Settings { +public: + Settings(); + ~Settings(); + + Settings(const Settings&) = delete; + Settings& operator=(const Settings&) = delete; + + bool Init(); + void Unload(); + + DWORD QueryValue(SettingsKey key, DWORD defValue); + bool SetValue(SettingsKey key, DWORD value); + +private: + HKEY hRegSettingsKey_; +}; \ No newline at end of file diff --git a/WinMute/StdAfx.cpp b/WinMute/StdAfx.cpp new file mode 100644 index 0000000..c27e33a --- /dev/null +++ b/WinMute/StdAfx.cpp @@ -0,0 +1,33 @@ +/* WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" diff --git a/WinMute/StdAfx.h b/WinMute/StdAfx.h new file mode 100644 index 0000000..0d96724 --- /dev/null +++ b/WinMute/StdAfx.h @@ -0,0 +1,91 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#ifdef _UNICODE + #if defined _M_IX86 + #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") + #elif defined _M_IA64 + #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") + #elif defined _M_X64 + #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") + #else + #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + #endif +#endif + +#define STRICT +#define _WIN32_WINNT 0x0600 +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "resource.h" + +#include "ScreensaverNotifier.h" +#include "Settings.h" +#include "TrayIcon.h" +#include "WinMute.h" +#include "VersionHelper.h" + +template +inline void SafeRelease(Interface** ppInterfaceToRelease) +{ + if (*ppInterfaceToRelease) { + (*ppInterfaceToRelease)->Release(); + (*ppInterfaceToRelease) = nullptr; + } +} + +#ifdef UNICODE + typedef std::basic_string tstring; +#else + typedef std::basic_string tstring; +#endif + +// Utility +void PrintWindowsError(LPTSTR lpszFunction, DWORD lastError = -1); + +const LPCTSTR PROGRAM_NAME = _T("WinMute"); diff --git a/WinMute/TrayIcon.cpp b/WinMute/TrayIcon.cpp new file mode 100644 index 0000000..ac3594e --- /dev/null +++ b/WinMute/TrayIcon.cpp @@ -0,0 +1,172 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" + +TrayIcon::TrayIcon() : + hIcon_(0), trayID_(0), hWnd_(0), iconVisible_(false) +{ + +} + +TrayIcon::TrayIcon(HWND hWnd, UINT trayID, HICON hIcon, + const std::wstring& tooltip, bool show) : + iconVisible_(false) +{ + Init(hWnd, trayID, hIcon, tooltip, show); +} + +void TrayIcon::Init(HWND hWnd, UINT trayID, HICON hIcon, + const std::wstring& tooltip, bool show) +{ + if (!hIcon) { + hIcon_ = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION)); + } else { + hIcon_ = hIcon; + } + + tooltip_ = tooltip; + trayID_ = trayID; + hWnd_ = hWnd; + + if (show) { + Show(); + } +} + +TrayIcon::~TrayIcon() +{ + Hide(); + DestroyTrayIcon(); +} + +void TrayIcon::Hide() +{ + if (iconVisible_) { + if (RemoveNotifyIcon()) { + iconVisible_ = false; + } + } +} + +void TrayIcon::Show() +{ + if (!iconVisible_) { + if(AddNotifyIcon()) { + iconVisible_ = true; + } + } +} + +void TrayIcon::ChangeIcon(HICON hNewIcon) +{ + if (!hNewIcon) { + return; + } + bool oldIconVisible = iconVisible_; + + DestroyTrayIcon(); + hIcon_ = hNewIcon; + + if (oldIconVisible) { + NOTIFYICONDATA tnid; + + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = hWnd_; + tnid.uID = trayID_; + tnid.hIcon = hIcon_; + tnid.uFlags = NIF_ICON; + + if (!Shell_NotifyIcon(NIM_MODIFY, &tnid)) + return; + + iconVisible_ = true; + } + + return; +} + +void TrayIcon::ChangeText(const std::wstring& tooltip) +{ + tooltip_ = tooltip; + + if (iconVisible_) + ChangeText(); +} + +void TrayIcon::DestroyTrayIcon() +{ + if (hIcon_) { + DestroyIcon(hIcon_); + hIcon_ = 0; + } +} + +bool TrayIcon::AddNotifyIcon() +{ + NOTIFYICONDATA tnid; + + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = hWnd_; + tnid.uID = trayID_; + tnid.uFlags = NIF_ICON|NIF_TIP|NIF_MESSAGE; + tnid.hIcon = hIcon_; + tnid.uCallbackMessage = WM_TRAYICON; + lstrcpyn(tnid.szTip, tooltip_.c_str(), sizeof(tnid.szTip) / sizeof(TCHAR)); + + return Shell_NotifyIcon(NIM_ADD, &tnid) != 0; +} + +bool TrayIcon::RemoveNotifyIcon() +{ + NOTIFYICONDATA tnid; + + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = hWnd_; + tnid.uID = trayID_; + + return Shell_NotifyIcon(NIM_DELETE, &tnid) != 0; +} + +bool TrayIcon::ChangeText() +{ + NOTIFYICONDATA tnid; + + tnid.cbSize = sizeof(NOTIFYICONDATA); + tnid.hWnd = hWnd_; + tnid.uID = trayID_; + tnid.uFlags = NIF_TIP; + lstrcpyn(tnid.szTip, tooltip_.c_str(), sizeof(tnid.szTip) / sizeof(TCHAR)); + + return Shell_NotifyIcon(NIM_MODIFY, &tnid) != 0; +} diff --git a/WinMute/TrayIcon.h b/WinMute/TrayIcon.h new file mode 100644 index 0000000..6d5ab24 --- /dev/null +++ b/WinMute/TrayIcon.h @@ -0,0 +1,64 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#pragma once +#include "StdAfx.h" + +#define WM_TRAYICON (WM_APP + 700) + +class TrayIcon{ +public: + TrayIcon(); + TrayIcon(HWND hWnd, UINT trayID, HICON hIcon, const std::wstring& tooltip, + bool show); + ~TrayIcon(); + void Init(HWND hWnd, UINT trayID, HICON hIcon, const std::wstring& tooltip, + bool show); + void Hide(); + void Show(); + bool IsShown() const { return iconVisible_; } + void ChangeIcon(HICON hNewIcon); + void ChangeText(const std::wstring& tooltip); + +private: + void DestroyTrayIcon(); + bool AddNotifyIcon(); + bool RemoveNotifyIcon(); + bool ChangeText(); + + bool iconVisible_; + UINT trayID_; + HICON hIcon_; + HWND hWnd_; + std::wstring tooltip_; +}; diff --git a/WinMute/Utility.cpp b/WinMute/Utility.cpp new file mode 100644 index 0000000..79543c1 --- /dev/null +++ b/WinMute/Utility.cpp @@ -0,0 +1,69 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" + +void PrintWindowsError(LPTSTR lpszFunction, DWORD lastError) +{ + // Retrieve the system error message for the last-error code + if (lastError == -1) { + lastError = GetLastError(); + } + + LPVOID lpMsgBuf; + if (FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&lpMsgBuf), 0, nullptr) != 0) { + + // Display the error message and exit the process + LPVOID lpDisplayBuf = reinterpret_cast(LocalAlloc(LMEM_ZEROINIT, + (lstrlen(static_cast(lpMsgBuf)) + + lstrlen(static_cast(lpszFunction)) + 40) + * sizeof(TCHAR))); + if (lpDisplayBuf) { + StringCchPrintf((LPTSTR)lpDisplayBuf, + LocalSize(lpDisplayBuf), + _T("%s failed with error %d: %s"), + lpszFunction, lastError, lpMsgBuf); + + MessageBox(nullptr, static_cast(lpDisplayBuf), _T("Error"), + MB_ICONERROR | MB_OK); + + LocalFree(lpDisplayBuf); + } + LocalFree(lpMsgBuf); + } +} diff --git a/WinMute/VersionHelper.h b/WinMute/VersionHelper.h new file mode 100644 index 0000000..38c8edb --- /dev/null +++ b/WinMute/VersionHelper.h @@ -0,0 +1,67 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "StdAfx.h" + +#ifndef _versionhelpers_H_INCLUDED_ // avoid conflict with MS versionhelpers + +inline bool IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, { 0 }, 0, 0 }; + DWORDLONG const dwlConditionMask = VerSetConditionMask( + VerSetConditionMask( + VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + + osvi.dwMajorVersion = wMajorVersion; + osvi.dwMinorVersion = wMinorVersion; + osvi.wServicePackMajor = wServicePackMajor; + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE; +} + +inline bool IsWindowsXPOrGreater() +{ + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0); +} + +inline bool IsWindowsVistaOrGreater() +{ + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0); +} + +#endif \ No newline at end of file diff --git a/WinMute/VistaAudio.cpp b/WinMute/VistaAudio.cpp new file mode 100644 index 0000000..a17f90d --- /dev/null +++ b/WinMute/VistaAudio.cpp @@ -0,0 +1,181 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" +#include + +#pragma warning(disable : 4201) +# include +#pragma warning(default : 4201) + +#include "WinAudio.h" +#include "VistaAudioSessionEvents.h" +#include "MMNotificationClient.h" + +VistaAudio::VistaAudio() : + endpointVolume_(nullptr), sessionControl_(nullptr), + wasapiAudioEvents_(nullptr), mmnAudioEvents_(nullptr), + deviceEnumerator_(nullptr), reInit_(false) +{ + CoInitialize(nullptr); +} + +VistaAudio::~VistaAudio() +{ + Uninit(); + CoUninitialize(); +} + +bool VistaAudio::Init(HWND hParent) +{ + hParent_ = hParent; + reInit_ = false; + + if(FAILED(CoCreateInstance(__uuidof(MMDeviceEnumerator), + nullptr, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&deviceEnumerator_)))) { + return false; + } + + IMMDevice *defaultDevice = nullptr; + if(FAILED(deviceEnumerator_->GetDefaultAudioEndpoint(eRender, eConsole, + &defaultDevice))) { + MessageBox(0, _T("Failed to get default audio endpoint device"), + PROGRAM_NAME, MB_ICONERROR); + return false; + } + + + IAudioSessionManager2* sessionManager2 = nullptr; + if (FAILED(defaultDevice->Activate(__uuidof(IAudioSessionManager2), + CLSCTX_INPROC_SERVER, nullptr, + reinterpret_cast(&sessionManager2)))) { + MessageBox(0, _T("Failed to retrieve audio session manager."), + PROGRAM_NAME, MB_ICONERROR); + SafeRelease(&defaultDevice); + return false; + } + + if (FAILED(sessionManager2->GetAudioSessionControl(nullptr, 0, + &sessionControl_))) { + MessageBox(0, _T("Failed to retrieve session control."), PROGRAM_NAME, + MB_ICONERROR); + SafeRelease(&sessionManager2); + return false; + } + SafeRelease(&sessionManager2); + + wasapiAudioEvents_ = new VistaAudioSessionEvents(this); + if (wasapiAudioEvents_) { + sessionControl_->RegisterAudioSessionNotification(wasapiAudioEvents_); + } + mmnAudioEvents_ = new MMNotificationClient(this); + if (mmnAudioEvents_) { + deviceEnumerator_->RegisterEndpointNotificationCallback(mmnAudioEvents_); + } + + if (FAILED(defaultDevice->Activate(__uuidof(IAudioEndpointVolume), + CLSCTX_INPROC_SERVER, nullptr, + reinterpret_cast(&endpointVolume_)))) { + MessageBox(0, _T("Failed to activate default audio device."), + PROGRAM_NAME, MB_ICONERROR); + SafeRelease(&defaultDevice); + return false; + } + defaultDevice->Release(); + + return true; +} + +void VistaAudio::Uninit() +{ + if (sessionControl_ && wasapiAudioEvents_) { + sessionControl_->UnregisterAudioSessionNotification(wasapiAudioEvents_); + } + if (deviceEnumerator_ && mmnAudioEvents_) { + deviceEnumerator_->UnregisterEndpointNotificationCallback(mmnAudioEvents_); + } + + SafeRelease(&wasapiAudioEvents_); + SafeRelease(&mmnAudioEvents_); + SafeRelease(&sessionControl_); + SafeRelease(&endpointVolume_); + SafeRelease(&deviceEnumerator_); +} + +void VistaAudio::ShouldReInit() +{ + reInit_ = true; +} + +bool VistaAudio::CheckForReInit() +{ + bool ok = true; + if (reInit_) { + Uninit(); + ok = Init(hParent_); + } + return ok; +} + +bool VistaAudio::IsMuted() +{ + if (CheckForReInit()) { + BOOL isMuted = FALSE; + endpointVolume_->GetMute(&isMuted); + return isMuted == TRUE; + } + return false; +} + +void VistaAudio::Mute() +{ + if (CheckForReInit()) { + BOOL isMuted = FALSE; + endpointVolume_->GetMute(&isMuted); + if (!isMuted) { + endpointVolume_->SetMute(TRUE, nullptr); + } + } +} + +void VistaAudio::UnMute() +{ + if (CheckForReInit()) { + BOOL isMuted = TRUE; + endpointVolume_->GetMute(&isMuted); + if (isMuted) { + endpointVolume_->SetMute(FALSE, nullptr); + } + } +} diff --git a/WinMute/VistaAudioSessionEvents.cpp b/WinMute/VistaAudioSessionEvents.cpp new file mode 100644 index 0000000..795352e --- /dev/null +++ b/WinMute/VistaAudioSessionEvents.cpp @@ -0,0 +1,149 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" +#include "WinAudio.h" +#include "VistaAudioSessionEvents.h" + + +VistaAudioSessionEvents::VistaAudioSessionEvents(WinAudio* notifyParent) : + ref_(1) +{ + notifyParent_ = notifyParent; +} + +VistaAudioSessionEvents::~VistaAudioSessionEvents() +{ +} + +ULONG STDMETHODCALLTYPE VistaAudioSessionEvents::AddRef() +{ + return InterlockedIncrement(&ref_); +} + +ULONG STDMETHODCALLTYPE VistaAudioSessionEvents::Release() +{ + ULONG ref = InterlockedDecrement(&ref_); + if (ref == 0) { + delete this; + } + return ref; +} + +HRESULT STDMETHODCALLTYPE VistaAudioSessionEvents::QueryInterface( + REFIID riid, + VOID **ppvInterface) +{ + if (riid == IID_IUnknown) { + AddRef(); + *ppvInterface = reinterpret_cast(this); + } else if (riid == __uuidof(IAudioSessionEvents)) { + AddRef(); + *ppvInterface = reinterpret_cast(this); + } else { + *ppvInterface = nullptr; + return E_NOINTERFACE; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE VistaAudioSessionEvents::OnDisplayNameChanged( + LPCWSTR /*newDisplayName*/, + LPCGUID /*eventContext*/) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE VistaAudioSessionEvents::OnIconPathChanged( + LPCWSTR /*newIconPath*/, + LPCGUID /*eventContext*/) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE VistaAudioSessionEvents::OnSimpleVolumeChanged( + float /*newVolume*/, + BOOL /*newMute*/, + LPCGUID /*eventContext*/) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE VistaAudioSessionEvents::OnChannelVolumeChanged( + DWORD /*channelCount*/, + float* /*newChannelVolumeArray[]*/, + DWORD /*changedChannel*/, + LPCGUID /*eventContext*/) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE VistaAudioSessionEvents::OnGroupingParamChanged( + LPCGUID /*newGroupingParam*/, + LPCGUID /*eventContext*/) +{ + return S_OK; +} + +HRESULT STDMETHODCALLTYPE VistaAudioSessionEvents::OnStateChanged( + AudioSessionState /*newState*/) +{ + return S_OK; +} + +/* See + * http://blogs.msdn.com/b/larryosterman/archive/2007/10/31/what-happens-when-audio-rendering-fails.aspx + * for detailed information about each of these entries */ +HRESULT STDMETHODCALLTYPE VistaAudioSessionEvents::OnSessionDisconnected( + AudioSessionDisconnectReason disconnectReason) +{ + + switch (disconnectReason) { + case DisconnectReasonDeviceRemoval: + case DisconnectReasonFormatChanged: + case DisconnectReasonSessionDisconnected: + notifyParent_->ShouldReInit(); + break; + case DisconnectReasonServerShutdown: + MessageBox(0, _T("The audio service has been shut down. ") + _T("WinMute is not able to recover from that condition.\n") + _T("Please try restarting the program"), PROGRAM_NAME, + MB_ICONWARNING | MB_OK); + break; + case DisconnectReasonSessionLogoff: + break; + case DisconnectReasonExclusiveModeOverride: + break; + } + return S_OK; +} diff --git a/WinMute/VistaAudioSessionEvents.h b/WinMute/VistaAudioSessionEvents.h new file mode 100644 index 0000000..f6719d4 --- /dev/null +++ b/WinMute/VistaAudioSessionEvents.h @@ -0,0 +1,82 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" +#include + +class WinAudio; + +class VistaAudioSessionEvents : public IAudioSessionEvents { +public: + VistaAudioSessionEvents(WinAudio* notifyParent); + ~VistaAudioSessionEvents(); + + // IUnknown methods -- AddRef, Release, and QueryInterface + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface); + + // Notification methods for audio session events + HRESULT STDMETHODCALLTYPE OnDisplayNameChanged( + LPCWSTR newDisplayName, + LPCGUID eventContext); + + HRESULT STDMETHODCALLTYPE OnIconPathChanged( + LPCWSTR newIconPath, + LPCGUID eventContext); + + HRESULT STDMETHODCALLTYPE OnSimpleVolumeChanged( + float newVolume, + BOOL newMute, + LPCGUID eventContext); + + HRESULT STDMETHODCALLTYPE OnChannelVolumeChanged( + DWORD channelCount, + float newChannelVolumeArray[], + DWORD changedChannel, + LPCGUID eventContext); + + HRESULT STDMETHODCALLTYPE OnGroupingParamChanged( + LPCGUID newGroupingParam, + LPCGUID eventContext); + + HRESULT STDMETHODCALLTYPE OnStateChanged(AudioSessionState newState); + + HRESULT STDMETHODCALLTYPE OnSessionDisconnected( + AudioSessionDisconnectReason disconnectReason); + +private: + LONG ref_; + WinAudio* notifyParent_; +}; diff --git a/WinMute/WinAudio.h b/WinMute/WinAudio.h new file mode 100644 index 0000000..4ebe0ab --- /dev/null +++ b/WinMute/WinAudio.h @@ -0,0 +1,118 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "StdAfx.h" + +class WinAudio { +public: + virtual bool Init(HWND hParent) = 0; + virtual void ShouldReInit() = 0; + virtual bool IsMuted() = 0; + virtual void Mute() = 0; + virtual void UnMute() = 0; + virtual ~WinAudio() { }; +}; + +class XPAudio : public WinAudio { +public: + XPAudio(); + ~XPAudio(); + + bool Init(HWND hParent); + void ShouldReInit(); + bool IsMuted(); + void Mute(); + void UnMute(); + + LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM); +private: + struct MixerDevice { + HMIXER hMixer; + bool useMute; + DWORD volCtrlID; + DWORD muteCtrlID; + DWORD oldValue; + }; + bool InitNotifyWindow(HWND hParent); + bool GetMuteControl(MixerDevice& md); + DWORD GetOldControlValue(const MixerDevice& md); + void MuteDevice(MixerDevice& md, bool saveOldValue); + void SetDeviceValue(MixerDevice& md, DWORD val); + + std::vector mixers_; + HWND hNotifyWnd_; + bool currentlyMuted_; + time_t muteTime_; + + // non copy-able + XPAudio(const XPAudio& other); + XPAudio& operator=(const XPAudio& other); +}; + +// Forwards +struct IAudioEndpointVolume; +struct IAudioSessionControl; +struct IMMDeviceEnumerator; +class VistaAudioSessionEvents; +class MMNotificationClient; + +class VistaAudio : public WinAudio { +public: + VistaAudio(); + ~VistaAudio(); + + bool Init(HWND hParent); + void ShouldReInit(); + bool IsMuted(); + void Mute(); + void UnMute(); +private: + void Uninit(); + bool CheckForReInit(); + + IAudioEndpointVolume* endpointVolume_; + IAudioSessionControl* sessionControl_; + IMMDeviceEnumerator *deviceEnumerator_; + VistaAudioSessionEvents* wasapiAudioEvents_; + MMNotificationClient* mmnAudioEvents_; + + bool reInit_; + float oldVolume_; + HWND hParent_; + + // non copy-able + VistaAudio(const VistaAudio& other); + VistaAudio& operator=(const VistaAudio& other); +}; \ No newline at end of file diff --git a/WinMute/WinMain.cpp b/WinMute/WinMain.cpp new file mode 100644 index 0000000..e3c5e9c --- /dev/null +++ b/WinMute/WinMain.cpp @@ -0,0 +1,91 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" + +HINSTANCE hglobInstance; + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) +{ + HANDLE hMutex = CreateMutex(nullptr, TRUE, _T("BinaryStudiosWinMute")); + if (hMutex == NULL) { + return FALSE; + } + if (GetLastError() == ERROR_ALREADY_EXISTS) { + ReleaseMutex(hMutex); + MessageBox(0, _T("WinMute is already running."), PROGRAM_NAME, + MB_ICONINFORMATION); + return FALSE; + } + + hglobInstance = hInstance; + + HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0); + + // + INITCOMMONCONTROLSEX initComCtrl; + initComCtrl.dwSize = sizeof(INITCOMMONCONTROLSEX); + initComCtrl.dwICC = ICC_LINK_CLASS; + if (InitCommonControlsEx(&initComCtrl) == FALSE){ + MessageBox(0, _T("Fatal Error:\n") + _T("Failed to register extended window controls"), + PROGRAM_NAME, MB_ICONSTOP); + ReleaseMutex(hMutex); + return FALSE; + } + // + + // + if (CoInitializeEx(0, COINIT_APARTMENTTHREADED) != S_OK) { + MessageBox(0, _T("Fatal Error:\nFailed to initialize COM library."), + PROGRAM_NAME, MB_ICONERROR); + ReleaseMutex(hMutex); + return FALSE; + } + + MSG msg = {0}; + WinMute program; + if (program.Init()) { + while (GetMessage(&msg, nullptr, 0, 0)) { + HWND hwnd = GetForegroundWindow(); + if (!IsWindow(hwnd) || !IsDialogMessage(hwnd, &msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } + + CoUninitialize(); + ReleaseMutex(hMutex); + return static_cast(msg.wParam); +} diff --git a/WinMute/WinMute.cpp b/WinMute/WinMute.cpp new file mode 100644 index 0000000..0702495 --- /dev/null +++ b/WinMute/WinMute.cpp @@ -0,0 +1,318 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" +#include "WinMute.h" +#include "WinAudio.h" + +extern HINSTANCE hglobInstance; +extern INT_PTR CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM); + +static LPCTSTR WINMUTE_CLASS_NAME = _T("WinMute"); + +static LRESULT CALLBACK WinMuteWndProc(HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + auto wm = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + switch (msg) { + case WM_NCCREATE: { + LPCREATESTRUCTW cs = reinterpret_cast(lParam); + SetWindowLongPtr(hWnd, GWLP_USERDATA, + reinterpret_cast(cs->lpCreateParams)); + return TRUE; + } + default: + break; + } + return (wm) ? wm->WindowProc(hWnd, msg, wParam, lParam) + : DefWindowProc(hWnd, msg, wParam, lParam); +} + +WinMute::WinMute() : + muteOnLock_(true), + muteOnScreensaver_(true), + restoreAudio_(true) +{ } + +WinMute::~WinMute() +{ + Unload(); +} + +bool WinMute::RegisterWindowClass() +{ + WNDCLASS wc={0}; + wc.hIcon = LoadIcon(hglobInstance, MAKEINTRESOURCE(IDI_APP)); + wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); + wc.hInstance = hglobInstance; + wc.lpfnWndProc = WinMuteWndProc; + wc.lpszClassName = WINMUTE_CLASS_NAME; + + if (!RegisterClass(&wc)) { + PrintWindowsError(_T("RegisterClass")); + return false; + } + return true; +} + +bool WinMute::InitWindow() +{ + hWnd_ = CreateWindowEx(WS_EX_TOOLWINDOW, WINMUTE_CLASS_NAME, PROGRAM_NAME, + WS_POPUP, 0, 0, 0, 0, HWND_MESSAGE, 0, hglobInstance, + this); + if (hWnd_ == nullptr) { + PrintWindowsError(_T("CreateWindowEx")); + return false; + } + return true; +} + +bool WinMute::InitAudio() +{ + if (IsWindowsVistaOrGreater()) { + audio_ = std::unique_ptr(new VistaAudio); + } else if (IsWindowsXPOrGreater()) { + audio_ = std::unique_ptr(new XPAudio); + } else { + MessageBox(0, _T("Only Windows versions XP and newer are supported"), + 0, MB_ICONERROR); + return false; + } + + if (!audio_->Init(hWnd_)) { + return false; + } + + return true; +} + +bool WinMute::InitTrayMenu() +{ + hTrayMenu_ = LoadMenu(hglobInstance, MAKEINTRESOURCE(IDR_TRAYMENU)); + if (!hTrayMenu_) { + PrintWindowsError(_T("LoadMenu")); + return false; + } else if (CheckMenuItem(hTrayMenu_, ID_TRAYMENU_MUTEONLOCK, + muteOnLock_ ? MF_CHECKED : MF_UNCHECKED) == -1 || + CheckMenuItem(hTrayMenu_, ID_TRAYMENU_MUTEONSCREENSAVER, + muteOnScreensaver_ ? MF_CHECKED : MF_UNCHECKED) == -1 || + CheckMenuItem(hTrayMenu_, ID_TRAYMENU_RESTOREAUDIO, + restoreAudio_ ? MF_CHECKED : MF_UNCHECKED) == -1) { + return false; + } + return true; +} + +bool WinMute::Init() +{ + hAppIcon_ = LoadIcon(hglobInstance, MAKEINTRESOURCE(IDI_APP)); + + if (!settings_.Init() || + !LoadDefaults()) { + return false; + } + + if (!RegisterWindowClass() || + !InitWindow() || + !InitTrayMenu()) { + return false; + } + + if (!scrnSaverNoti_.Init()) { + return false; + } + + if (muteOnScreensaver_) { + if (!scrnSaverNoti_.ActivateNotifications(hWnd_)) { + return false; + } + } + + if (!WTSRegisterSessionNotification(hWnd_, NOTIFY_FOR_THIS_SESSION)) { + PrintWindowsError(_T("WTSRegisterSessionNotification")); + return false; + } + + if (!InitAudio()) { + return false; + } + + trayIcon_.Init(hWnd_, 0, hAppIcon_, _T("WinMute"), true); + return true; +} + +bool WinMute::LoadDefaults() +{ + muteOnLock_ = + settings_.QueryValue(SettingsKey::MUTE_ON_LOCK, 1) != 0; + muteOnScreensaver_ = + settings_.QueryValue(SettingsKey::MUTE_ON_SCREENSAVER, 1) != 0; + restoreAudio_ = + settings_.QueryValue(SettingsKey::RESTORE_AUDIO, 1) != 0; + return true; +} + +void WinMute::CheckOrUncheckMenu(UINT item, bool* setting) +{ + UINT state = GetMenuState(hTrayMenu_, item, MF_BYCOMMAND); + if (state & MF_CHECKED) { + *setting = false; + CheckMenuItem(hTrayMenu_, item, MF_UNCHECKED); + } else { + *setting = true; + CheckMenuItem(hTrayMenu_, item, MF_CHECKED); + } +} + +LRESULT CALLBACK WinMute::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + static UINT uTaskbarRestart = 0; + switch (msg) { + case WM_CREATE: { + uTaskbarRestart = RegisterWindowMessage(_T("TaskbarCreated")); + return TRUE; + } + case WM_COMMAND: { + switch (LOWORD(wParam)) { + case ID_TRAYMENU_INFO: + DialogBox(hglobInstance, + MAKEINTRESOURCE(IDD_ABOUT), + hWnd_, + AboutDlgProc); + break; + case ID_TRAYMENU_EXIT: + SendMessage(hWnd, WM_CLOSE, 0, 0); + break; + case ID_TRAYMENU_MUTEONLOCK: + CheckOrUncheckMenu(ID_TRAYMENU_MUTEONLOCK, &muteOnLock_); + settings_.SetValue(SettingsKey::MUTE_ON_LOCK, muteOnLock_); + break; + case ID_TRAYMENU_RESTOREAUDIO: + CheckOrUncheckMenu(ID_TRAYMENU_RESTOREAUDIO, &restoreAudio_); + settings_.SetValue(SettingsKey::RESTORE_AUDIO, restoreAudio_); + break; + case ID_TRAYMENU_MUTEONSCREENSAVER: + CheckOrUncheckMenu(ID_TRAYMENU_MUTEONSCREENSAVER, &muteOnScreensaver_); + settings_.SetValue(SettingsKey::MUTE_ON_SCREENSAVER, muteOnScreensaver_); + if (muteOnScreensaver_) { + scrnSaverNoti_.ActivateNotifications(hWnd_); + } else { + scrnSaverNoti_.ClearNotifications(); + } + break; + case ID_TRAYMENU_MUTE: { + bool state = false; + CheckOrUncheckMenu(ID_TRAYMENU_MUTE, &state); + if (!state) { + audio_->UnMute(); + } else { + audio_->Mute(); + } + break; + } default: + __assume(0); + } + return 0; + } + case WM_TRAYICON: { + switch (lParam) { + case WM_LBUTTONUP: + case WM_RBUTTONUP: { + POINT p = {0}; + GetCursorPos(&p); + SetForegroundWindow(hWnd); + TrackPopupMenuEx(GetSubMenu(hTrayMenu_, 0), TPM_NONOTIFY | TPM_TOPALIGN + | TPM_LEFTALIGN, p.x, p.y, hWnd_, nullptr); + PostMessage(hWnd, WM_NULL, 0, 0); + break; + } + default: + break; + } + return TRUE; + } + case WM_CLOSE: { + Close(); + return 0; + } + case WM_WTSSESSION_CHANGE: { + static bool wasAlreadyMuted = false; + if (wParam == WTS_SESSION_LOCK) { + wasAlreadyMuted = audio_->IsMuted(); + if (!wasAlreadyMuted && muteOnLock_) { + audio_->Mute(); + } + } else if (wParam == WTS_SESSION_UNLOCK) { + if (!wasAlreadyMuted && muteOnLock_ && restoreAudio_) { + audio_->UnMute(); + } + } + return 0; + } + case WM_SCRNSAVE_CHANGE: { + static bool wasAlreadyMuted = false; + if (wParam == SCRNSAVE_START) { + wasAlreadyMuted = audio_->IsMuted(); + if (!wasAlreadyMuted && muteOnScreensaver_) { + audio_->Mute(); + } + } else if (wParam == SCRNSAVE_STOP) { + if (!wasAlreadyMuted && muteOnScreensaver_ && restoreAudio_) { + audio_->UnMute(); + } + } + return 0; + } + default: + if (msg == uTaskbarRestart) { // restore trayicon if explorer.exe crashes + trayIcon_.Hide(); + trayIcon_.Show(); + } + break; + } + + return DefWindowProc(hWnd, msg, wParam, lParam); +} + +void WinMute::Unload() +{ + scrnSaverNoti_.Unload(); + settings_.Unload(); +} + +void WinMute::Close() +{ + Unload(); + PostQuitMessage(0); +} diff --git a/WinMute/WinMute.h b/WinMute/WinMute.h new file mode 100644 index 0000000..476941e --- /dev/null +++ b/WinMute/WinMute.h @@ -0,0 +1,79 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#pragma once + +#include "StdAfx.h" + +class WinAudio; + +class WinMute { +public: + WinMute(); + ~WinMute(); + + bool Init(); + void Close(); + + HWND GetWnd(); + + // for internal use + LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +private: + HWND hWnd_; + HMENU hTrayMenu_; + HICON hAppIcon_; + bool muteOnLock_, + muteOnScreensaver_, + restoreAudio_; + + TrayIcon trayIcon_; + std::unique_ptr audio_; + ScreensaverNotifier scrnSaverNoti_; + Settings settings_; + + bool RegisterWindowClass(); + bool InitWindow(); + bool InitAudio(); + bool InitTrayMenu(); + bool LoadDefaults(); + + void Unload(); + + void CheckOrUncheckMenu(UINT item, bool* setting); + + + // Disable copying + WinMute(const WinMute&); + WinMute& operator=(const WinMute&); +}; diff --git a/WinMute/WinMute.vcxproj b/WinMute/WinMute.vcxproj new file mode 100644 index 0000000..6e7b3e7 --- /dev/null +++ b/WinMute/WinMute.vcxproj @@ -0,0 +1,212 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {488617F0-5DD3-42B5-81ED-A1E9B3117551} + WinMute + Win32Proj + + + + Application + Unicode + true + v120_xp + + + Application + Unicode + true + v120 + + + Application + Unicode + v120 + + + Application + Unicode + v120 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)Bin\ + $(SolutionDir)Bin\ + $(Configuration)\ + $(Configuration) (x64)\ + true + true + $(SolutionDir)Bin\ + $(SolutionDir)Bin\ + $(Configuration)\ + $(Configuration) (x64)\ + false + false + AllRules.ruleset + AllRules.ruleset + + + + + AllRules.ruleset + AllRules.ruleset + + + + + $(ProjectName) (x64) + $(ProjectName) (x64) + + + + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + Use + Level4 + EditAndContinue + + + strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;%(AdditionalDependencies) + true + Windows + MachineX86 + + + + + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + Level4 + ProgramDatabase + + + strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;%(AdditionalDependencies) + true + Windows + + + + + /MP %(AdditionalOptions) + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreaded + true + Use + Level4 + ProgramDatabase + true + + + strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;%(AdditionalDependencies) + $(SolutionDir)\Bin\$(ProjectName).exe + true + Windows + true + true + MachineX86 + + + + + /MP %(AdditionalOptions) + MaxSpeed + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + true + Use + Level4 + ProgramDatabase + + + strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + Windows + true + true + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WinMute/WinMute.vcxproj.filters b/WinMute/WinMute.vcxproj.filters new file mode 100644 index 0000000..f9bb087 --- /dev/null +++ b/WinMute/WinMute.vcxproj.filters @@ -0,0 +1,108 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {065a6082-9732-43e4-ad7b-714757809908} + + + {19d0b819-b48e-4418-917c-f92abc4c2160} + + + {4ea37611-be22-4541-bfcb-ca9d271b5166} + + + {aca601be-bf13-4396-89b2-8252b3fd2703} + + + {f9c118fc-0a72-4278-a710-841604aeb3e3} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files\Audio + + + Source Files\Audio + + + Source Files\UI + + + Source Files\UI + + + Source Files\Audio\Vista Notification + + + Source Files\Audio\Vista Notification + + + Source Files\Helper + + + Source Files\Helper + + + Source Files\Settings + + + + + Source Files\UI + + + Source Files + + + Source Files\UI + + + Source Files\Audio + + + Source Files + + + Source Files\Audio\Vista Notification + + + Source Files\Audio\Vista Notification + + + Source Files\Helper + + + Source Files\Helper + + + Source Files\Settings + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/WinMute/WinMute.vcxproj.user b/WinMute/WinMute.vcxproj.user new file mode 100644 index 0000000..ace9a86 --- /dev/null +++ b/WinMute/WinMute.vcxproj.user @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/WinMute/XPAudio.cpp b/WinMute/XPAudio.cpp new file mode 100644 index 0000000..66363f9 --- /dev/null +++ b/WinMute/XPAudio.cpp @@ -0,0 +1,339 @@ +/* + WinMute + Copyright (c) 2014 Alexander Steinhoefer + +----------------------------------------------------------------------------- +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the author nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +----------------------------------------------------------------------------- +*/ + +#include "StdAfx.h" +#include +#include "WinAudio.h" + +static const TCHAR* MIXER_NOTIFY_WND_CLASS = _T("WinMuteMixerNotifyWnd"); +extern HINSTANCE hglobInstance; + +LRESULT CALLBACK MixerWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + XPAudio* xpa = + reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + switch (msg) { + case WM_NCCREATE: { + LPCREATESTRUCTW cs = reinterpret_cast(lParam); + SetWindowLongPtr(hWnd, GWLP_USERDATA, + reinterpret_cast(cs->lpCreateParams)); + return TRUE; + } + default: + break; + } + return (xpa) ? xpa->WindowProc(hWnd, msg, wParam, lParam) + : DefWindowProc(hWnd, msg, wParam, lParam); +} + +static void PrintMixerError(const tstring& funcName, MMRESULT err) +{ +//#ifdef _DEBUG + std::basic_string error = funcName + L" failed with: "; + switch (err) { + case MIXERR_INVALCONTROL: + error += _T("The control reference is invalid."); + break; + case MIXERR_INVALLINE: + error += _T("The audio line reference is invalid."); + break; + case MMSYSERR_BADDEVICEID: + error += _T("The hmxobj parameter specifies an invalid device") + _T(" identifier."); + break; + case MMSYSERR_INVALFLAG: + error += _T("One or more flags are invalid."); + break; + case MMSYSERR_INVALHANDLE: + error += _T("The hmxobj parameter specifies an invalid handle."); + break; + case MMSYSERR_INVALPARAM: + error += _T("One or more parameters are invalid."); + break; + case MMSYSERR_NODRIVER: + error += _T("No mixer device is available for the object specified") + _T(" by hmxobj."); + break; + default: { + error += _T("An unknown error: "); + std::wstringstream s; + s << err; + error += s.str(); + + break; + } + } + MessageBox(0, error.c_str(), 0, MB_ICONERROR); +//#else +// UNREFERENCED_PARAMETER(funcName); +// UNREFERENCED_PARAMETER(err); +//#endif +} + +XPAudio::XPAudio() : + hNotifyWnd_(nullptr), currentlyMuted_(false), muteTime_(0) +{ +} + +XPAudio::~XPAudio() +{ + std::for_each(mixers_.begin(), mixers_.end(), [](XPAudio::MixerDevice& md) { + mixerClose(md.hMixer); + }); + mixers_.clear(); + DestroyWindow(hNotifyWnd_); +} + +/* ----------------------------------------------------------------------------- + Init + -------------------------------------------------------------------------- */ + +bool XPAudio::Init(HWND hParent) +{ + if (!InitNotifyWindow(hParent)) + return false; + + UINT numMixers = mixerGetNumDevs(); + for (UINT i = 0; i < numMixers; ++i) { + MixerDevice md; + if (mixerOpen(&md.hMixer, i, reinterpret_cast(hNotifyWnd_), + 0, CALLBACK_WINDOW) == MMSYSERR_NOERROR) { + MIXERCAPS mixcaps; + mixerGetDevCaps(i, &mixcaps, sizeof(MIXERCAPS)); + if (GetMuteControl(md)) { + mixers_.push_back(md); + } else { + mixerClose(md.hMixer); + } + } + } + return !mixers_.empty(); +} + +bool XPAudio::InitNotifyWindow(HWND hParent) +{ + WNDCLASS wc={0}; + wc.hInstance = hglobInstance; + wc.lpfnWndProc = MixerWndProc; + wc.lpszClassName = MIXER_NOTIFY_WND_CLASS; + + if (!RegisterClass(&wc)) { + PrintWindowsError(_T("RegisterClass")); + return false; + } + hNotifyWnd_ = CreateWindow(MIXER_NOTIFY_WND_CLASS, 0, 0, 0, 0, 0, 0, + hParent, 0, hglobInstance, this); + if (hNotifyWnd_ == nullptr) { + PrintWindowsError(_T("CreateWindow")); + return false; + } + return true; +} + +void XPAudio::ShouldReInit() +{ +} + +bool XPAudio::GetMuteControl(XPAudio::MixerDevice& md) +{ + MIXERLINE mxl = {0}; + mxl.cbStruct = sizeof(MIXERLINE); + mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; + + MMRESULT mmrErr = mixerGetLineInfo(reinterpret_cast(md.hMixer), + &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE); + if (mmrErr != MMSYSERR_NOERROR) { + return false; + } + + // At first: Try to optain the Mute-Control. + MIXERCONTROL mxCtrl = {0}; + MIXERLINECONTROLS mxLineCtrls = {0}; + mxLineCtrls.cbStruct = sizeof(MIXERLINECONTROLS); + mxLineCtrls.cControls = 1; + mxLineCtrls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE; + mxLineCtrls.dwLineID = mxl.dwLineID; + mxLineCtrls.pamxctrl = &mxCtrl; + mxLineCtrls.cbmxctrl = sizeof(MIXERCONTROL); + + mmrErr = mixerGetLineControls(reinterpret_cast(md.hMixer), + &mxLineCtrls, MIXER_GETLINECONTROLSF_ONEBYTYPE); + + if (mmrErr != MMSYSERR_NOERROR) { + // If this doesn't work, get the volume slider + mxLineCtrls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; + mmrErr = mixerGetLineControls(reinterpret_cast(md.hMixer), + &mxLineCtrls, MIXER_GETLINECONTROLSF_ONEBYTYPE); + if (mmrErr != MMSYSERR_NOERROR) { + return false; + } + md.volCtrlID = mxCtrl.dwControlID; + md.useMute = false; + } else { + md.muteCtrlID = mxCtrl.dwControlID; + md.useMute = true; + } + + return true; +} + +/* ----------------------------------------------------------------------------- + Window Proc + -------------------------------------------------------------------------- */ + +LRESULT CALLBACK XPAudio::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, + LPARAM lParam) +{ + static bool muteLock = false; + if (msg == MM_MIXM_CONTROL_CHANGE) { + if (!muteLock && currentlyMuted_ && time(0) - muteTime_ > 1) { + muteLock = true; + for (auto md = mixers_.begin(); md != mixers_.end(); ++md) { + if (reinterpret_cast(wParam) == md->hMixer) { + DWORD notifyID = static_cast(lParam); + if (notifyID == md->muteCtrlID || notifyID == md->volCtrlID) { + MuteDevice(*md, false); + } + } + } + SetTimer(hWnd, 5, 200, NULL); + } + return 0; + } else if (msg == WM_TIMER) { + if (wParam == 5 && muteLock) { + KillTimer(hWnd, 5); + muteLock = false; + } + } + return DefWindowProc(hWnd, msg, wParam, lParam); +} + + +/* ----------------------------------------------------------------------------- + Mute Logic + -------------------------------------------------------------------------- */ + +bool XPAudio::IsMuted() +{ + return currentlyMuted_; +} + +DWORD XPAudio::GetOldControlValue(const MixerDevice& md) +{ + MMRESULT err; + MIXERCONTROLDETAILS mxcd = {0}; + mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); + mxcd.cChannels = 1; + DWORD oldVal; + if (md.useMute) { // Mute control + MIXERCONTROLDETAILS_BOOLEAN mxCtrlDetMuted = { 0 }; + mxcd.dwControlID = md.muteCtrlID; + mxcd.paDetails = &mxCtrlDetMuted; + mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); + + err = mixerGetControlDetails(reinterpret_cast(md.hMixer), + &mxcd, MIXER_GETCONTROLDETAILSF_VALUE); + oldVal = mxCtrlDetMuted.fValue; + } else { // Volume Slider control + MIXERCONTROLDETAILS_UNSIGNED mxCtrlVolume = { 0 }; + + mxcd.dwControlID = md.volCtrlID; + mxcd.paDetails = &mxCtrlVolume; + mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + + err = mixerGetControlDetails(reinterpret_cast(md.hMixer), + &mxcd, MIXER_GETCONTROLDETAILSF_VALUE); + oldVal = mxCtrlVolume.dwValue; + } + + if (err != MMSYSERR_NOERROR) { + PrintMixerError(L"mixerGetControlDetails", err); + return 0; + } + + return oldVal; +} + +void XPAudio::SetDeviceValue(XPAudio::MixerDevice& md, DWORD val) +{ + MIXERCONTROLDETAILS mxcd = {0}; + mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS); + mxcd.cChannels = 1; + + MIXERCONTROLDETAILS_UNSIGNED mxCtrlDetVolume = { val }; + MIXERCONTROLDETAILS_BOOLEAN mxCtrlDetMuted = { val }; + + if (md.useMute) { + mxcd.dwControlID = md.muteCtrlID; + mxcd.paDetails = &mxCtrlDetMuted; + mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); + } else { // Volume Slider + mxcd.dwControlID = md.volCtrlID; + mxcd.paDetails = &mxCtrlDetVolume; + mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); + } + + MMRESULT mmrErr = mixerSetControlDetails( + reinterpret_cast(md.hMixer), &mxcd, + MIXER_OBJECTF_MIXER | MIXER_SETCONTROLDETAILSF_VALUE); + + if (mmrErr != MMSYSERR_NOERROR) { + PrintMixerError(_T("mixerSetControlDetails"), mmrErr); + } +} + +void XPAudio::MuteDevice(XPAudio::MixerDevice& md, bool saveOldValue) +{ + if (saveOldValue) { + md.oldValue = GetOldControlValue(md); + } + SetDeviceValue(md, md.useMute ? 1 : 0); +} + +void XPAudio::Mute() +{ + for (auto md = mixers_.begin(); md != mixers_.end(); ++md) { + MuteDevice(*md, true); + } + currentlyMuted_ = true; + muteTime_ = time(0); +} + +void XPAudio::UnMute() +{ + muteTime_ = 0; + currentlyMuted_ = false; // Order important (s. WindowProc notification) + for (auto md = mixers_.begin(); md != mixers_.end(); ++md) { + SetDeviceValue(*md, md->oldValue); + } +} diff --git a/WinMute/app.ico b/WinMute/app.ico new file mode 100644 index 0000000..2ff05b2 Binary files /dev/null and b/WinMute/app.ico differ diff --git a/WinMute/res.rc b/WinMute/res.rc new file mode 100644 index 0000000..d1d92aa --- /dev/null +++ b/WinMute/res.rc @@ -0,0 +1,183 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_TRAYMENU MENU +BEGIN + POPUP "TrayMenu" + BEGIN + MENUITEM "Info", ID_TRAYMENU_INFO + MENUITEM SEPARATOR + MENUITEM "Mute on ...", ID_TRAYMENU_MUTEON, INACTIVE + MENUITEM "... Workstation lock", ID_TRAYMENU_MUTEONLOCK, CHECKED + MENUITEM "... Screensaver start", ID_TRAYMENU_MUTEONSCREENSAVER, CHECKED + MENUITEM SEPARATOR + MENUITEM "Restore Audio", ID_TRAYMENU_RESTOREAUDIO, CHECKED + MENUITEM SEPARATOR + MENUITEM "Mute now", ID_TRAYMENU_MUTE + MENUITEM SEPARATOR + MENUITEM "Exit", ID_TRAYMENU_EXIT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOGEX 0, 0, 251, 52 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION +CAPTION "About WinMute" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,194,7,50,14 + LTEXT "WinMute v1.4",IDC_STATIC,43,9,67,11 + CONTROL "lx-systems - lx-s.de",IDC_LINK_HOMEPAGE, + "SysLink",WS_TABSTOP,43,31,69,13 + LTEXT "Copyright © 2014 Alexander Steinhöfer",IDC_STATIC,43,20,148,12 + ICON IDI_APP,IDC_STATIC,13,7,20,20 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 244 + VERTGUIDE, 43 + TOPMARGIN, 7 + BOTTOMMARGIN, 45 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,4,0,0 + PRODUCTVERSION 1,4,0,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "lx-s" + VALUE "FileDescription", "Automatic sound muter." + VALUE "FileVersion", "1.4.0.0" + VALUE "InternalName", "WinMute" + VALUE "LegalCopyright", "Copyright (C) 2013 Alexander Steinhöfer" + VALUE "OriginalFilename", "WinMute.exe" + VALUE "ProductName", "WinMute" + VALUE "ProductVersion", "1.4.0.0" + END + BLOCK "040704b0" + BEGIN + VALUE "CompanyName", "lx-s" + VALUE "FileDescription", "Automatisches Stummschalten bei PC Sperre." + VALUE "FileVersion", "1.4.0.0" + VALUE "InternalName", "WinMute" + VALUE "LegalCopyright", "Copyright (C) 2013 Alexander Steinhöfer" + VALUE "OriginalFilename", "WinMute.exe" + VALUE "ProductName", "WinMute" + VALUE "ProductVersion", "1.4.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200, 0x407, 1200 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP ICON "app.ico" +#endif // German (Germany) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/WinMute/resource.h b/WinMute/resource.h new file mode 100644 index 0000000..f0fa03c --- /dev/null +++ b/WinMute/resource.h @@ -0,0 +1,31 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by res.rc +// +#define IDR_TRAYMENU 101 +#define IDD_ABOUT 102 +#define IDI_APP 106 +#define IDC_LINK_HOMEPAGE 1001 +#define ID_TRAYMENU_INFO 40001 +#define ID_TRAYMENU_EXIT 40002 +#define ID_TRAYMENU_MUTEONLOCK 40003 +#define ID_TRAYMENU_MUTEONSCREENSAVER 40004 +#define ID_TRAYMENU_ 40005 +#define ID_TRAYMENU_MUTEONMONITOROFF 40006 +#define ID_TRAYMENU_MUTE 40007 +#define ID_TRAYMENU_MUTEONSCREENSAVER40008 40008 +#define ID_TRAYMENU_RESTOREAUDIO 40009 +#define ID_TRAYMENU_40010 40010 +#define ID_TRAYMENU_40011 40011 +#define ID_TRAYMENU_MUTEON 40012 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 107 +#define _APS_NEXT_COMMAND_VALUE 40013 +#define _APS_NEXT_CONTROL_VALUE 1002 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif