450 lines
11 KiB
C++
450 lines
11 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
|
|
#include "StdAfx.h"
|
|
#include "AlarmClient.h"
|
|
#include "AlarmContent.h"
|
|
|
|
//
|
|
// This APPLICATION_ID is the unique ID for this
|
|
// Windows SideShow application. It is a GUID.
|
|
//
|
|
|
|
// {0F11B914-F461-4785-877C-482AB481CF7A}
|
|
static const GUID ALARM_CLIENT_APPLICATION_ID =
|
|
{ 0xf11b914, 0xf461, 0x4785, { 0x87, 0x7c, 0x48, 0x2a, 0xb4, 0x81, 0xcf, 0x7a } };
|
|
|
|
|
|
CAlarmClient::CAlarmClient() :
|
|
m_pSession(NULL),
|
|
m_pContentMgr(NULL),
|
|
m_pContent(NULL),
|
|
m_pNotificationMgr(NULL),
|
|
m_pNotification(NULL),
|
|
m_pAlarms(NULL),
|
|
m_lastNotificationId(0)
|
|
{
|
|
m_pAlarms = new Alarm();
|
|
}
|
|
|
|
CAlarmClient::~CAlarmClient()
|
|
{
|
|
//
|
|
// Release the memory used for all of the alarms
|
|
//
|
|
while (NULL != m_pAlarms)
|
|
{
|
|
Alarm* tmp = m_pAlarms->m_pNext;
|
|
delete m_pAlarms;
|
|
m_pAlarms = tmp;
|
|
}
|
|
}
|
|
|
|
void CAlarmClient::SetAlarm(SYSTEMTIME* pAlarmTime)
|
|
{
|
|
if (NULL != pAlarmTime)
|
|
{
|
|
Alarm* pLastAlarm = m_pAlarms;
|
|
|
|
//
|
|
// Find the last Alarm in the list
|
|
//
|
|
while (pLastAlarm->m_pNext != NULL)
|
|
{
|
|
pLastAlarm = pLastAlarm->m_pNext;
|
|
}
|
|
|
|
//
|
|
// Increment the last-used NOTIFICATION_ID so
|
|
// we have a new one to assign to this alarm
|
|
//
|
|
m_lastNotificationId++;
|
|
|
|
//
|
|
// Initialize the Alarm struct; this is empty
|
|
// because the last item in the list is always
|
|
// an empty structure.
|
|
//
|
|
pLastAlarm->m_bSet = TRUE;
|
|
pLastAlarm->m_time = *pAlarmTime;
|
|
pLastAlarm->m_notificationId= m_lastNotificationId;
|
|
pLastAlarm->m_pClient = this;
|
|
|
|
pLastAlarm->m_pNext = new Alarm();
|
|
|
|
//
|
|
// Start a thread that will fire the alarm when it's time
|
|
//
|
|
StartAlarmThread(pLastAlarm);
|
|
|
|
::MessageBox(NULL, L"You have set the alarm.", L"Alarm Set", MB_OK);
|
|
}
|
|
}
|
|
|
|
void CAlarmClient::ShowNotification(Alarm* pAlarm)
|
|
{
|
|
if (NULL != m_pNotification)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR wszMsg[32];
|
|
SYSTEMTIME expTime;
|
|
|
|
//
|
|
// Set the NotificationId property
|
|
//
|
|
hr = m_pNotification->put_NotificationId(pAlarm->m_notificationId);
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// handle failure case
|
|
//
|
|
}
|
|
|
|
//
|
|
// Set the Title property
|
|
//
|
|
hr = m_pNotification->put_Title(L"Alarm!!!");
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// handle failure case
|
|
//
|
|
}
|
|
|
|
//
|
|
// Set the Message property
|
|
// Use the safe string functions so the buffer doesn't
|
|
// get overrun.
|
|
//
|
|
hr = StringCchPrintf(wszMsg,
|
|
ARRAYSIZE(wszMsg),
|
|
L"Alarm %d set for %02d:%02d",
|
|
pAlarm->m_notificationId,
|
|
pAlarm->m_time.wHour,
|
|
pAlarm->m_time.wMinute);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = m_pNotification->put_Message(wszMsg);
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// handle failure case
|
|
//
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If StringCchPrintf failed above, just use a default message for
|
|
// the alarm so that it doesn't appear blank.
|
|
//
|
|
hr = m_pNotification->put_Message(L"The Alarm just went off!");
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// handle failure case
|
|
//
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the Notification to expire after 90 days
|
|
//
|
|
::GetLocalTime(&expTime);
|
|
|
|
FILETIME ft = { 0 };
|
|
SystemTimeToFileTime(&expTime, &ft);
|
|
|
|
ULARGE_INTEGER u = { 0 };
|
|
memcpy(&u, &ft, sizeof(u));
|
|
u.QuadPart += 90 * 24 * 60 * 60 * 10000000LLU; // 90 days
|
|
memcpy(&ft, &u, sizeof(ft));
|
|
|
|
FileTimeToSystemTime(&ft, &expTime);
|
|
|
|
hr = m_pNotification->put_ExpirationTime(&expTime);
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// handle failure case
|
|
//
|
|
}
|
|
|
|
//
|
|
// Show the notification on the device, and
|
|
// revoke it when the user dismisses the alarm
|
|
//
|
|
if (NULL != m_pNotificationMgr)
|
|
{
|
|
m_pNotificationMgr->Show(m_pNotification);
|
|
|
|
::MessageBox(NULL, wszMsg, L"Alarm went off!", MB_OK);
|
|
|
|
m_pNotificationMgr->Revoke(pAlarm->m_notificationId);
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD WINAPI CAlarmClient::TimeMonitor(LPVOID lpParam)
|
|
{
|
|
Alarm* pAlarm = (Alarm*)lpParam;
|
|
|
|
if (NULL == pAlarm)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
SYSTEMTIME sysTime;
|
|
FILETIME ftNow;
|
|
FILETIME ftAlarm;
|
|
bool fNotificationShown = false;
|
|
|
|
::SystemTimeToFileTime(&(pAlarm->m_time), &ftAlarm);
|
|
|
|
while (!fNotificationShown)
|
|
{
|
|
//
|
|
// Get the local system time
|
|
//
|
|
::GetLocalTime(&sysTime);
|
|
::SystemTimeToFileTime(&sysTime, &ftNow);
|
|
|
|
//
|
|
// Compare the times; if it is currently past the
|
|
// time for the Alarm to fire, then show it.
|
|
//
|
|
if (::CompareFileTime(&ftNow, &ftAlarm) >= 0)
|
|
{
|
|
pAlarm->m_pClient->ShowNotification(pAlarm);
|
|
fNotificationShown = true;
|
|
}
|
|
else
|
|
{
|
|
Sleep(1000);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CAlarmClient::StartAlarmThread(Alarm* pAlarm)
|
|
{
|
|
HANDLE hThread = ::CreateThread(NULL,
|
|
0,
|
|
this->TimeMonitor,
|
|
pAlarm,
|
|
0,
|
|
NULL);
|
|
|
|
if (NULL == hThread)
|
|
{
|
|
//
|
|
// Failed to start alarm thread
|
|
//
|
|
}
|
|
|
|
}
|
|
|
|
void CAlarmClient::CreateNotification()
|
|
{
|
|
if (NULL != m_pSession &&
|
|
NULL == m_pNotificationMgr)
|
|
{
|
|
HRESULT hr = ::CoCreateInstance(CLSID_SideShowNotification,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_PPV_ARGS(&m_pNotification));
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// Failed to CoCreate SideShowNotification
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Register with the platform so that we can provide Notifications
|
|
// to the devices
|
|
//
|
|
hr = m_pSession->RegisterNotifications(ALARM_CLIENT_APPLICATION_ID,
|
|
&m_pNotificationMgr);
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
//
|
|
// Successfully registered notifications with Windows SideShow platform.
|
|
//
|
|
}
|
|
else if (S_FALSE == hr)
|
|
{
|
|
//
|
|
// Successfully registered notifications with Windows SideShow platform,
|
|
// but no devices available or enabled.
|
|
//
|
|
}
|
|
else if (E_INVALIDARG == hr)
|
|
{
|
|
//
|
|
// ISideShowSession::RegisterNotifications failed with Invalid Argument.
|
|
// Registry data is missing.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// ISideShowSession::RegisterNotifications failed.
|
|
//
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CAlarmClient::Register()
|
|
{
|
|
//
|
|
// Create the SideShowSession object that
|
|
// enables us to talk to the platform.
|
|
//
|
|
HRESULT hr = S_OK;
|
|
|
|
if (NULL == m_pSession &&
|
|
NULL == m_pContentMgr)
|
|
{
|
|
hr = ::CoCreateInstance(CLSID_SideShowSession,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_PPV_ARGS(&m_pSession));
|
|
if (FAILED(hr))
|
|
{
|
|
//
|
|
// Failed to CoCreate SideShowSession.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Register this client application with the platform
|
|
// so that it can send content to devices
|
|
//
|
|
hr = m_pSession->RegisterContent(ALARM_CLIENT_APPLICATION_ID,
|
|
SIDESHOW_ENDPOINT_SIMPLE_CONTENT_FORMAT,
|
|
&m_pContentMgr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Successfully registered with Windows SideShow platform,
|
|
// now go register for Notifications
|
|
//
|
|
CreateNotification();
|
|
}
|
|
else if (E_INVALIDARG == hr)
|
|
{
|
|
//
|
|
// ISideShowSession::RegisterContent failed with Invalid Argument:
|
|
// Have you added the proper information to the registry for this application?
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// ISideShowSession::RegisterContent failed
|
|
//
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This instance has already registered with the Windows SideShow platform
|
|
//
|
|
}
|
|
}
|
|
|
|
void CAlarmClient::Unregister()
|
|
{
|
|
if (NULL != m_pNotification)
|
|
{
|
|
m_pNotification->Release();
|
|
m_pNotification = NULL;
|
|
}
|
|
|
|
if (NULL != m_pNotificationMgr)
|
|
{
|
|
m_pNotificationMgr->Release();
|
|
m_pNotificationMgr = NULL;
|
|
}
|
|
|
|
if (NULL != m_pContent)
|
|
{
|
|
m_pContent->Release();
|
|
m_pContent = NULL;
|
|
}
|
|
|
|
if (NULL != m_pContentMgr)
|
|
{
|
|
m_pContentMgr->Release();
|
|
m_pContentMgr = NULL;
|
|
}
|
|
|
|
if (NULL != m_pSession)
|
|
{
|
|
m_pSession->Release();
|
|
m_pSession = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void CAlarmClient::AddContent()
|
|
{
|
|
if (NULL != m_pContentMgr)
|
|
{
|
|
//
|
|
// Create an instance of the content object if it doesn't exist
|
|
//
|
|
if (NULL == m_pContent)
|
|
{
|
|
m_pContent = new CAlarmContent();
|
|
}
|
|
|
|
HRESULT hr = m_pContentMgr->Add(m_pContent);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Successfully added content
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Failed to add content
|
|
//
|
|
}
|
|
}
|
|
}
|
|
|
|
void CAlarmClient::RemoveAllContent()
|
|
{
|
|
if (NULL != m_pContentMgr)
|
|
{
|
|
HRESULT hr = m_pContentMgr->RemoveAll();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Removed all content.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Failed to remove content.
|
|
//
|
|
}
|
|
}
|
|
}
|