]> repos.lx-s.de Git - winmute.git/commitdiff
Initial commit to github (WinMute Version 1.4) 1.4
authorunknown <Alexander.steinhoefe@W9490082.iuk.stv.bayern.de>
Thu, 10 Jul 2014 13:20:49 +0000 (15:20 +0200)
committerunknown <Alexander.steinhoefe@W9490082.iuk.stv.bayern.de>
Thu, 10 Jul 2014 13:20:49 +0000 (15:20 +0200)
37 files changed:
Bin/changelog.txt [new file with mode: 0644]
Bin/license.txt [new file with mode: 0644]
Bin/liesmich.html [new file with mode: 0644]
Bin/readme.html [new file with mode: 0644]
ScreensaverNotify/ScreensaverNotify.cpp [new file with mode: 0644]
ScreensaverNotify/ScreensaverNotify.h [new file with mode: 0644]
ScreensaverNotify/ScreensaverNotify.vcxproj [new file with mode: 0644]
ScreensaverNotify/ScreensaverNotify.vcxproj.filters [new file with mode: 0644]
ScreensaverNotify/ScreensaverNotify.vcxproj.user [new file with mode: 0644]
WinMute.sln [new file with mode: 0644]
WinMute/AboutDlg.cpp [new file with mode: 0644]
WinMute/MMNotificationClient.cpp [new file with mode: 0644]
WinMute/MMNotificationClient.h [new file with mode: 0644]
WinMute/ScreensaverNotifier.cpp [new file with mode: 0644]
WinMute/ScreensaverNotifier.h [new file with mode: 0644]
WinMute/Settings.cpp [new file with mode: 0644]
WinMute/Settings.h [new file with mode: 0644]
WinMute/StdAfx.cpp [new file with mode: 0644]
WinMute/StdAfx.h [new file with mode: 0644]
WinMute/TrayIcon.cpp [new file with mode: 0644]
WinMute/TrayIcon.h [new file with mode: 0644]
WinMute/Utility.cpp [new file with mode: 0644]
WinMute/VersionHelper.h [new file with mode: 0644]
WinMute/VistaAudio.cpp [new file with mode: 0644]
WinMute/VistaAudioSessionEvents.cpp [new file with mode: 0644]
WinMute/VistaAudioSessionEvents.h [new file with mode: 0644]
WinMute/WinAudio.h [new file with mode: 0644]
WinMute/WinMain.cpp [new file with mode: 0644]
WinMute/WinMute.cpp [new file with mode: 0644]
WinMute/WinMute.h [new file with mode: 0644]
WinMute/WinMute.vcxproj [new file with mode: 0644]
WinMute/WinMute.vcxproj.filters [new file with mode: 0644]
WinMute/WinMute.vcxproj.user [new file with mode: 0644]
WinMute/XPAudio.cpp [new file with mode: 0644]
WinMute/app.ico [new file with mode: 0644]
WinMute/res.rc [new file with mode: 0644]
WinMute/resource.h [new file with mode: 0644]

diff --git a/Bin/changelog.txt b/Bin/changelog.txt
new file mode 100644 (file)
index 0000000..9a27f75
--- /dev/null
@@ -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 (file)
index 0000000..c1cf7a9
--- /dev/null
@@ -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 (file)
index 0000000..6121380
--- /dev/null
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html lang="de">
+<head>
+   <meta charset="utf-8">
+   <title>WinMute 1.4 - Readme</title>
+
+   <style type="text/css">
+   <!--
+      html, body { margin: 0; padding: 0 }
+      body { color: #000; background-color: #fff; font-family: "Segoe UI", Verdana, san-serif; font-size: 0.8em; padding: 10px 0 0 10px; line-height: 1.8; }
+      h1, h2 { font-family: "Segoe UI Light", Verdana; }
+      h1 { font-size: 1.8em; margin: 0 0 3px 0; }
+      h2 { font-size: 1.4em; margin: 20px 0 5px 0; }
+      .copyright { color: #aaa; }
+      p { color: #444; width: 600px; margin: 0 0 10px 5px; }
+   -->
+   </style>
+</head>
+<body>
+   <h1>WinMute 1.4</h1>
+   <p class="copyright">&copy; Copyright 2014, Alexander Steinh&ouml;fer - <a href="http://www.lx-s.de">www.lx-s.de</a></p>
+
+   <h2>About</h2>
+   <p>WinMute schaltet Windows stumm, sobald sie ihren PC sperren oder sich der Screensaver einschaltet.</p>
+
+   <p>
+      Das ist vor allem in einer B&uuml;roumgebung n&uuml;tzlich, wenn Sie Ihren
+      Schreibtisch verlassen, aber die Kollegen nicht mit Musik oder
+      sonstigen Ger&auml;uschen aus Ihrem Computer st&ouml;ren m&ouml;chten.
+   </p>
+
+   <a name="requirements"></a>
+   <h2>Systemvorraussetzungen</h2>
+   <ul>
+      <li>Betriebssystem:
+         <ul>
+            <li>Windows XP SP3 oder aktueller</li>
+         </ul>
+      </li>
+   </ul>
+
+   <h2>Installation</h2>
+   <p>Einfach WinMute in ein Verzeichnis Ihrer Wahl kopieren und das war's!</p>
+   <p>
+      Wenn sie WinMute automatisch mit Windows starten m&ouml;chten,
+      kopieren sie eine Verkn&uuml;pfung zur WinMute.exe in den &quot;Autostart&quot;
+      Ordner, den sie im Startmen&uuml; unter &quot;Programme&quot; finden (um diesen
+         Ordner zu finden drücken sie Windows+R auf ihrer Tastatur und tippen dann
+         &quot;Shell:Startup&quot; in das Textfeld ein. Bestätigen sie das Fenster mit OK).
+   </p>
+
+   <h2>Deinstallation</h2>
+   <p>
+      Einfach die WinMute.exe und ScreensaverNotify.dll l&ouml;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.
+   </p>
+   <p>
+       * 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.
+  </p>
+
+   <h2>Benutzung</h2>
+   <p>Einfach starten - und fertig!</p>
+   <p>
+      Sobald das Programm l&auml;uft, wird die
+      Lautst&auml;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&auml;rke auf den
+         urspr&uuml;nglichen Wert zur&uuml;ckgestellt.
+   </p><p>
+      Wenn dieses Verhalten kurzzeitig deaktiviert werden soll, k&ouml;nnen
+      Sie dies &uuml;ber einen Rechtsklick auf das Taskbar-Icon bei der Uhr
+      erreichen, indem sie den Haken bei &quot;Mute on Workstation lock&quot; bzw.
+         &quot;Mute on Screensaver start&quot; tentfernen.
+   </p>
+</body>
+</html>
diff --git a/Bin/readme.html b/Bin/readme.html
new file mode 100644 (file)
index 0000000..7cb5b0c
--- /dev/null
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+   <meta charset="utf-8">
+   <title>WinMute 1.4 - Readme</title>
+
+   <style type="text/css">
+   <!--
+      html, body { margin: 0; padding: 0 }
+      body { color: #000; background-color: #fff; font-family: "Segoe UI", Verdana, san-serif; font-size: 0.8em; padding: 10px 0 0 10px; line-height: 1.8; }
+      h1, h2 { font-family: "Segoe UI Light", Verdana; }
+      h1 { font-size: 1.8em; margin: 0 0 3px 0; }
+      h2 { font-size: 1.4em; margin: 20px 0 5px 0; }
+      .copyright { color: #aaa; }
+      p { color: #444; width: 600px; margin: 0 0 10px 5px; }
+   -->
+   </style>
+</head>
+<body>
+   <h1>WinMute 1.3</h1>
+   <p class="copyright">&copy; Copyright 2014, by Alexander Steinh&ouml;fer - <a href="http://www.lx-s.de">www.lx-s.de</a></p>
+
+   <h2>About</h2>
+   <p>WinMute automatically mutes your PC volume if you lock your screen or the screensaver is running.</p>
+
+   <p>
+      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.
+   </p>
+
+   <a name="requirements"></a>
+   <h2>Requirements</h2>
+   <ul>
+      <li>Operating System
+         <ul>
+            <li>Windows XP SP3 or newer</li>
+         </ul>
+      </li>
+   </ul>
+
+   <h2>Installation</h2>
+   <p>Unzip it to your favourite directory and you are all set up ;)</p>
+   <p>
+      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").
+   </p>
+
+   <h2>Uninstalling WinMute</h2>
+   <p>
+      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.
+   </p>
+   <p>
+       * 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.
+   </p>
+
+   <h2>Usage</h2>
+   <p>Start it and that's it!</p>
+   <p>
+      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.<br>
+      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".
+   </p>
+</body>
+</html>
diff --git a/ScreensaverNotify/ScreensaverNotify.cpp b/ScreensaverNotify/ScreensaverNotify.cpp
new file mode 100644 (file)
index 0000000..4d4a839
--- /dev/null
@@ -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 <SDKDDKVer.h>
+#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<LPMSG>(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<HOOKPROC>(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 (file)
index 0000000..90477d7
--- /dev/null
@@ -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 <Windows.h>
+
+#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 (file)
index 0000000..be6f26f
--- /dev/null
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{A48C241D-70F5-4919-BE06-8C5BE99CCC23}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>ScreensaverNotify</RootNamespace>
+    <ProjectName>ScreensaverNotify</ProjectName>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120_xp</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <OutDir>$(SolutionDir)Bin\</OutDir>
+    <TargetName>$(ProjectName)</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+    <OutDir>$(SolutionDir)Bin\</OutDir>
+    <TargetName>$(ProjectName)</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;WINMUTEDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level4</WarningLevel>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+      <Optimization>MaxSpeed</Optimization>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;WINMUTEDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <SDLCheck>true</SDLCheck>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClInclude Include="ScreensaverNotify.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="ScreensaverNotify.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/ScreensaverNotify/ScreensaverNotify.vcxproj.filters b/ScreensaverNotify/ScreensaverNotify.vcxproj.filters
new file mode 100644 (file)
index 0000000..96422cc
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="ScreensaverNotify.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="ScreensaverNotify.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/ScreensaverNotify/ScreensaverNotify.vcxproj.user b/ScreensaverNotify/ScreensaverNotify.vcxproj.user
new file mode 100644 (file)
index 0000000..a375ae3
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup />
+</Project>
\ No newline at end of file
diff --git a/WinMute.sln b/WinMute.sln
new file mode 100644 (file)
index 0000000..d7fd0f9
--- /dev/null
@@ -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 (file)
index 0000000..a7ca22b
--- /dev/null
@@ -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 (file)
index 0000000..a95874a
--- /dev/null
@@ -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 (file)
index 0000000..53c46ef
--- /dev/null
@@ -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 <Mmdeviceapi.h>
+
+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 (file)
index 0000000..0adee9c
--- /dev/null
@@ -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<ScreensaverNotifier*>(
+                                         GetWindowLongPtr(hWnd, GWLP_USERDATA));
+   switch (msg) {
+   case WM_NCCREATE: {
+      LPCREATESTRUCTW cs = reinterpret_cast<LPCREATESTRUCTW>(lParam);
+      SetWindowLongPtr(hWnd, GWLP_USERDATA,
+                       reinterpret_cast<LONG>(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<RegisterHook>(
+            GetProcAddress(hookDll_, "RegisterScreensaverHook"));
+         unregHook_ = reinterpret_cast<UnregisterHook>(
+            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 (file)
index 0000000..ef8ffb9
--- /dev/null
@@ -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 (file)
index 0000000..6ccdfd4
--- /dev/null
@@ -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<LPBYTE>(&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<BYTE*>(&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 (file)
index 0000000..3471797
--- /dev/null
@@ -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 (file)
index 0000000..c27e33a
--- /dev/null
@@ -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 (file)
index 0000000..0d96724
--- /dev/null
@@ -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 <sdkddkver.h>
+
+#include <cassert>
+#include <string>
+#include <memory>
+#include <vector>
+#include <algorithm>
+
+#include <windows.h>
+#include <commctrl.h>
+#include <WtsApi32.h>
+#include <tchar.h>
+#include <strsafe.h>
+#include <time.h>
+
+#include "resource.h"
+
+#include "ScreensaverNotifier.h"
+#include "Settings.h"
+#include "TrayIcon.h"
+#include "WinMute.h"
+#include "VersionHelper.h"
+
+template<class Interface>
+inline void SafeRelease(Interface** ppInterfaceToRelease)
+{
+   if (*ppInterfaceToRelease) {
+      (*ppInterfaceToRelease)->Release();
+      (*ppInterfaceToRelease) = nullptr;
+   }
+}
+
+#ifdef UNICODE
+   typedef std::basic_string<wchar_t> tstring;
+#else
+   typedef std::basic_string<char> 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 (file)
index 0000000..ac3594e
--- /dev/null
@@ -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 (file)
index 0000000..6d5ab24
--- /dev/null
@@ -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 (file)
index 0000000..79543c1
--- /dev/null
@@ -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<LPTSTR>(&lpMsgBuf), 0, nullptr) != 0) {
+
+      // Display the error message and exit the process
+      LPVOID lpDisplayBuf = reinterpret_cast<LPVOID>(LocalAlloc(LMEM_ZEROINIT,
+                            (lstrlen(static_cast<LPCTSTR>(lpMsgBuf)) +
+                             lstrlen(static_cast<LPCTSTR>(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<LPCTSTR>(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 (file)
index 0000000..38c8edb
--- /dev/null
@@ -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 (file)
index 0000000..a17f90d
--- /dev/null
@@ -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 <mmdeviceapi.h>
+
+#pragma warning(disable : 4201)
+#  include <endpointvolume.h> 
+#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<LPVOID*>(&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<LPVOID*>(&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 (file)
index 0000000..795352e
--- /dev/null
@@ -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<IUnknown*>(this);
+   } else if (riid == __uuidof(IAudioSessionEvents)) {
+      AddRef();
+      *ppvInterface = reinterpret_cast<IAudioSessionEvents*>(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 (file)
index 0000000..f6719d4
--- /dev/null
@@ -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 <audiopolicy.h>
+
+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 (file)
index 0000000..4ebe0ab
--- /dev/null
@@ -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<MixerDevice> 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 (file)
index 0000000..e3c5e9c
--- /dev/null
@@ -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);
+
+   // <Init Common Controls>
+   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;
+   }
+   // </Init Common Controls>
+
+   // <Init COM>
+   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<int>(msg.wParam);
+}
diff --git a/WinMute/WinMute.cpp b/WinMute/WinMute.cpp
new file mode 100644 (file)
index 0000000..0702495
--- /dev/null
@@ -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<WinMute*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
+   switch (msg) {
+   case WM_NCCREATE: {
+      LPCREATESTRUCTW cs = reinterpret_cast<LPCREATESTRUCTW>(lParam);
+      SetWindowLongPtr(hWnd, GWLP_USERDATA,
+                       reinterpret_cast<LONG>(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<WinAudio>(new VistaAudio);
+   } else if (IsWindowsXPOrGreater()) {
+      audio_ = std::unique_ptr<XPAudio>(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 (file)
index 0000000..476941e
--- /dev/null
@@ -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<WinAudio> 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 (file)
index 0000000..6e7b3e7
--- /dev/null
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{488617F0-5DD3-42B5-81ED-A1E9B3117551}</ProjectGuid>
+    <RootNamespace>WinMute</RootNamespace>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v120_xp</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)Bin\</OutDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)Bin\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Configuration) (x64)\</IntDir>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)Bin\</OutDir>
+    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)Bin\</OutDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\</IntDir>
+    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Configuration) (x64)\</IntDir>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(ProjectName) (x64)</TargetName>
+    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(ProjectName) (x64)</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MinimalRebuild>true</MinimalRebuild>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <OutputFile>$(SolutionDir)\Bin\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level4</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>strsafe.lib;comctl32.lib;WtsApi32.lib;Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="AboutDlg.cpp" />
+    <ClCompile Include="MMNotificationClient.cpp" />
+    <ClCompile Include="ScreensaverNotifier.cpp" />
+    <ClCompile Include="Settings.cpp" />
+    <ClCompile Include="StdAfx.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+    </ClCompile>
+    <ClCompile Include="TrayIcon.cpp" />
+    <ClCompile Include="Utility.cpp" />
+    <ClCompile Include="VistaAudio.cpp" />
+    <ClCompile Include="VistaAudioSessionEvents.cpp" />
+    <ClCompile Include="WinMain.cpp" />
+    <ClCompile Include="WinMute.cpp" />
+    <ClCompile Include="XPAudio.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="MMNotificationClient.h" />
+    <ClInclude Include="resource.h" />
+    <ClInclude Include="ScreensaverNotifier.h" />
+    <ClInclude Include="Settings.h" />
+    <ClInclude Include="StdAfx.h" />
+    <ClInclude Include="TrayIcon.h" />
+    <ClInclude Include="VersionHelper.h" />
+    <ClInclude Include="VistaAudioSessionEvents.h" />
+    <ClInclude Include="WinAudio.h" />
+    <ClInclude Include="WinMute.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.ico" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="res.rc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/WinMute/WinMute.vcxproj.filters b/WinMute/WinMute.vcxproj.filters
new file mode 100644 (file)
index 0000000..f9bb087
--- /dev/null
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+    </Filter>
+    <Filter Include="Source Files\Audio">
+      <UniqueIdentifier>{065a6082-9732-43e4-ad7b-714757809908}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\UI">
+      <UniqueIdentifier>{19d0b819-b48e-4418-917c-f92abc4c2160}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Audio\Vista Notification">
+      <UniqueIdentifier>{4ea37611-be22-4541-bfcb-ca9d271b5166}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Helper">
+      <UniqueIdentifier>{aca601be-bf13-4396-89b2-8252b3fd2703}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Settings">
+      <UniqueIdentifier>{f9c118fc-0a72-4278-a710-841604aeb3e3}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="StdAfx.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="WinMain.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="WinMute.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="VistaAudio.cpp">
+      <Filter>Source Files\Audio</Filter>
+    </ClCompile>
+    <ClCompile Include="XPAudio.cpp">
+      <Filter>Source Files\Audio</Filter>
+    </ClCompile>
+    <ClCompile Include="TrayIcon.cpp">
+      <Filter>Source Files\UI</Filter>
+    </ClCompile>
+    <ClCompile Include="AboutDlg.cpp">
+      <Filter>Source Files\UI</Filter>
+    </ClCompile>
+    <ClCompile Include="VistaAudioSessionEvents.cpp">
+      <Filter>Source Files\Audio\Vista Notification</Filter>
+    </ClCompile>
+    <ClCompile Include="MMNotificationClient.cpp">
+      <Filter>Source Files\Audio\Vista Notification</Filter>
+    </ClCompile>
+    <ClCompile Include="ScreensaverNotifier.cpp">
+      <Filter>Source Files\Helper</Filter>
+    </ClCompile>
+    <ClCompile Include="Utility.cpp">
+      <Filter>Source Files\Helper</Filter>
+    </ClCompile>
+    <ClCompile Include="Settings.cpp">
+      <Filter>Source Files\Settings</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="resource.h">
+      <Filter>Source Files\UI</Filter>
+    </ClInclude>
+    <ClInclude Include="StdAfx.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="TrayIcon.h">
+      <Filter>Source Files\UI</Filter>
+    </ClInclude>
+    <ClInclude Include="WinAudio.h">
+      <Filter>Source Files\Audio</Filter>
+    </ClInclude>
+    <ClInclude Include="WinMute.h">
+      <Filter>Source Files</Filter>
+    </ClInclude>
+    <ClInclude Include="VistaAudioSessionEvents.h">
+      <Filter>Source Files\Audio\Vista Notification</Filter>
+    </ClInclude>
+    <ClInclude Include="MMNotificationClient.h">
+      <Filter>Source Files\Audio\Vista Notification</Filter>
+    </ClInclude>
+    <ClInclude Include="ScreensaverNotifier.h">
+      <Filter>Source Files\Helper</Filter>
+    </ClInclude>
+    <ClInclude Include="VersionHelper.h">
+      <Filter>Source Files\Helper</Filter>
+    </ClInclude>
+    <ClInclude Include="Settings.h">
+      <Filter>Source Files\Settings</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.ico">
+      <Filter>Resource Files</Filter>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="res.rc">
+      <Filter>Resource Files</Filter>
+    </ResourceCompile>
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/WinMute/WinMute.vcxproj.user b/WinMute/WinMute.vcxproj.user
new file mode 100644 (file)
index 0000000..ace9a86
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
\ No newline at end of file
diff --git a/WinMute/XPAudio.cpp b/WinMute/XPAudio.cpp
new file mode 100644 (file)
index 0000000..66363f9
--- /dev/null
@@ -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 <sstream>
+#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<XPAudio*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
+   switch (msg) {
+   case WM_NCCREATE: {
+      LPCREATESTRUCTW cs = reinterpret_cast<LPCREATESTRUCTW>(lParam);
+      SetWindowLongPtr(hWnd, GWLP_USERDATA,
+                       reinterpret_cast<LONG>(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<TCHAR> 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<DWORD_PTR>(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<HMIXEROBJ>(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<HMIXEROBJ>(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<HMIXEROBJ>(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<HMIXER>(wParam) == md->hMixer) {
+               DWORD notifyID = static_cast<DWORD>(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<HMIXEROBJ>(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<HMIXEROBJ>(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<HMIXEROBJ>(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 (file)
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 (file)
index 0000000..d1d92aa
--- /dev/null
@@ -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         "<a href=""http://lx-s.de"">lx-systems - lx-s.de</a>",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 (file)
index 0000000..f0fa03c
--- /dev/null
@@ -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