Files
AppInstallerForWin8/ToastNotification/ToastNotification.cpp
2025-02-19 21:09:40 +08:00

226 lines
6.4 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "stdafx.h"
#include "ToastNotification.h"
bool SaveIStreamToTempFile (IStream* stream, wchar_t* tempFilePath, size_t pathLen)
{
wchar_t tempPath [MAX_PATH];
if (!GetTempPathW (MAX_PATH, tempPath)) return false;
if (!GetTempFileNameW (tempPath, L"TST", 0, tempFilePath)) return false;
std::ofstream outFile (tempFilePath, std::ios::binary);
if (!outFile) return false;
// 读取 IStream 数据
STATSTG stat;
HRESULT hr = stream->Stat (&stat, STATFLAG_NONAME);
if (FAILED (hr)) return false;
LARGE_INTEGER liZero = {};
stream->Seek (liZero, STREAM_SEEK_SET, nullptr);
ULARGE_INTEGER remaining = stat.cbSize;
BYTE buffer [4096];
ULONG bytesRead;
while (remaining.QuadPart > 0)
{
hr = stream->Read (buffer, min (sizeof (buffer), remaining.LowPart), &bytesRead);
if (FAILED (hr) || bytesRead == 0) break;
outFile.write ((char*)buffer, bytesRead);
remaining.QuadPart -= bytesRead;
}
return outFile.good ();
}
// 线程安全删除临时文件
void DeleteFileThreadSafe (wchar_t* filePath)
{
Sleep (5000); // 等待通知可能完成显示
DeleteFileW (filePath);
}
bool CreateToastNotification (
LPCWSTR identityName,
LPCWSTR title,
LPCWSTR text,
NOTICE_PRESS_CALLBACK callback,
HISTREAM imgFile
)
{
ComPtr <IToastNotifier> notifier;
ComPtr <IToastNotification> toast;
ComPtr <IToastNotificationFactory> toastFactory;
ComPtr <IXmlDocument> xmlDoc;
HRESULT hr = RoInitialize (RO_INIT_MULTITHREADED);
if (FAILED (hr) && hr != RPC_E_CHANGED_MODE) return false;
ComPtr <IToastNotificationManagerStatics> toastManager;
hr = RoGetActivationFactory (HStringReference (L"Windows.UI.Notifications.ToastNotificationManager").Get (),
__uuidof(IToastNotificationManagerStatics),
&toastManager);
if (FAILED (hr)) return false;
hr = toastManager->CreateToastNotifierWithId (HStringReference (identityName).Get (), &notifier);
if (FAILED (hr)) return false;
hr = RoActivateInstance (HStringReference (L"Windows.Data.Xml.Dom.XmlDocument").Get (), &xmlDoc);
if (FAILED (hr)) return false;
wchar_t xmlTemplateWithImage [] =
L"<toast>"
L"<visual>"
L"<binding template='ToastImageAndText02'>"
L"<image id='1' src='file://%s'/>"
L"<text id='1'>%s</text>"
L"<text id='2'>%s</text>"
L"</binding>"
L"</visual>"
L"</toast>";
wchar_t xmlTemplateNoImage [] =
L"<toast>"
L"<visual>"
L"<binding template='ToastGeneric'>"
L"<text>%s</text>"
L"<text>%s</text>"
L"</binding>"
L"</visual>"
L"</toast>";
wchar_t xmlData [1024];
wchar_t imagePath [MAX_PATH] = L"";
if (imgFile != NULL)
{
IStream* img = (IStream*)imgFile;
STATSTG stat;
hr = img->Stat (&stat, STATFLAG_DEFAULT);
if (SUCCEEDED (hr) && stat.pwcsName)
{
wcscpy_s (imagePath, stat.pwcsName);
CoTaskMemFree (stat.pwcsName);
}
else
{
if (!SaveIStreamToTempFile (img, imagePath, MAX_PATH)) return false;
wchar_t* tempFileCopy = _wcsdup (imagePath);
if (tempFileCopy)
{
CreateThread (nullptr, 0, (LPTHREAD_START_ROUTINE)DeleteFileThreadSafe, tempFileCopy, 0, nullptr);
}
}
swprintf_s (xmlData, xmlTemplateWithImage, imagePath, title, text);
}
else
{
swprintf_s (xmlData, xmlTemplateNoImage, title, text);
}
ComPtr <IXmlDocumentIO> xmlDocIO;
hr = xmlDoc.As (&xmlDocIO);
if (FAILED (hr)) return false;
hr = xmlDocIO->LoadXml (HStringReference (xmlData).Get ());
if (FAILED (hr)) return false;
hr = RoGetActivationFactory (HStringReference (L"Windows.UI.Notifications.ToastNotification").Get (),
__uuidof(IToastNotificationFactory),
&toastFactory);
if (FAILED (hr)) return false;
hr = toastFactory->CreateToastNotification (xmlDoc.Get (), &toast);
if (FAILED (hr)) return false;
return SUCCEEDED (notifier->Show (toast.Get ()));
}
HRESULT CreateShortcutWithAppIdA (LPCSTR pszShortcutPath, LPCSTR pszTargetPath, LPCSTR pszAppId)
{
HRESULT hr;
// 初始化 COM
hr = CoInitialize (NULL);
if (FAILED (hr))
return hr;
// 创建 IShellLink 对象ANSI版本
IShellLinkA* pShellLinkA = NULL;
hr = CoCreateInstance (CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
IID_IShellLinkA, (void**)&pShellLinkA);
if (FAILED (hr))
{
CoUninitialize ();
return hr;
}
// 设置快捷方式目标路径
hr = pShellLinkA->SetPath (pszTargetPath);
if (FAILED (hr))
{
pShellLinkA->Release ();
CoUninitialize ();
return hr;
}
// 设置 AppUserModelID
IPropertyStore* pPropStore = NULL;
hr = pShellLinkA->QueryInterface (IID_IPropertyStore, (void**)&pPropStore);
if (SUCCEEDED (hr))
{
PROPVARIANT propvar;
hr = InitPropVariantFromString (_bstr_t (pszAppId), &propvar);
if (SUCCEEDED (hr))
{
// PKEY_AppUserModel_ID 定义在 propkey.h 中
hr = pPropStore->SetValue (PKEY_AppUserModel_ID, propvar);
if (SUCCEEDED (hr))
hr = pPropStore->Commit ();
PropVariantClear (&propvar);
}
pPropStore->Release ();
}
// 保存快捷方式文件IPersistFile 要求传入宽字符串)
IPersistFile* pPersistFile = NULL;
hr = pShellLinkA->QueryInterface (IID_IPersistFile, (void**)&pPersistFile);
if (SUCCEEDED (hr))
{
// 将 pszShortcutPath 从 ANSI 转换为 Unicode
wchar_t wszShortcutPath [MAX_PATH];
MultiByteToWideChar (CP_ACP, 0, pszShortcutPath, -1, wszShortcutPath, MAX_PATH);
hr = pPersistFile->Save (wszShortcutPath, TRUE);
pPersistFile->Release ();
}
pShellLinkA->Release ();
CoUninitialize ();
return hr;
}
HRESULT CreateShortcutWithAppIdW (LPCWSTR pszShortcutPath, LPCWSTR pszTargetPath, LPCWSTR pszAppId)
{
HRESULT hr;
hr = CoInitialize (NULL);
if (FAILED (hr))
{
return hr;
}
IShellLinkW* pShellLinkW = NULL;
hr = CoCreateInstance (CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void**)&pShellLinkW);
if (FAILED (hr))
{
CoUninitialize ();
return hr;
}
hr = pShellLinkW->SetPath (pszTargetPath);
if (FAILED (hr))
{
pShellLinkW->Release ();
CoUninitialize ();
return hr;
}
IPropertyStore* pPropStore = NULL;
hr = pShellLinkW->QueryInterface (IID_IPropertyStore, (void**)&pPropStore);
if (SUCCEEDED (hr))
{
PROPVARIANT propvar;
hr = InitPropVariantFromString (pszAppId, &propvar);
if (SUCCEEDED (hr))
{
hr = pPropStore->SetValue (PKEY_AppUserModel_ID, propvar);
if (SUCCEEDED (hr))
{
hr = pPropStore->Commit ();
}
PropVariantClear (&propvar);
}
pPropStore->Release ();
}
IPersistFile* pPersistFile = NULL;
hr = pShellLinkW->QueryInterface (IID_IPersistFile, (void**)&pPersistFile);
if (SUCCEEDED (hr))
{
hr = pPersistFile->Save (pszShortcutPath, TRUE);
pPersistFile->Release ();
}
pShellLinkW->Release ();
CoUninitialize ();
return hr;
}