Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions AudioPlaybackConnector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ winrt::fire_and_forget ConnectDevice(DevicePicker, std::wstring_view);
void SetupDevicePicker();
void SetupSvgIcon();
void UpdateNotifyIcon();
void ShowInitialToastNotification();

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
Expand All @@ -20,6 +21,31 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,

g_hInst = hInstance;

g_hMutex = CreateMutexW(NULL, TRUE, UNIQUE_MUTEX_NAME);
if (g_hMutex == NULL)
{
TaskDialog(nullptr, nullptr, _(L"Error"), nullptr, _(L"Could not create mutex. Application will exit."), TDCBF_OK_BUTTON, TD_ERROR_ICON, nullptr);
return EXIT_FAILURE;
}

if (GetLastError() == ERROR_ALREADY_EXISTS)
{
CloseHandle(g_hMutex);
g_hMutex = NULL;

HWND hExistingWnd = FindWindowW(L"AudioPlaybackConnector", nullptr);
if (hExistingWnd)
{
SetForegroundWindow(hExistingWnd);
PostMessageW(hExistingWnd, WM_SHOW_DEVICEPICKER_FROM_OTHER_INSTANCE, 0, 0);
}
else
{
TaskDialog(nullptr, nullptr, _(L"Information"), nullptr, _(L"Another instance is running, but its window could not be found."), TDCBF_OK_BUTTON, TD_WARNING_ICON, nullptr);
}
return EXIT_SUCCESS;
}

winrt::init_apartment();

bool supported = false;
Expand Down Expand Up @@ -81,6 +107,8 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,

PostMessageW(g_hWnd, WM_CONNECTDEVICE, 0, 0);

ShowInitialToastNotification();

MSG msg;
while (GetMessageW(&msg, nullptr, 0, 0))
{
Expand Down Expand Up @@ -117,8 +145,49 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
SaveSettings();
}
Shell_NotifyIconW(NIM_DELETE, &g_nid);

if (g_hMutex)
{
ReleaseMutex(g_hMutex);
CloseHandle(g_hMutex);
g_hMutex = NULL;
}

PostQuitMessage(0);
break;
case WM_SHOW_DEVICEPICKER_FROM_OTHER_INSTANCE:
{
using namespace winrt::Windows::UI::Popups;
RECT iconRect;
HRESULT hr = Shell_NotifyIconGetRect(&g_niid, &iconRect);
if (FAILED(hr))
{
LOG_HR(hr);
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&iconRect.left));
ClientToScreen(hWnd, reinterpret_cast<POINT*>(&iconRect.right));
}

auto dpi = GetDpiForWindow(hWnd);
Rect rect = {
static_cast<float>(iconRect.left * USER_DEFAULT_SCREEN_DPI / dpi),
static_cast<float>(iconRect.top * USER_DEFAULT_SCREEN_DPI / dpi),
static_cast<float>((iconRect.right - iconRect.left) * USER_DEFAULT_SCREEN_DPI / dpi),
static_cast<float>((iconRect.bottom - iconRect.top) * USER_DEFAULT_SCREEN_DPI / dpi)
};
if (IsRectEmpty(&iconRect) || FAILED(hr)) {
rect = { 100.0f, 100.0f, 300.0f, 400.0f };
}

SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_HIDEWINDOW);
ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);

if (g_devicePicker)
{
g_devicePicker.Show(rect, Placement::Above);
}
}
break;
case WM_SETTINGCHANGE:
if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, TRUE) == CSTR_EQUAL)
{
Expand Down Expand Up @@ -449,3 +518,61 @@ void UpdateNotifyIcon()
}
}
}

void ShowInitialToastNotification()
{
try
{
std::wstring title = _(L"AudioPlaybackConnector");
std::wstring message = _(L"Application has started and is running in the notification area.");

std::wstring toastXmlString =
L"<toast activationType=\"protocol\" launch=\"audioplaybackconnector:show\">"
L"<visual>"
L"<binding template=\"ToastGeneric\">"
L"<text>" + title + L"</text>"
L"<text>" + message + L"</text>"
L"</binding>"
L"</visual>"
L"</toast>";

XmlDocument toastXml;
toastXml.LoadXml(toastXmlString);

ToastNotifier notifier{ nullptr };
try {
notifier = ToastNotificationManager::CreateToastNotifier();
}
catch (winrt::hresult_error) {
LOG_CAUGHT_EXCEPTION();
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
std::wstring appId = exePath;
try {
notifier = ToastNotificationManager::CreateToastNotifier(appId);
}
catch (winrt::hresult_error) {
LOG_CAUGHT_EXCEPTION();
}
}

if (!notifier)
{
return;
}

ToastNotification toast(toastXml);

using namespace std::chrono;
toast.ExpirationTime(winrt::Windows::Foundation::DateTime::clock::now() + seconds(5));

notifier.Show(toast);
}
catch (winrt::hresult_error)
{

}
catch (std::exception)
{
}
}
8 changes: 7 additions & 1 deletion AudioPlaybackConnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ using namespace winrt::Windows::Media::Audio;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Controls;
using namespace winrt::Windows::UI::Xaml::Hosting;
using namespace winrt::Windows::UI::Notifications;
using namespace winrt::Windows::Data::Xml::Dom;
namespace fs = std::filesystem;

constexpr UINT WM_NOTIFYICON = WM_APP + 1;
constexpr UINT WM_CONNECTDEVICE = WM_APP + 2;
constexpr UINT WM_SHOW_DEVICEPICKER_FROM_OTHER_INSTANCE = WM_APP + 3;

const WCHAR UNIQUE_MUTEX_NAME[] = L"{019730ef-fcc8-7f5a-94b3-8b77d764a65f}";

HANDLE g_hMutex = nullptr;
HINSTANCE g_hInst;
HWND g_hWnd;
HWND g_hWndXaml;
Expand Down Expand Up @@ -41,4 +47,4 @@ std::vector<std::wstring> g_lastDevices;
#include "Util.hpp"
#include "I18n.hpp"
#include "SettingsUtil.hpp"
#include "Direct2DSvg.hpp"
#include "Direct2DSvg.hpp"
18 changes: 9 additions & 9 deletions AudioPlaybackConnector.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,58 +40,58 @@
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{2daaabdd-2402-4023-bc3e-b6e93fad567b}</ProjectGuid>
<RootNamespace>AudioPlaybackConnector</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
Expand Down
2 changes: 2 additions & 0 deletions pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,7 @@
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#include <winrt/Windows.UI.Xaml.Markup.h>
#include <winrt/Windows.UI.Notifications.h>
#include <winrt/Windows.Data.Xml.Dom.h>

#endif //PCH_H