// pkgmgr.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h" #include "notice.h" #include "raii.h" #include "version.h" #include "nstring.h" #ifdef GetFullPathName #undef GetFullPathName #endif #ifdef min #undef min #endif #ifdef max #undef max #endif std::wstring GetFullPathName (const std::wstring &lpFileName) { if (lpFileName.empty ()) return L""; DWORD length = GetFullPathNameW (lpFileName.c_str (), 0, nullptr, nullptr); if (length == 0) return L""; std::vector buffer (length + 1, L'\0'); DWORD result = GetFullPathNameW (lpFileName.c_str (), length, buffer.data (), nullptr); if (result == 0) return L""; return std::wstring (buffer.data (), result); } LPWSTR AllocWideString (const std::wstring &str) { size_t size = (str.length () + 1) * sizeof (WCHAR); LPWSTR buf = (LPWSTR)CoTaskMemAlloc (size); if (!buf) return nullptr; ZeroMemory (buf, size); wcscpy (buf, str.c_str ()); return buf; } // 测试用 LPWSTR AllocWideString (LPCWSTR str) { if (!str) return nullptr; size_t size = (wcslen (str) + 1) * sizeof (WCHAR); LPWSTR buf = (LPWSTR)CoTaskMemAlloc (size); if (!buf) return nullptr; ZeroMemory (buf, size); wcscpy (buf, str); return buf; } #define _wcsdup AllocWideString #define free CoTaskMemFree #define malloc CoTaskMemAlloc #define realloc CoTaskMemRealloc #define calloc(_cnt_, _size_) CoTaskMemAlloc (_cnt_ * _size_) struct destruct { std::function endtask = nullptr; destruct (std::function pfunc): endtask (pfunc) {} ~destruct () { if (endtask) endtask (); } }; static std::wstring StringToWString (const std::string &str, UINT codePage = CP_ACP) { if (str.empty ()) return std::wstring (); int len = MultiByteToWideChar (codePage, 0, str.c_str (), -1, nullptr, 0); if (len == 0) return std::wstring (); std::wstring wstr (len - 1, L'\0'); MultiByteToWideChar (codePage, 0, str.c_str (), -1, &wstr [0], len); return wstr; } Windows::Data::Xml::Dom::XmlDocument ^TemplateToastNoticeXml (const std::wstring &lpTemplateName) { std::wnstring temp = lpTemplateName; try { using toastttype = Windows::UI::Notifications::ToastTemplateType; auto tttype = Windows::UI::Notifications::ToastTemplateType::ToastImageAndText01; if (temp.equals (L"ToastText01")) tttype = toastttype::ToastText01; else if (temp.equals (L"ToastText02")) tttype = toastttype::ToastText02; else if (temp.equals (L"ToastText03")) tttype = toastttype::ToastText03; else if (temp.equals (L"ToastText04")) tttype = toastttype::ToastText04; else if (temp.equals (L"ToastImageAndText01")) tttype = toastttype::ToastImageAndText01; else if (temp.equals (L"ToastImageAndText02")) tttype = toastttype::ToastImageAndText02; else if (temp.equals (L"ToastImageAndText03")) tttype = toastttype::ToastImageAndText03; else if (temp.equals (L"ToastImageAndText04")) tttype = toastttype::ToastImageAndText04; else tttype = (toastttype)-1; if ((INT16)tttype > 0) { auto tt = Windows::UI::Notifications::ToastNotificationManager::GetTemplateContent (tttype); if (tt) return tt; } } catch (...) {} auto xmldoc = ref new Windows::Data::Xml::Dom::XmlDocument (); auto root = xmldoc->CreateElement ("toast"); xmldoc->AppendChild (root); auto visual = xmldoc->CreateElement ("visual"); root->AppendChild (visual); auto binding = xmldoc->CreateElement ("binding"); visual->AppendChild (binding); if (temp.equals (L"ToastText01")) { binding->SetAttribute ("template", "ToastText01"); auto text1 = xmldoc->CreateElement ("text"); text1->SetAttribute ("id", "1"); binding->AppendChild (text1); } else if (temp.equals (L"ToastText02")) { binding->SetAttribute ("template", "ToastText02"); auto text1 = xmldoc->CreateElement ("text"); text1->SetAttribute ("id", "1"); auto text2 = xmldoc->CreateElement ("text"); text2->SetAttribute ("id", "2"); binding->AppendChild (text1); binding->AppendChild (text2); } else if (temp.equals (L"ToastText03")) { binding->SetAttribute ("template", "ToastText03"); auto text1 = xmldoc->CreateElement ("text"); text1->SetAttribute ("id", "1"); auto text2 = xmldoc->CreateElement ("text"); text2->SetAttribute ("id", "2"); binding->AppendChild (text1); binding->AppendChild (text2); } else if (temp.equals (L"ToastText04")) { binding->SetAttribute ("template", "ToastText04"); auto text1 = xmldoc->CreateElement ("text"); text1->SetAttribute ("id", "1"); auto text2 = xmldoc->CreateElement ("text"); text2->SetAttribute ("id", "2"); auto text3 = xmldoc->CreateElement ("text"); text3->SetAttribute ("id", "3"); binding->AppendChild (text1); binding->AppendChild (text2); binding->AppendChild (text3); } else if (temp.equals (L"ToastImageAndText01")) { binding->SetAttribute ("template", "ToastImageAndText01"); auto text1 = xmldoc->CreateElement ("text"); text1->SetAttribute ("id", "1"); auto img1 = xmldoc->CreateElement ("image"); img1->SetAttribute ("id", "1"); img1->SetAttribute ("src", ""); img1->SetAttribute ("alt", ""); binding->AppendChild (img1); binding->AppendChild (text1); } else if (temp.equals (L"ToastImageAndText02")) { binding->SetAttribute ("template", "ToastImageAndText02"); auto text1 = xmldoc->CreateElement ("text"); text1->SetAttribute ("id", "1"); auto img1 = xmldoc->CreateElement ("image"); img1->SetAttribute ("id", "1"); img1->SetAttribute ("src", ""); img1->SetAttribute ("alt", ""); binding->AppendChild (img1); binding->AppendChild (text1); } else if (temp.equals (L"ToastImageAndText03")) { binding->SetAttribute ("template", "ToastImageAndText03"); auto text1 = xmldoc->CreateElement ("text"); text1->SetAttribute ("id", "1"); auto text2 = xmldoc->CreateElement ("text"); text2->SetAttribute ("id", "2"); auto img1 = xmldoc->CreateElement ("image"); img1->SetAttribute ("id", "1"); img1->SetAttribute ("src", ""); img1->SetAttribute ("alt", ""); binding->AppendChild (img1); binding->AppendChild (text1); binding->AppendChild (text2); } else if (temp.equals (L"ToastImageAndText04")) { binding->SetAttribute ("template", "ToastImageAndText04"); auto text1 = xmldoc->CreateElement ("text"); text1->SetAttribute ("id", "1"); auto text2 = xmldoc->CreateElement ("text"); text2->SetAttribute ("id", "2"); auto text3 = xmldoc->CreateElement ("text"); text3->SetAttribute ("id", "3"); auto img1 = xmldoc->CreateElement ("image"); img1->SetAttribute ("id", "1"); img1->SetAttribute ("src", ""); img1->SetAttribute ("alt", ""); binding->AppendChild (img1); binding->AppendChild (text1); binding->AppendChild (text2); binding->AppendChild (text3); } else { binding->SetAttribute ("template", "ToastImageAndText04"); auto text1 = xmldoc->CreateElement ("text"); binding->AppendChild (text1); } return xmldoc; } LPWSTR GetToastNoticeXml (LPCWSTR lpTemplateName) { auto xmldoc = TemplateToastNoticeXml (lpTemplateName); return _wcsdup (xmldoc->GetXml ()->Data ()); } Windows::Data::Xml::Dom::XmlDocument ^SimpleToastNoticeXml (const std::wstring &lpText, const std::wstring &lpImgPath = L"") { Windows::Data::Xml::Dom::XmlDocument ^xmldoc = nullptr; std::wnstring img = lpImgPath; std::wstring text = std::wnstring::trim (std::wstring (lpText)); { // std::wstring xmltemplate = L""; xmldoc = TemplateToastNoticeXml (img.empty () ? L"ToastText01" : L"ToastImageAndText01"); } Windows::Foundation::Uri ^imguri = nullptr; try { imguri = ref new Windows::Foundation::Uri (ref new Platform::String (img.c_str ())); } catch (...) { try { std::wstring fullpath = GetFullPathName (lpImgPath); if (fullpath.empty ()) fullpath = lpImgPath; imguri = ref new Windows::Foundation::Uri (ref new Platform::String (img.c_str ())); } catch (...) { imguri = nullptr; } } auto toast = xmldoc->FirstChild; auto visual = toast->FirstChild; auto binding = visual->FirstChild; auto binds = binding->ChildNodes; auto textNodes = binding->SelectNodes (ref new Platform::String (L"text")); if (textNodes && textNodes->Length > 0) { auto node = dynamic_cast (textNodes->Item (0)); if (node) node->InnerText = ref new Platform::String (text.c_str ()); } auto imageNodes = binding->SelectNodes (ref new Platform::String (L"image")); if (imageNodes && imageNodes->Length > 0 && !img.empty ()) { auto node = dynamic_cast (imageNodes->Item (0)); if (node) { node->SetAttribute (L"src", ref new Platform::String (imguri && imguri->ToString ()->Data () ? imguri->ToString ()->Data () : img.c_str ())); node->SetAttribute (L"alt", ref new Platform::String (L"image")); } } return xmldoc; } LPWSTR GenerateSimpleToastNoticeXml (LPCWSTR lpText, LPCWSTR lpImagePath) { auto xmldoc = SimpleToastNoticeXml (lpText ? lpText : L"", lpImagePath ? lpImagePath : L""); return _wcsdup (xmldoc->GetXml ()->Data ()); } Windows::Data::Xml::Dom::XmlDocument ^SimpleToastNoticeXml2 (const std::wstring &lpTitle, const std::wstring &lpText = L"", const std::wstring &lpImagePath = L"") { Windows::Data::Xml::Dom::XmlDocument ^xmldoc = nullptr; std::wnstring img = lpImagePath; std::wstring title = std::wnstring (lpTitle).trim (); std::wstring text = std::wnstring (lpText).trim (); { // std::wstring xmltemplate = L""; std::wstring templatename = L""; WORD flag = (bool)(!img.empty ()) << 2 | (bool)title.size () << 1 | (bool)text.size (); switch (flag) { case 1: templatename = L"ToastText01"; break; // 仅正文 case 3: templatename = L"ToastText02"; break; // 标题 + 正文 case 6: case 5: templatename = L"ToastImageAndText01"; break; // 图 + 正文 case 7: templatename = L"ToastImageAndText02"; break; // 图 + 标题 + 正文 default: templatename = L"ToastText01"; break; } xmldoc = TemplateToastNoticeXml (templatename); } Windows::Foundation::Uri ^imguri = nullptr; try { imguri = ref new Windows::Foundation::Uri (ref new Platform::String (img.c_str ())); } catch (...) { try { std::wstring fullpath = GetFullPathName (lpImagePath); if (fullpath.empty ()) fullpath = lpImagePath; imguri = ref new Windows::Foundation::Uri (ref new Platform::String (img.c_str ())); } catch (...) { imguri = nullptr; } } auto binding = xmldoc->SelectSingleNode (ref new Platform::String (L"/toast/visual/binding")); auto textNodes = binding->SelectNodes (ref new Platform::String (L"text")); if (textNodes && textNodes->Length > 0) { unsigned int idx = 0; if (!title.empty ()) { auto node = dynamic_cast (textNodes->Item (idx++)); if (node) node->InnerText = ref new Platform::String (title.c_str ()); } if (!text.empty () && idx < textNodes->Length) { auto node = dynamic_cast (textNodes->Item (idx)); if (node) node->InnerText = ref new Platform::String (text.c_str ()); } else if (!text.empty () && title.empty ()) { auto node = dynamic_cast (textNodes->Item (0)); if (node) node->InnerText = ref new Platform::String (text.c_str ()); } } auto imageNodes = binding->SelectNodes (ref new Platform::String (L"image")); if (imageNodes && imageNodes->Length > 0 && !img.empty ()) { auto node = dynamic_cast (imageNodes->Item (0)); if (node) { node->SetAttribute (L"src", ref new Platform::String (imguri && imguri->ToString ()->Data () ? imguri->ToString ()->Data () : img.c_str ())); node->SetAttribute (L"alt", ref new Platform::String (L"image")); } } return xmldoc; } LPWSTR GenerateSimpleToastNoticeXml2 (LPCWSTR lpTitle, LPCWSTR lpText, LPCWSTR lpImagePath) { auto xmldoc = SimpleToastNoticeXml2 (lpTitle ? lpTitle : L"", lpText ? lpText : L"", lpImagePath ? lpImagePath : L""); return _wcsdup (xmldoc->GetXml ()->Data ()); } // 会实时记录 hResult; HRESULT g_lasthr = S_OK; // 记录上一次异常(不会根据操作更新)的信息 std::wstring g_lastexc = L""; #define catch_lasterr(_PHRESULT_Outptr_lphResult_, _HLPWSTR_Outptr_lpExcepMsg_) \ catch (Platform::Exception ^e) \ { \ g_lastexc = e->ToString ()->Data (); \ if (_HLPWSTR_Outptr_lpExcepMsg_) *(_HLPWSTR_Outptr_lpExcepMsg_) = _wcsdup (g_lastexc.c_str ()); \ g_lasthr = SUCCEEDED ((HRESULT)e->HResult) ? E_FAIL : (HRESULT)e->HResult; \ if (_PHRESULT_Outptr_lphResult_) *(_PHRESULT_Outptr_lphResult_) = g_lasthr; \ } \ catch (const std::exception &e) \ { \ g_lastexc = StringToWString (e.what () ? e.what () : "Unknown exception."); \ if (_HLPWSTR_Outptr_lpExcepMsg_) *(_HLPWSTR_Outptr_lpExcepMsg_) = _wcsdup (g_lastexc.c_str ()); \ g_lasthr = E_FAIL; \ if (_PHRESULT_Outptr_lphResult_) *(_PHRESULT_Outptr_lphResult_) = g_lasthr; \ } \ catch (...) \ { \ g_lastexc = L"Unknown exception"; \ if (_HLPWSTR_Outptr_lpExcepMsg_) *(_HLPWSTR_Outptr_lpExcepMsg_) = _wcsdup (g_lastexc.c_str ()); \ g_lasthr = E_FAIL; \ if (_PHRESULT_Outptr_lphResult_) *(_PHRESULT_Outptr_lphResult_) = g_lasthr; \ } HRESULT CreateToastNoticeFromXml (const std::wstring &lpIdName, Windows::Data::Xml::Dom::XmlDocument ^pIXml, NOTICE_ACTIVECALLBACK pfCallback = nullptr, void *pCustom = nullptr, LPWSTR *lpExceptMsg = nullptr) { using XmlDoc = Windows::Data::Xml::Dom::XmlDocument; using ToastNotification = Windows::UI::Notifications::ToastNotification; using Toast = ToastNotification; using ToastMgr = Windows::UI::Notifications::ToastNotificationManager; using String = Platform::String; using Object = Platform::Object; auto &hr = g_lasthr; if (lpExceptMsg) *lpExceptMsg = nullptr; try { Windows::UI::Notifications::ToastNotifier ^notifier = nullptr; if (!std::wnstring (lpIdName).empty ()) notifier = ToastMgr::CreateToastNotifier (ref new String (lpIdName.c_str ())); else notifier = ToastMgr::CreateToastNotifier (); auto &xmldoc = pIXml; auto toast = ref new Toast (xmldoc); //toast->Activated += ref new Windows::Foundation::TypedEventHandler < // Windows::UI::Notifications::ToastNotification ^, // Platform::Object ^ //> ([=] (Windows::UI::Notifications::ToastNotification ^sender, Platform::Object ^args) { // if (pfCallback) pfCallback (pCustom); //}); notifier->Show (toast); return hr = S_OK; } catch_lasterr (&hr, lpExceptMsg); return hr; } HRESULT CreateToastNoticeFromXml (const std::wstring &lpIdName, const std::wstring &lpXmlString, NOTICE_ACTIVECALLBACK pfCallback = nullptr, void *pCustom = nullptr, LPWSTR *lpExceptMsg = nullptr) { using XmlDoc = Windows::Data::Xml::Dom::XmlDocument; using String = Platform::String; using Object = Platform::Object; if (lpExceptMsg) *lpExceptMsg = nullptr; auto &hr = g_lasthr; try { auto xmldoc = ref new XmlDoc (); xmldoc->LoadXml (ref new String (lpXmlString.c_str ())); return hr = CreateToastNoticeFromXml (lpIdName, xmldoc, pfCallback, pCustom, lpExceptMsg); } catch_lasterr (&hr, lpExceptMsg); return hr; } HRESULT CreateToastNoticeFromXmlDocument (LPCWSTR lpIdName, LPCWSTR lpXmlString, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg) { return CreateToastNoticeFromXml (lpIdName ? lpIdName : L"", lpXmlString ? lpXmlString : L"", pfCallback, pCustom, lpExceptMsg); } HRESULT CreateToastNotice2 (LPCWSTR lpIdName, LPCWSTR lpTitle, LPCWSTR lpText, LPCWSTR lpImgPath, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg) { auto &hr = g_lasthr; try { auto xmldoc = SimpleToastNoticeXml2 (lpTitle ? lpTitle : L"", lpText ? lpText : L"", lpImgPath ? lpImgPath : L""); return hr = CreateToastNoticeFromXml (lpIdName, xmldoc, pfCallback, pCustom, lpExceptMsg); } catch_lasterr (&hr, lpExceptMsg); return hr; } HRESULT CreateToastNotice (LPCWSTR lpIdName, LPCWSTR lpText, LPCWSTR lpImgPath, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg) { return CreateToastNotice2 (lpIdName, lpText, nullptr, lpImgPath, pfCallback, pCustom, lpExceptMsg); } std::wstring GetRandomText (size_t length = 16, const std::wstring &charset = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") { if (charset.empty ()) return L""; static bool seeded = false; if (!seeded) { std::srand ((unsigned int)(std::time (nullptr) ^ (uintptr_t)&seeded)); seeded = true; } std::wstring ret; ret.reserve (length); for (size_t i = 0; i < length; ++i) { size_t index = (size_t)(std::rand () % charset.size ()); ret.push_back (charset [index]); } return ret; } std::wstring CombinePath (const std::wstring &left, const std::wstring &right) { std::vector buf (left.capacity () + right.capacity () + 2); PathCombineW (buf.data (), left.c_str (), right.c_str ()); return buf.data (); } std::wstring GetRamdomFileName (const std::wstring &directory, const std::wstring &ext = L".tmp", bool retfullpath = true) { std::wnstring name = std::wnstring::trim (GetRandomText (3) + L"-" + GetRandomText (5) + L"-" + GetRandomText (3)) + std::wnstring::trim (ext); std::wnstring path = CombinePath (directory, name); while (GetFileAttributesW (path.c_str ()) != INVALID_FILE_ATTRIBUTES) { name = GetRandomText (3) + L"-" + GetRandomText (5) + L"-" + GetRandomText (3) + ext; path = CombinePath (directory, name); } if (retfullpath) return path; else return name; } std::wstring GetTempDirectory () { std::vector ret (GetTempPathW (0, nullptr) + 2); GetTempPathW (ret.size (), ret.data ()); return ret.data (); } std::wstring GetRamdomTempFileName (const std::wstring &ext = L".tmp", bool retfullpath = true) { return GetRamdomFileName (GetTempDirectory (), ext, retfullpath); } std::wstring IStreamToTempFile (IStream *p, const std::wstring &ext = L".tmp") { if (!p) throw ref new Platform::InvalidArgumentException ("IStream is nullptr."); std::wnstring outpath = GetRamdomTempFileName (ext); auto &stream = p; STATSTG stat; HRESULT hr = stream->Stat (&stat, STATFLAG_NONAME); if (FAILED (hr)) throw Platform::Exception::CreateException (hr); LARGE_INTEGER liZero = {}; stream->Seek (liZero, STREAM_SEEK_SET, nullptr); HANDLE hFile = CreateFileW (outpath.c_str (), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, nullptr); const size_t bufsize = 4096; BYTE buf [bufsize] = {0}; ULONG bytesRead = 0; DWORD bytesWritten = 0; while (true) { hr = stream->Read (buf, bufsize, &bytesRead); if (FAILED (hr)) { CloseHandle (hFile); throw Platform::Exception::CreateException (hr); } if (bytesRead == 0) break; if (!WriteFile (hFile, buf, bytesRead, &bytesWritten, nullptr) || bytesWritten != bytesRead) { CloseHandle (hFile); throw std::runtime_error ("WriteFile failed."); } } CloseHandle (hFile); return outpath; } void DeleteFileThreadSafe (LPWSTR filepath) { raii endt ([&] () { if (filepath) free (filepath); filepath = nullptr; }); Sleep (5000); DeleteFileW (filepath); } HRESULT CreateToastNoticeWithIStream2 (LPCWSTR lpIdName, LPCWSTR lpTitle, LPCWSTR lpText, HANDLE pIImgStream, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg) { auto &hr = g_lasthr; try { std::wnstring imgpath = L""; try { if (pIImgStream) { IStream *img = (IStream *)pIImgStream; LARGE_INTEGER li; li.QuadPart = 0; img->Seek (li, STREAM_SEEK_SET, nullptr); STATSTG stat; hr = img->Stat (&stat, STATFLAG_DEFAULT); if (SUCCEEDED (hr) && stat.pwcsName) { if (stat.pwcsName) imgpath = stat.pwcsName; CoTaskMemFree (stat.pwcsName); } else { imgpath = IStreamToTempFile (img, L".jpg"); CreateThread (nullptr, 0, (LPTHREAD_START_ROUTINE)DeleteFileThreadSafe, _wcsdup (imgpath.c_str ()), 0, nullptr); } } Windows::Foundation::Uri ^uri = ref new Windows::Foundation::Uri (ref new Platform::String (imgpath.c_str ())); } catch (...) { imgpath = L""; } return hr = CreateToastNotice2 (lpIdName, lpTitle, lpText, imgpath.c_str (), pfCallback, pCustom, lpExceptMsg); } catch_lasterr (&hr, lpExceptMsg); return hr; } HRESULT CreateToastNoticeWithIStream (LPCWSTR lpIdName, LPCWSTR lpText, HANDLE pIImgStream, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg) { return CreateToastNoticeWithIStream2 (lpIdName, lpText, nullptr, pIImgStream, pfCallback, pCustom, lpExceptMsg); } HRESULT NoticeGetLastHResult () { return g_lasthr; } LPCWSTR NoticeGetLastDetailMessage () { return g_lastexc.c_str (); } HRESULT CreateShortcutWithAppIdW (LPCWSTR pszShortcutPath, LPCWSTR pszTargetPath, LPCWSTR pszAppId, LPWSTR *lpException) { HRESULT &hr = g_lasthr; destruct relt ([&] () { if (FAILED (hr)) { if (lpException && !*lpException) { _com_error ex (hr); g_lastexc = ex.ErrorMessage () ? ex.ErrorMessage () : L""; *lpException = _wcsdup (g_lastexc.c_str ()); } } }); if (lpException) *lpException = nullptr; try { hr = CoInitialize (NULL); if (FAILED (hr)) return hr; IShellLinkW *pShellLinkW = nullptr; raii reltask1 ([&] () { if (pShellLinkW) pShellLinkW->Release (); pShellLinkW = nullptr; }); hr = CoCreateInstance (CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void **)&pShellLinkW); if (FAILED (hr)) return hr; hr = pShellLinkW->SetPath (pszTargetPath); if (FAILED (hr)) return hr; IPropertyStore *pPropStore = nullptr; raii reltask2 ([&] () { if (pPropStore) pPropStore->Release (); pPropStore = nullptr; }); 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); } } else pPropStore = nullptr; IPersistFile *pPersistFile = nullptr; raii reltask3 ([&] () { if (pPersistFile) pPersistFile->Release (); pPersistFile = nullptr; }); hr = pShellLinkW->QueryInterface (IID_IPersistFile, (void **)&pPersistFile); if (SUCCEEDED (hr)) hr = pPersistFile->Save (pszShortcutPath, TRUE); else pPersistFile = nullptr; return hr; } catch_lasterr (&hr, lpException); return hr; } void NoticeApiFreeString (LPWSTR lpstr) { if (!lpstr) return; CoTaskMemFree (lpstr); } size_t Base64ToBytes (const std::wstring &base64OrDataUri, std::vector &retbytes) { retbytes.clear (); std::wstring base64 = base64OrDataUri; size_t commaPos = base64.find (L','); if (commaPos != std::wstring::npos) base64 = base64.substr (commaPos + 1); DWORD binLen = 0; if (!CryptStringToBinaryW (base64.c_str (), static_cast (base64.length ()), CRYPT_STRING_BASE64, nullptr, &binLen, nullptr, nullptr)) return 0; retbytes.resize (binLen); if (!CryptStringToBinaryW (base64.c_str (), static_cast (base64.length ()), CRYPT_STRING_BASE64, retbytes.data (), &binLen, nullptr, nullptr)) { retbytes.clear (); return 0; // 解码失败 } return binLen; } HRESULT BytesToIStream (const std::vector &data, IStream **ppStream) { if (!ppStream) return E_POINTER; *ppStream = nullptr; HGLOBAL hMem = GlobalAlloc (GMEM_MOVEABLE, data.size ()); if (!hMem) return E_OUTOFMEMORY; void *pMem = GlobalLock (hMem); if (!pMem) { GlobalFree (hMem); return E_FAIL; } memcpy (pMem, data.data (), data.size ()); GlobalUnlock (hMem); HRESULT hr = CreateStreamOnHGlobal (hMem, TRUE, ppStream); if (FAILED (hr)) GlobalFree (hMem); return hr; } HRESULT CreateToastNoticeWithImgBase64 (LPCWSTR lpIdName, LPCWSTR lpText, LPCWSTR lpImgBase64, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg) { IStream *ist = nullptr; destruct relt ([&ist] () { if (ist) ist->Release (); ist = nullptr; }); std::vector bytes; Base64ToBytes (lpImgBase64 ? lpImgBase64 : L"", bytes); if (bytes.size ()) { if (FAILED (BytesToIStream (bytes, &ist))) ist = nullptr; } return CreateToastNoticeWithIStream (lpIdName, lpText, ist, pfCallback, pCustom, lpExceptMsg); } HRESULT CreateToastNotice2WithImgBase64 (LPCWSTR lpIdName, LPCWSTR lpTitle, LPCWSTR lpText, LPCWSTR lpImgBase64, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg) { IStream *ist = nullptr; destruct relt ([&ist] () { if (ist) ist->Release (); ist = nullptr; }); std::vector bytes; Base64ToBytes (lpImgBase64 ? lpImgBase64 : L"", bytes); if (bytes.size ()) { if (FAILED (BytesToIStream (bytes, &ist))) ist = nullptr; } return CreateToastNoticeWithIStream2 (lpIdName, lpTitle, lpText, ist, pfCallback, pCustom, lpExceptMsg); } HRESULT CreateMessageDialog (const std::wstring &content, const std::wstring &title, LPWSTR *lpException) { auto &hr = g_lasthr; try { auto refcon = ref new Platform::String (content.c_str ()); auto reftit = ref new Platform::String (title.c_str ()); Windows::UI::Popups::MessageDialog ^msgdlg = nullptr; if (IsNormalizeStringEmpty (title)) msgdlg = ref new Windows::UI::Popups::MessageDialog (refcon); else msgdlg = ref new Windows::UI::Popups::MessageDialog (refcon, reftit); msgdlg->ShowAsync (); return S_OK; } catch_lasterr (&hr, lpException); return hr; } HRESULT SimpleMessageDialog (LPCWSTR lpContent, LPCWSTR lpTitle, LPWSTR *lpException) { auto &hr = g_lasthr; try { return CreateMessageDialog ( lpContent ? lpContent : L"", lpTitle ? lpTitle : L"", lpException ); } catch_lasterr (&hr, lpException); return hr; } HRESULT CreateTileNoticifation (LPCWSTR lpAppId, LPCWSTR lpXmlDoc, LPWSTR *lpExMsg) { auto &hr = g_lasthr; try { auto refcon = ref new Platform::String (lpXmlDoc ? lpXmlDoc : L""); auto xmldoc = ref new Windows::Data::Xml::Dom::XmlDocument (); xmldoc->LoadXml (ref new Platform::String (lpXmlDoc ? lpXmlDoc : L"")); auto tile = ref new Windows::UI::Notifications::TileNotification (xmldoc); auto tilemgr = Windows::UI::Notifications::TileUpdateManager::CreateTileUpdaterForApplication (ref new Platform::String (lpAppId ? lpAppId : L"")); tilemgr->Update (tile); return S_OK; } catch_lasterr (&hr, lpExMsg); return hr; }