Skip to content

Commit 225d0ba

Browse files
committed
1 parent afaf166 commit 225d0ba

9 files changed

+822
-0
lines changed

Src/OpenShell.sln

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ EndProject
4040
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ClassicIEDLL", "ClassicIE\ClassicIEDLL\ClassicIEDLL.vcxproj", "{BC0E6E7C-08C1-4F12-A754-4608E5A22FA8}"
4141
EndProject
4242
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Update", "Update\Update.vcxproj", "{171B46B0-6083-4D9E-BD33-946EA3BD76FA}"
43+
ProjectSection(ProjectDependencies) = postProject
44+
{D94BD2A6-1872-4F01-B911-F406603AA2E1} = {D94BD2A6-1872-4F01-B911-F406603AA2E1}
45+
EndProjectSection
4346
EndProject
4447
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Win7Aero7", "Skins\Win7Aero7\Win7Aero7.vcxproj", "{A2CCDE9F-17CE-461E-8BD9-00261B8855A6}"
4548
EndProject
@@ -63,6 +66,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Metro", "Skins\Metro\Metro.
6366
EndProject
6467
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Metallic7", "Skins\Metallic7\Metallic7.vcxproj", "{CA5BFC96-428D-42F5-9F7D-CDDE048A357C}"
6568
EndProject
69+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DesktopToasts", "Update\DesktopToasts\DesktopToasts.vcxproj", "{D94BD2A6-1872-4F01-B911-F406603AA2E1}"
70+
EndProject
6671
Global
6772
GlobalSection(SolutionConfigurationPlatforms) = preSolution
6873
Debug|Win32 = Debug|Win32
@@ -374,6 +379,15 @@ Global
374379
{CA5BFC96-428D-42F5-9F7D-CDDE048A357C}.Setup|Win32.ActiveCfg = Resource|Win32
375380
{CA5BFC96-428D-42F5-9F7D-CDDE048A357C}.Setup|Win32.Build.0 = Resource|Win32
376381
{CA5BFC96-428D-42F5-9F7D-CDDE048A357C}.Setup|x64.ActiveCfg = Resource|Win32
382+
{D94BD2A6-1872-4F01-B911-F406603AA2E1}.Debug|Win32.ActiveCfg = Debug|Win32
383+
{D94BD2A6-1872-4F01-B911-F406603AA2E1}.Debug|Win32.Build.0 = Debug|Win32
384+
{D94BD2A6-1872-4F01-B911-F406603AA2E1}.Debug|x64.ActiveCfg = Debug|Win32
385+
{D94BD2A6-1872-4F01-B911-F406603AA2E1}.Release|Win32.ActiveCfg = Release|Win32
386+
{D94BD2A6-1872-4F01-B911-F406603AA2E1}.Release|Win32.Build.0 = Release|Win32
387+
{D94BD2A6-1872-4F01-B911-F406603AA2E1}.Release|x64.ActiveCfg = Release|Win32
388+
{D94BD2A6-1872-4F01-B911-F406603AA2E1}.Setup|Win32.ActiveCfg = Release|Win32
389+
{D94BD2A6-1872-4F01-B911-F406603AA2E1}.Setup|Win32.Build.0 = Release|Win32
390+
{D94BD2A6-1872-4F01-B911-F406603AA2E1}.Setup|x64.ActiveCfg = Release|Win32
377391
EndGlobalSection
378392
GlobalSection(SolutionProperties) = preSolution
379393
HideSolutionNode = FALSE
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
// ******************************************************************
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// This code is licensed under the MIT License (MIT).
4+
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
5+
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
7+
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
8+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
9+
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
10+
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
11+
// ******************************************************************
12+
13+
#include "DesktopNotificationManagerCompat.h"
14+
#include <appmodel.h>
15+
#include <wrl\wrappers\corewrappers.h>
16+
17+
#define RETURN_IF_FAILED(hr) do { HRESULT _hrTemp = hr; if (FAILED(_hrTemp)) { return _hrTemp; } } while (false)
18+
19+
using namespace ABI::Windows::Data::Xml::Dom;
20+
using namespace Microsoft::WRL;
21+
using namespace Microsoft::WRL::Wrappers;
22+
23+
namespace DesktopNotificationManagerCompat
24+
{
25+
HRESULT RegisterComServer(GUID clsid, const wchar_t exePath[]);
26+
HRESULT EnsureRegistered();
27+
bool IsRunningAsUwp();
28+
29+
bool s_registeredAumidAndComServer = false;
30+
std::wstring s_aumid;
31+
bool s_registeredActivator = false;
32+
bool s_hasCheckedIsRunningAsUwp = false;
33+
bool s_isRunningAsUwp = false;
34+
35+
HRESULT RegisterAumidAndComServer(const wchar_t *aumid, GUID clsid)
36+
{
37+
/*
38+
// If running as Desktop Bridge
39+
if (IsRunningAsUwp())
40+
{
41+
// Clear the AUMID since Desktop Bridge doesn't use it, and then we're done.
42+
// Desktop Bridge apps are registered with platform through their manifest.
43+
// Their LocalServer32 key is also registered through their manifest.
44+
s_aumid = L"";
45+
s_registeredAumidAndComServer = true;
46+
return S_OK;
47+
}
48+
*/
49+
// Copy the aumid
50+
s_aumid = std::wstring(aumid);
51+
/*
52+
// Get the EXE path
53+
wchar_t exePath[MAX_PATH];
54+
DWORD charWritten = ::GetModuleFileName(nullptr, exePath, ARRAYSIZE(exePath));
55+
RETURN_IF_FAILED(charWritten > 0 ? S_OK : HRESULT_FROM_WIN32(::GetLastError()));
56+
57+
// Register the COM server
58+
RETURN_IF_FAILED(RegisterComServer(clsid, exePath));
59+
*/
60+
s_registeredAumidAndComServer = true;
61+
return S_OK;
62+
}
63+
64+
HRESULT RegisterActivator()
65+
{
66+
// Module<OutOfProc> needs a callback registered before it can be used.
67+
// Since we don't care about when it shuts down, we'll pass an empty lambda here.
68+
Module<OutOfProc>::Create([] {});
69+
70+
// If a local server process only hosts the COM object then COM expects
71+
// the COM server host to shutdown when the references drop to zero.
72+
// Since the user might still be using the program after activating the notification,
73+
// we don't want to shutdown immediately. Incrementing the object count tells COM that
74+
// we aren't done yet.
75+
Module<OutOfProc>::GetModule().IncrementObjectCount();
76+
77+
RETURN_IF_FAILED(Module<OutOfProc>::GetModule().RegisterObjects());
78+
79+
s_registeredActivator = true;
80+
return S_OK;
81+
}
82+
83+
HRESULT RegisterComServer(GUID clsid, const wchar_t exePath[])
84+
{
85+
// Turn the GUID into a string
86+
OLECHAR* clsidOlechar;
87+
StringFromCLSID(clsid, &clsidOlechar);
88+
std::wstring clsidStr(clsidOlechar);
89+
::CoTaskMemFree(clsidOlechar);
90+
91+
// Create the subkey
92+
// Something like SOFTWARE\Classes\CLSID\{23A5B06E-20BB-4E7E-A0AC-6982ED6A6041}\LocalServer32
93+
std::wstring subKey = LR"(SOFTWARE\Classes\CLSID\)" + clsidStr + LR"(\LocalServer32)";
94+
95+
// Include -ToastActivated launch args on the exe
96+
std::wstring exePathStr(exePath);
97+
exePathStr = L"\"" + exePathStr + L"\" " + TOAST_ACTIVATED_LAUNCH_ARG;
98+
99+
// We don't need to worry about overflow here as ::GetModuleFileName won't
100+
// return anything bigger than the max file system path (much fewer than max of DWORD).
101+
DWORD dataSize = static_cast<DWORD>((exePathStr.length() + 1) * sizeof(WCHAR));
102+
103+
// Register the EXE for the COM server
104+
return HRESULT_FROM_WIN32(::RegSetKeyValue(
105+
HKEY_CURRENT_USER,
106+
subKey.c_str(),
107+
nullptr,
108+
REG_SZ,
109+
reinterpret_cast<const BYTE*>(exePathStr.c_str()),
110+
dataSize));
111+
}
112+
113+
HRESULT CreateToastNotifier(IToastNotifier **notifier)
114+
{
115+
RETURN_IF_FAILED(EnsureRegistered());
116+
117+
ComPtr<IToastNotificationManagerStatics> toastStatics;
118+
RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory(
119+
HStringReference(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(),
120+
&toastStatics));
121+
122+
if (s_aumid.empty())
123+
{
124+
return toastStatics->CreateToastNotifier(notifier);
125+
}
126+
else
127+
{
128+
return toastStatics->CreateToastNotifierWithId(HStringReference(s_aumid.c_str()).Get(), notifier);
129+
}
130+
}
131+
132+
HRESULT CreateXmlDocumentFromString(const wchar_t *xmlString, IXmlDocument **doc)
133+
{
134+
ComPtr<IXmlDocument> answer;
135+
RETURN_IF_FAILED(Windows::Foundation::ActivateInstance(HStringReference(RuntimeClass_Windows_Data_Xml_Dom_XmlDocument).Get(), &answer));
136+
137+
ComPtr<IXmlDocumentIO> docIO;
138+
RETURN_IF_FAILED(answer.As(&docIO));
139+
140+
// Load the XML string
141+
RETURN_IF_FAILED(docIO->LoadXml(HStringReference(xmlString).Get()));
142+
143+
return answer.CopyTo(doc);
144+
}
145+
146+
HRESULT CreateToastNotification(IXmlDocument *content, IToastNotification **notification)
147+
{
148+
ComPtr<IToastNotificationFactory> factory;
149+
RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory(
150+
HStringReference(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(),
151+
&factory));
152+
153+
return factory->CreateToastNotification(content, notification);
154+
}
155+
156+
HRESULT get_History(std::unique_ptr<DesktopNotificationHistoryCompat>* history)
157+
{
158+
RETURN_IF_FAILED(EnsureRegistered());
159+
160+
ComPtr<IToastNotificationManagerStatics> toastStatics;
161+
RETURN_IF_FAILED(Windows::Foundation::GetActivationFactory(
162+
HStringReference(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(),
163+
&toastStatics));
164+
165+
ComPtr<IToastNotificationManagerStatics2> toastStatics2;
166+
RETURN_IF_FAILED(toastStatics.As(&toastStatics2));
167+
168+
ComPtr<IToastNotificationHistory> nativeHistory;
169+
RETURN_IF_FAILED(toastStatics2->get_History(&nativeHistory));
170+
171+
*history = std::unique_ptr<DesktopNotificationHistoryCompat>(new DesktopNotificationHistoryCompat(s_aumid.c_str(), nativeHistory));
172+
return S_OK;
173+
}
174+
175+
bool CanUseHttpImages()
176+
{
177+
return IsRunningAsUwp();
178+
}
179+
180+
HRESULT EnsureRegistered()
181+
{
182+
// If not registered AUMID yet
183+
if (!s_registeredAumidAndComServer)
184+
{
185+
// Check if Desktop Bridge
186+
if (IsRunningAsUwp())
187+
{
188+
// Implicitly registered, all good!
189+
s_registeredAumidAndComServer = true;
190+
}
191+
else
192+
{
193+
// Otherwise, incorrect usage, must call RegisterAumidAndComServer first
194+
return E_ILLEGAL_METHOD_CALL;
195+
}
196+
}
197+
198+
// If not registered activator yet
199+
if (!s_registeredActivator)
200+
{
201+
// Incorrect usage, must call RegisterActivator first
202+
return E_ILLEGAL_METHOD_CALL;
203+
}
204+
205+
return S_OK;
206+
}
207+
208+
bool IsRunningAsUwp()
209+
{
210+
if (!s_hasCheckedIsRunningAsUwp)
211+
{
212+
// https://stackoverflow.com/questions/39609643/determine-if-c-application-is-running-as-a-uwp-app-in-desktop-bridge-project
213+
UINT32 length;
214+
wchar_t packageFamilyName[PACKAGE_FAMILY_NAME_MAX_LENGTH + 1];
215+
LONG result = GetPackageFamilyName(GetCurrentProcess(), &length, packageFamilyName);
216+
s_isRunningAsUwp = result == ERROR_SUCCESS;
217+
s_hasCheckedIsRunningAsUwp = true;
218+
}
219+
220+
return s_isRunningAsUwp;
221+
}
222+
}
223+
224+
DesktopNotificationHistoryCompat::DesktopNotificationHistoryCompat(const wchar_t *aumid, ComPtr<IToastNotificationHistory> history)
225+
{
226+
m_aumid = std::wstring(aumid);
227+
m_history = history;
228+
}
229+
230+
HRESULT DesktopNotificationHistoryCompat::Clear()
231+
{
232+
if (m_aumid.empty())
233+
{
234+
return m_history->Clear();
235+
}
236+
else
237+
{
238+
return m_history->ClearWithId(HStringReference(m_aumid.c_str()).Get());
239+
}
240+
}
241+
242+
HRESULT DesktopNotificationHistoryCompat::GetHistory(ABI::Windows::Foundation::Collections::IVectorView<ToastNotification*> **toasts)
243+
{
244+
ComPtr<IToastNotificationHistory2> history2;
245+
RETURN_IF_FAILED(m_history.As(&history2));
246+
247+
if (m_aumid.empty())
248+
{
249+
return history2->GetHistory(toasts);
250+
}
251+
else
252+
{
253+
return history2->GetHistoryWithId(HStringReference(m_aumid.c_str()).Get(), toasts);
254+
}
255+
}
256+
257+
HRESULT DesktopNotificationHistoryCompat::Remove(const wchar_t *tag)
258+
{
259+
if (m_aumid.empty())
260+
{
261+
return m_history->Remove(HStringReference(tag).Get());
262+
}
263+
else
264+
{
265+
return m_history->RemoveGroupedTagWithId(HStringReference(tag).Get(), HStringReference(L"").Get(), HStringReference(m_aumid.c_str()).Get());
266+
}
267+
}
268+
269+
HRESULT DesktopNotificationHistoryCompat::RemoveGroupedTag(const wchar_t *tag, const wchar_t *group)
270+
{
271+
if (m_aumid.empty())
272+
{
273+
return m_history->RemoveGroupedTag(HStringReference(tag).Get(), HStringReference(group).Get());
274+
}
275+
else
276+
{
277+
return m_history->RemoveGroupedTagWithId(HStringReference(tag).Get(), HStringReference(group).Get(), HStringReference(m_aumid.c_str()).Get());
278+
}
279+
}
280+
281+
HRESULT DesktopNotificationHistoryCompat::RemoveGroup(const wchar_t *group)
282+
{
283+
if (m_aumid.empty())
284+
{
285+
return m_history->RemoveGroup(HStringReference(group).Get());
286+
}
287+
else
288+
{
289+
return m_history->RemoveGroupWithId(HStringReference(group).Get(), HStringReference(m_aumid.c_str()).Get());
290+
}
291+
}

0 commit comments

Comments
 (0)