他人の空似自作物置場

volume_manager.zip/volume_manager.h

#pragma once

#include <boost/range/irange.hpp>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>

#include <Windows.h>
#include <MMDeviceAPI.h>
#include <Audiopolicy.h>
#include <psapi.h>

#pragma comment(lib, "psapi.lib")

#pragma comment (lib, "volume_manager.lib")

class ComBase {
private:
   static unsigned int counter;
   static bool initialized;
protected:
   class ReleaseCom {
   public:
      void operator()(IUnknown * const ptr) {
         ptr->Release();
      }
   };
   static HRESULT CoCreateInstance(REFCLSID rclsid, REFIID riid, LPVOID FAR* ppv) {
      if (!initialized) {
         ::CoInitialize(nullptr);
         initialized = true;
      }
      return ::CoCreateInstance(rclsid, nullptr, CLSCTX_INPROC_SERVER, riid, ppv);
   }
public:
   ComBase() {
      counter++;
   }
   ~ComBase() {
      counter--;
      if (counter == 0) {
         ::CoUninitialize();
      }
   }
};

template<typename ComInterface>
class Com : public ComBase {
protected:
   std::unique_ptr<ComInterface, ReleaseCom> ptr;
public:
   Com(ComInterface * const raw) {
      ptr = std::unique_ptr<ComInterface, ReleaseCom>(raw);
   }
   ComInterface *operator->() {
      return ptr.get();
   }
};

template<typename ComInterface, typename UUIDOFType = ComInterface>
class ComCCI : public Com<ComInterface> {
private:
   static ComInterface *create() {
      ComInterface *raw;
      const HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), IID_PPV_ARGS(&raw));
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return raw;
   }
public:
   ComCCI() : Com<ComInterface>(create()) {
   }
};

class SimpleAudioVolume : public Com<ISimpleAudioVolume> {
public:
   SimpleAudioVolume(ISimpleAudioVolume * const raw) : Com<ISimpleAudioVolume>(raw) {
   }
   void Set(const float value) {
      const HRESULT hr = ptr->SetMasterVolume(value, nullptr);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
   }
   float Get() {
      float result;
      const HRESULT hr = ptr->GetMasterVolume(&result);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return result;
   }
};

class AudioSessionControl : public Com<IAudioSessionControl2> {
private:
   class HandleCloser {
   public:
      void operator()(void *ptr) {
         ::CloseHandle(reinterpret_cast<HANDLE>(ptr));
      }
   };
public:
   AudioSessionControl(IAudioSessionControl2 * const raw) : Com<IAudioSessionControl2>(raw) {
   }
   DWORD GetProcessId() {
      DWORD result;
      const HRESULT hr = ptr->GetProcessId(&result);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return result;
   }
   boost::filesystem::path GetProcessImageFilePath() {
      const DWORD processId = GetProcessId();
      const HANDLE processHandleRaw = ::OpenProcess(PROCESS_QUERY_INFORMATION, false, processId);
      std::unique_ptr<void, HandleCloser> processHandle(processHandleRaw);
      wchar_t path[MAX_PATH];
      ::GetProcessImageFileNameW(processHandle.get(), path, _countof(path));
      return path;
   }
   std::wstring GetDisplayName() {
      wchar_t *result;
      const HRESULT hr = ptr->GetDisplayName(&result);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return result;
   }
   SimpleAudioVolume GetVolumeInstance() {
      ISimpleAudioVolume *result;
      const HRESULT hr = ptr->QueryInterface(&result);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return SimpleAudioVolume(result);
   }
   void SetVolume(const float value) {
      GetVolumeInstance().Set(value);
   }
   float GetVolume() {
      return GetVolumeInstance().Get();
   }
};

class AudioSessionControlOld : public Com<IAudioSessionControl> {
public:
   AudioSessionControlOld(IAudioSessionControl * const raw) : Com<IAudioSessionControl>(raw) {
   }
   AudioSessionControl Convert() {
      IAudioSessionControl2 *result;
      const HRESULT hr = ptr->QueryInterface(&result);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return AudioSessionControl(result);
   }
};

class AudioSessionEnumerator : public Com<IAudioSessionEnumerator> {
private:
   unsigned int count;
   unsigned int GetCountRaw() {
      int result;
      const HRESULT hr = ptr->GetCount(&result);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return static_cast<unsigned int>(result);
   }
   class Iterator {
   private:
      AudioSessionEnumerator &ptr;
      unsigned int index;
   public:
      Iterator(AudioSessionEnumerator &ptr, const unsigned int index) : ptr(ptr), index(index) {
      }
      AudioSessionControl operator*() {
         return ptr.GetSession(index);
      }
      void operator++() {
         index++;
      }
      bool operator!=(const Iterator &other) const {
         return index != other.index;
      }
      bool operator==(const Iterator &other) const {
         return index == other.index;
      }
   };
public:
   AudioSessionEnumerator(IAudioSessionEnumerator * const raw) : Com<IAudioSessionEnumerator>(raw) {
      count = GetCountRaw();
   }
   AudioSessionControl GetSession(const unsigned int index) {
      IAudioSessionControl *result;
      const HRESULT hr = ptr->GetSession(index, &result);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return AudioSessionControlOld(result).Convert();
   }
   unsigned int GetCount() const {
      return count;
   }
   Iterator begin() {
      return Iterator(*this, 0);
   }
   Iterator end() {
      return Iterator(*this, GetCount());
   }
};

class AudioSessionManager : public Com<IAudioSessionManager2> {
public:
   AudioSessionManager(IAudioSessionManager2 * const raw) : Com<IAudioSessionManager2>(raw) {
   }
   AudioSessionEnumerator GetSessionEnumerator() {
      IAudioSessionEnumerator *result;
      const HRESULT hr = ptr->GetSessionEnumerator(&result);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return AudioSessionEnumerator(result);
   }
};

class MMDevice : public Com<IMMDevice> {
public:
   MMDevice(IMMDevice * const raw) : Com<IMMDevice>(raw) {
   }
   AudioSessionManager ActivateSessionManager() {
      IAudioSessionManager2 *result;
      const HRESULT hr = ptr->Activate(__uuidof(IAudioSessionManager2), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<void **>(&result));
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return AudioSessionManager(result);
   }
};

class MMDeviceEnumerator : public ComCCI<IMMDeviceEnumerator, MMDeviceEnumerator> {
public:
   MMDevice GetDefaultAudioEndpoint(EDataFlow flow, ERole role) {
      IMMDevice *result;
      const HRESULT hr = ptr->GetDefaultAudioEndpoint(flow, role, &result);
      if (FAILED(hr)) {
         ::ExitProcess(1);
      }
      return MMDevice(result);
   }
};