mirror of
https://github.com/modernw/App-Installer-For-Windows-8.x-Reset.git
synced 2026-04-11 17:57:19 +10:00
Update Toast Notice Features
This commit is contained in:
@@ -5,8 +5,11 @@
|
||||
#include "notice.h"
|
||||
#include "raii.h"
|
||||
#include "version.h"
|
||||
#include "nstring.h"
|
||||
|
||||
#ifdef GetFullPathName
|
||||
#undef GetFullPathName
|
||||
#endif
|
||||
std::wstring GetFullPathName (const std::wstring &lpFileName)
|
||||
{
|
||||
if (lpFileName.empty ()) return L"";
|
||||
@@ -18,9 +21,6 @@ std::wstring GetFullPathName (const std::wstring &lpFileName)
|
||||
return std::wstring (buffer.data (), result);
|
||||
}
|
||||
|
||||
std::wstring g_swExceptionCode = L"";
|
||||
std::wstring g_swExceptionDetail = L"";
|
||||
|
||||
struct destruct
|
||||
{
|
||||
std::function <void ()> endtask = nullptr;
|
||||
@@ -36,4 +36,299 @@ static std::wstring StringToWString (const std::string &str, UINT codePage = CP_
|
||||
MultiByteToWideChar (codePage, 0, str.c_str (), -1, &wstr [0], len);
|
||||
return wstr;
|
||||
}
|
||||
LPWSTR GetToastNoticeXml (LPCWSTR lpTemplateName)
|
||||
{
|
||||
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);
|
||||
std::wnstring temp = lpTemplateName ? lpTemplateName : L"";
|
||||
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 _wcsdup (xmldoc->GetXml ()->Data ());
|
||||
}
|
||||
LPWSTR GenerateSimpleToastNoticeXml (LPCWSTR lpText, LPCWSTR lpImagePath)
|
||||
{
|
||||
auto xmldoc = ref new Windows::Data::Xml::Dom::XmlDocument ();
|
||||
std::wnstring img = lpImagePath ? lpImagePath : L"";
|
||||
std::wstring text = std::wnstring::trim (std::wstring (lpText ? lpText : L""));
|
||||
{
|
||||
std::wstring xmltemplate = L"<toast><visual><binding template='ToastGeneric'><text></text></binding></visual></toast>";
|
||||
LPWSTR xt = nullptr;
|
||||
raii relt ([&xt] () {
|
||||
if (xt) free (xt);
|
||||
xt = nullptr;
|
||||
});
|
||||
xt = GetToastNoticeXml (img.empty () ? L"ToastText01" : L"ToastImageAndText01");
|
||||
if (xt && *xt) xmltemplate = xt;
|
||||
xmldoc->LoadXml (ref new Platform::String (xmltemplate.c_str ()));
|
||||
}
|
||||
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 ? lpImagePath : L"");
|
||||
if (fullpath.empty ()) fullpath = lpImagePath ? lpImagePath : L"";
|
||||
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 <Windows::Data::Xml::Dom::XmlElement ^> (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 <Windows::Data::Xml::Dom::XmlElement ^> (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 _wcsdup (xmldoc->GetXml ()->Data ());
|
||||
}
|
||||
LPWSTR GenerateSimpleToastNoticeXml2 (LPCWSTR lpTitle, LPCWSTR lpText, LPCWSTR lpImagePath)
|
||||
{
|
||||
auto xmldoc = ref new Windows::Data::Xml::Dom::XmlDocument ();
|
||||
std::wnstring img = lpImagePath ? lpImagePath : L"";
|
||||
std::wstring title = std::wnstring (lpTitle ? lpTitle : L"").trim ();
|
||||
std::wstring text = std::wnstring (lpText ? lpText : L"").trim ();
|
||||
{
|
||||
std::wstring xmltemplate = L"<toast><visual><binding template='ToastGeneric'><text></text></binding></visual></toast>";
|
||||
LPWSTR xt = nullptr;
|
||||
raii relt ([&xt] () {
|
||||
if (xt) free (xt);
|
||||
xt = nullptr;
|
||||
});
|
||||
std::wstring templatename = L"";
|
||||
WORD flag = (bool)(!img.empty ()) << 2 | (bool)title.size () << 1 | (bool)text.size ();
|
||||
switch (flag)
|
||||
{
|
||||
case 0b001: templatename = L"ToastText01"; break; // 仅正文
|
||||
case 0b011: templatename = L"ToastText02"; break; // 标题 + 正文
|
||||
case 0b101: templatename = L"ToastImageAndText01"; break; // 图 + 正文
|
||||
case 0b111: templatename = L"ToastImageAndText02"; break; // 图 + 标题 + 正文
|
||||
default: templatename = L"ToastText01"; break;
|
||||
}
|
||||
xt = GetToastNoticeXml (templatename.c_str ());
|
||||
if (xt && *xt) xmltemplate = xt;
|
||||
xmldoc->LoadXml (ref new Platform::String (xmltemplate.c_str ()));
|
||||
}
|
||||
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 ? lpImagePath : L"");
|
||||
if (fullpath.empty ()) fullpath = lpImagePath ? lpImagePath : L"";
|
||||
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 <Windows::Data::Xml::Dom::XmlElement ^> (textNodes->Item (idx++));
|
||||
if (node) node->InnerText = ref new Platform::String (title.c_str ());
|
||||
}
|
||||
if (!text.empty () && idx < textNodes->Length)
|
||||
{
|
||||
auto node = dynamic_cast <Windows::Data::Xml::Dom::XmlElement ^> (textNodes->Item (idx));
|
||||
if (node) node->InnerText = ref new Platform::String (text.c_str ());
|
||||
}
|
||||
else if (!text.empty () && title.empty ())
|
||||
{
|
||||
auto node = dynamic_cast <Windows::Data::Xml::Dom::XmlElement ^> (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 <Windows::Data::Xml::Dom::XmlElement ^> (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 _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 CreateToastNoticeFromXmlDocument (LPCWSTR lpIdName, LPCWSTR lpXmlString, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg)
|
||||
{
|
||||
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 (lpIdName && *lpIdName) notifier = ToastMgr::CreateToastNotifier (ref new String (lpIdName));
|
||||
else notifier = ToastMgr::CreateToastNotifier ();
|
||||
auto xmldoc = ref new XmlDoc ();
|
||||
xmldoc->LoadXml (ref new String (lpXmlString));
|
||||
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 S_OK;
|
||||
}
|
||||
catch_lasterr (&hr, lpExceptMsg);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ extern "C"
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
#define _DEFAULT_INIT_VALUE_(_init_value_) = _init_value_
|
||||
#ifndef PKGMGR_EXPORTS
|
||||
#ifndef NOTICE_EXPORTS
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_) = _init_value_
|
||||
#else
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
|
||||
@@ -27,6 +27,29 @@ extern "C"
|
||||
#define _DEFAULT_INIT_VALUE_(_init_value_)
|
||||
#define _DEFAULT_INIT_VALUE_FORFUNC_(_init_value_)
|
||||
#endif
|
||||
typedef void (*NOTICE_ACTIVECALLBACK) (void *pCustom);
|
||||
// 参考:https://learn.microsoft.com/zh-cn/previous-versions/windows/apps/hh761494(v=win.10)
|
||||
// 通过 Toast 通知名来获取 XML 模板。
|
||||
// 不符合会返回一个默认模板(只会有一个 text 节点。根据需要的话可以自己添加)
|
||||
// 注意:返回的指针要自己 free 释放
|
||||
NOTICE_API LPWSTR GetToastNoticeXml (LPCWSTR lpTemplateName);
|
||||
// 获取一个简单的 Toast 通知 XML 文档。第一个参数是必须的。第二个参数为图片 URI(file:///)。
|
||||
// 第二个参数如果为 NULL 或去掉首尾空的长度为 0 的文本则不会使用带图片的模板。
|
||||
// 注意:返回的指针要自己通过 free 释放
|
||||
NOTICE_API LPWSTR GenerateSimpleToastNoticeXml (LPCWSTR lpText, LPCWSTR lpImagePath);
|
||||
// 获取一个简单的 Toast 通知 XML 文档。第一个参数是必须的。第三个参数为图片 URI(file:///)。
|
||||
// 第三个参数如果为 NULL 或去掉首尾空的长度为 0 的文本则不会使用带图片的模板。
|
||||
// 第二个参数可以为 NULL 或空文本。当为空时不会使用相关模板
|
||||
// 注意:返回的指针要自己通过 free 释放
|
||||
NOTICE_API LPWSTR GenerateSimpleToastNoticeXml2 (LPCWSTR lpTitle, LPCWSTR lpText, LPCWSTR lpImagePath);
|
||||
// 创建并显示一个 Toast 通知
|
||||
// 参数1 为非必须项,这意味着可以传入 NULL 或空文本。但是建议必须填。桌面应用
|
||||
// 必须在开始菜单快捷方式储存处创建一个含有 AppUserModelID 的快捷方式才能使用 Toast 通知。而这个限制
|
||||
// 在 Windows 10 已经去除。
|
||||
// pfCallback 为点击 Toast 通知本体后触发的回调函数。注意:仅运行期才能用,且不一定会调用成功
|
||||
// pCustom 可以传入自定义内容并在回调中使用
|
||||
// lpExceptMsg 返回异常信息。获取到的指针必须由 free 释放。
|
||||
NOTICE_API HRESULT CreateToastNoticeFromXmlDocument (LPCWSTR lpIdName, LPCWSTR lpXmlString, NOTICE_ACTIVECALLBACK pfCallback, void *pCustom, LPWSTR *lpExceptMsg);
|
||||
|
||||
#ifdef _DEFAULT_INIT_VALUE_
|
||||
#undef _DEFAULT_INIT_VALUE_
|
||||
|
||||
@@ -32,9 +32,7 @@
|
||||
<CLRSupport>false</CLRSupport>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="..\packages\pugixml.1.15.0\build\native\pugixml.targets" Condition="Exists('..\packages\pugixml.1.15.0\build\native\pugixml.targets')" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="ExtensionSettings" />
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
@@ -89,19 +87,11 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="notice.h" />
|
||||
<ClInclude Include="nstring.h" />
|
||||
<ClInclude Include="raii.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="version.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\pugixml.1.15.0\build\native\pugixml.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\pugixml.1.15.0\build\native\pugixml.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -38,8 +38,8 @@
|
||||
<ClInclude Include="notice.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
<ClInclude Include="nstring.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
457
notice/nstring.h
Normal file
457
notice/nstring.h
Normal file
@@ -0,0 +1,457 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <cctype>
|
||||
namespace l0km
|
||||
{
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> inline std::basic_string<E, TR, AL> toupper (const std::basic_string <E, TR, AL> &src)
|
||||
{
|
||||
std::basic_string <E, TR, AL> dst = src;
|
||||
static const std::locale loc;
|
||||
const std::ctype <E> &ctype = std::use_facet <std::ctype <E>> (loc);
|
||||
for (typename std::basic_string <E, TR, AL>::size_type i = 0; i < src.size (); ++ i)
|
||||
{
|
||||
dst [i] = ctype.toupper (src [i]);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> inline std::basic_string <E, TR, AL> tolower (const std::basic_string <E, TR, AL> &src)
|
||||
{
|
||||
std::basic_string <E, TR, AL> dst = src;
|
||||
static const std::locale loc;
|
||||
const std::ctype <E> &ctype = std::use_facet <std::ctype <E>> (loc);
|
||||
for (typename std::basic_string <E, TR, AL>::size_type i = 0; i < src.size (); ++ i)
|
||||
{
|
||||
dst [i] = ctype.tolower (src [i]);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
inline char toupper (char ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <char>> (loc).toupper (ch);
|
||||
}
|
||||
inline char tolower (char ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <char>> (loc).tolower (ch);
|
||||
}
|
||||
inline wchar_t toupper (wchar_t ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <wchar_t>> (loc).toupper (ch);
|
||||
}
|
||||
inline wchar_t tolower (wchar_t ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <wchar_t>> (loc).tolower (ch);
|
||||
}
|
||||
inline int toupper (int ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <int>> (loc).toupper (ch);
|
||||
}
|
||||
inline int tolower (int ch)
|
||||
{
|
||||
if (ch < -1) return ch;
|
||||
static const std::locale loc;
|
||||
return std::use_facet <std::ctype <int>> (loc).tolower (ch);
|
||||
}
|
||||
}
|
||||
template <typename ct> bool is_blank (ct &ch)
|
||||
{
|
||||
return ch == ct (' ') || ch == ct ('\t') || ch == ct ('\n');
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> std::basic_string <E, TR, AL> NormalizeString (const std::basic_string <E, TR, AL> &str, bool upper = false, bool includemidblank = false)
|
||||
{
|
||||
typedef std::basic_string <E, TR, AL> string_type;
|
||||
string_type result;
|
||||
if (str.empty ()) return result;
|
||||
auto begin_it = str.begin ();
|
||||
auto end_it = str.end ();
|
||||
while (begin_it != end_it && is_blank (*begin_it)) ++begin_it;
|
||||
while (end_it != begin_it && is_blank (*(end_it - 1))) --end_it;
|
||||
bool in_space = false;
|
||||
for (auto it = begin_it; it != end_it; ++ it)
|
||||
{
|
||||
if (is_blank (*it))
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (!in_space)
|
||||
{
|
||||
result.push_back (E (' '));
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back (*it);
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back (*it);
|
||||
in_space = false;
|
||||
}
|
||||
}
|
||||
if (upper) return l0km::toupper (result);
|
||||
else return l0km::tolower (result);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> bool IsNormalizeStringEquals (const std::basic_string <E, TR, AL> &l, const std::basic_string <E, TR, AL> &r, bool includemidblank = false)
|
||||
{
|
||||
auto _local_strlen = [] (const E *p) -> size_t {
|
||||
size_t cnt = 0;
|
||||
while (*(p + cnt)) { cnt ++; }
|
||||
return cnt;
|
||||
};
|
||||
const E *pl = l.c_str ();
|
||||
const E *pr = r.c_str ();
|
||||
while (*pl && is_blank (*pl)) ++ pl;
|
||||
while (*pr && is_blank (*pr)) ++ pr;
|
||||
const E *el = l.c_str () + _local_strlen (l.c_str ());
|
||||
const E *er = r.c_str () + _local_strlen (r.c_str ());
|
||||
while (el > pl && is_blank (*(el - 1))) --el;
|
||||
while (er > pr && is_blank (*(er - 1))) --er;
|
||||
while (pl < el && pr < er)
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (is_blank (*pl) && is_blank (*pr))
|
||||
{
|
||||
while (pl < el && is_blank (*pl)) ++pl;
|
||||
while (pr < er && is_blank (*pr)) ++pr;
|
||||
continue;
|
||||
}
|
||||
else if (is_blank (*pl))
|
||||
{
|
||||
while (pl < el && is_blank (*pl)) ++pl;
|
||||
continue;
|
||||
}
|
||||
else if (is_blank (*pr))
|
||||
{
|
||||
while (pr < er && is_blank (*pr)) ++pr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (l0km::tolower (*pl) != l0km::tolower (*pr)) return false;
|
||||
++ pl;
|
||||
++ pr;
|
||||
}
|
||||
while (pl < el && is_blank (*pl)) ++ pl;
|
||||
while (pr < er && is_blank (*pr)) ++ pr;
|
||||
return pl == el && pr == er;
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> int64_t NormalizeStringCompare (const std::basic_string <E, TR, AL> &l, const std::basic_string <E, TR, AL> &r, bool includemidblank = false)
|
||||
{
|
||||
auto _local_strlen = [] (const E *p) -> size_t {
|
||||
size_t cnt = 0;
|
||||
while (*(p + cnt)) { cnt ++; }
|
||||
return cnt;
|
||||
};
|
||||
const E *pl = l.c_str ();
|
||||
const E *pr = r.c_str ();
|
||||
while (*pl && is_blank (*pl)) ++ pl;
|
||||
while (*pr && is_blank (*pr)) ++ pr;
|
||||
const E *el = l.c_str () + _local_strlen (l.c_str ());
|
||||
const E *er = r.c_str () + _local_strlen (r.c_str ());
|
||||
while (el > pl && is_blank (*(el - 1))) -- el;
|
||||
while (er > pr && is_blank (*(er - 1))) -- er;
|
||||
while (pl < el && pr < er)
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (is_blank (*pl) && is_blank (*pr))
|
||||
{
|
||||
while (pl < el && is_blank (*pl)) ++pl;
|
||||
while (pr < er && is_blank (*pr)) ++pr;
|
||||
continue;
|
||||
}
|
||||
else if (is_blank (*pl))
|
||||
{
|
||||
while (pl < el && is_blank (*pl)) ++pl;
|
||||
continue;
|
||||
}
|
||||
else if (is_blank (*pr))
|
||||
{
|
||||
while (pr < er && is_blank (*pr)) ++pr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
E chl = l0km::tolower (*pl);
|
||||
E chr = l0km::tolower (*pr);
|
||||
if (chl != chr) return (int64_t)chl - (int64_t)chr;
|
||||
++ pl;
|
||||
++ pr;
|
||||
}
|
||||
while (pl < el && is_blank (*pl)) ++ pl;
|
||||
while (pr < er && is_blank (*pr)) ++ pr;
|
||||
if (pl == el && pr == er) return 0;
|
||||
if (pl == el) return -1;
|
||||
if (pr == er) return 1;
|
||||
return (int64_t)l0km::tolower (*pl) - (int64_t)l0km::tolower (*pr);
|
||||
}
|
||||
template <typename CharT> bool IsNormalizeStringEquals (const CharT *l, const CharT *r, bool includemidblank = false)
|
||||
{
|
||||
if (!l || !r) return l == r;
|
||||
auto skip_blank = [] (const CharT *&p)
|
||||
{
|
||||
while (*p && is_blank (*p)) ++ p;
|
||||
};
|
||||
const CharT *p1 = l;
|
||||
const CharT *p2 = r;
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
while (*p1 && *p2)
|
||||
{
|
||||
CharT ch1 = l0km::tolower (*p1);
|
||||
CharT ch2 = l0km::tolower (*p2);
|
||||
if (ch1 != ch2) return false;
|
||||
++ p1;
|
||||
++ p2;
|
||||
if (includemidblank)
|
||||
{
|
||||
if (is_blank (*p1) || is_blank (*p2))
|
||||
{
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
}
|
||||
}
|
||||
}
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
return *p1 == 0 && *p2 == 0;
|
||||
}
|
||||
template <typename CharT> int64_t NormalizeStringCompare (const CharT *l, const CharT *r, bool includemidblank = false)
|
||||
{
|
||||
if (!l || !r) return l ? 1 : (r ? -1 : 0);
|
||||
auto skip_blank = [] (const CharT *&p)
|
||||
{
|
||||
while (*p && is_blank (*p)) ++ p;
|
||||
};
|
||||
const CharT *p1 = l;
|
||||
const CharT *p2 = r;
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
while (*p1 && *p2)
|
||||
{
|
||||
CharT ch1 = l0km::tolower (*p1);
|
||||
CharT ch2 = l0km::tolower (*p2);
|
||||
if (ch1 != ch2) return (ch1 < ch2) ? -1 : 1;
|
||||
++ p1;
|
||||
++ p2;
|
||||
if (includemidblank)
|
||||
{
|
||||
if (is_blank (*p1) || is_blank (*p2))
|
||||
{
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
}
|
||||
}
|
||||
}
|
||||
skip_blank (p1);
|
||||
skip_blank (p2);
|
||||
if (*p1 == 0 && *p2 == 0) return 0;
|
||||
if (*p1 == 0) return -1;
|
||||
return 1;
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> bool IsNormalizeStringEmpty (const std::basic_string <E, TR, AL> &str)
|
||||
{
|
||||
return IsNormalizeStringEquals (str, std::basic_string <E, TR, AL> ());
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>> std::basic_string <E, TR, AL> StringTrim (const std::basic_string <E, TR, AL> &str, bool includemidblank = false)
|
||||
{
|
||||
typedef std::basic_string <E, TR, AL> string_type;
|
||||
typedef typename string_type::size_type size_type;
|
||||
if (str.empty ()) return string_type ();
|
||||
size_type first = 0;
|
||||
size_type last = str.size ();
|
||||
while (first < last && is_blank (str [first])) ++first;
|
||||
while (last > first && is_blank (str [last - 1])) --last;
|
||||
if (first == last) return string_type ();
|
||||
string_type result;
|
||||
result.reserve (last - first);
|
||||
bool in_space = false;
|
||||
for (size_type i = first; i < last; ++ i)
|
||||
{
|
||||
if (is_blank (str [i]))
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (!in_space)
|
||||
{
|
||||
result.push_back (E (' '));
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back (str [i]);
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back (str [i]);
|
||||
in_space = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits<E>, typename AL = std::allocator <E>> size_t GetNormalizeStringLength (const std::basic_string <E, TR, AL> &str, bool includemidblank = false)
|
||||
{
|
||||
typedef typename std::basic_string <E, TR, AL>::size_type size_type;
|
||||
if (str.empty ()) return 0;
|
||||
size_type first = 0, last = str.size ();
|
||||
while (first < last && is_blank (str [first])) ++first;
|
||||
while (last > first && is_blank (str [last - 1])) --last;
|
||||
if (first == last) return 0;
|
||||
size_t length = 0;
|
||||
bool in_space = false;
|
||||
for (size_type i = first; i < last; ++i)
|
||||
{
|
||||
if (is_blank (str [i]))
|
||||
{
|
||||
if (includemidblank)
|
||||
{
|
||||
if (!in_space)
|
||||
{
|
||||
++ length;
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++ length;
|
||||
in_space = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++ length;
|
||||
in_space = false;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <typename ct, typename tr = std::char_traits <ct>, typename al = std::allocator <ct>> class basic_nstring: public std::basic_string <ct, tr, al>
|
||||
{
|
||||
bool default_upper = false, default_include_blank_in_str = false;
|
||||
public:
|
||||
using base = std::basic_string <ct, tr, al>;
|
||||
using derive = std::basic_nstring <ct, tr, al>;
|
||||
using typename base::size_type;
|
||||
using typename base::value_type;
|
||||
using base::base;
|
||||
basic_nstring (): base (), default_upper (false), default_include_blank_in_str (false) {}
|
||||
basic_nstring (const ct *pStr): base (pStr), default_upper (false), default_include_blank_in_str (false) {}
|
||||
basic_nstring (const base &str): base (str) {}
|
||||
basic_nstring (base &&str): base (std::move (str)) {}
|
||||
basic_nstring (const ct *data, size_type count): base (data, count), default_upper (false), default_include_blank_in_str (false) {}
|
||||
template <std::size_t N> basic_nstring (const ct (&arr) [N]) : base (arr, N) {}
|
||||
template <typename InputIt> basic_nstring (InputIt first, InputIt last): base (first, last), default_upper (false), default_include_blank_in_str (false) {}
|
||||
bool upper_default () const { return this->default_upper; }
|
||||
bool upper_default (bool value) { return this->default_upper = value; }
|
||||
bool include_blank_in_str_middle () const { return this->default_include_blank_in_str; }
|
||||
bool include_blank_in_str_middle (bool value) { return this->default_include_blank_in_str = value; }
|
||||
base normalize (bool upper, bool includemidblank) const
|
||||
{
|
||||
return NormalizeString <ct, tr, al> (*this, upper, includemidblank);
|
||||
}
|
||||
base normalize (bool upper) const
|
||||
{
|
||||
return this->normalize (upper, default_include_blank_in_str);
|
||||
}
|
||||
base normalize () const { return this->normalize (default_upper); }
|
||||
base upper (bool includemidblank) const
|
||||
{
|
||||
return NormalizeString <ct, tr, al> (*this, true, includemidblank);
|
||||
}
|
||||
base upper () const { return this->upper (default_include_blank_in_str); }
|
||||
base lower (bool includemidblank) const
|
||||
{
|
||||
return NormalizeString <ct, tr, al> (*this, false, includemidblank);
|
||||
}
|
||||
base lower () const { return this->lower (default_include_blank_in_str); }
|
||||
base trim (bool includemidblank) const
|
||||
{
|
||||
return StringTrim <ct, tr, al> (*this, includemidblank);
|
||||
}
|
||||
base trim () const { return this->trim (default_include_blank_in_str); }
|
||||
size_t length (bool includemidblank) const { return GetNormalizeStringLength (*this, includemidblank); }
|
||||
size_t length () const { return length (default_include_blank_in_str); }
|
||||
bool empty () const
|
||||
{
|
||||
return IsNormalizeStringEmpty (*this);
|
||||
}
|
||||
bool equals (const base &another, bool includemidblank) const
|
||||
{
|
||||
return IsNormalizeStringEquals <ct, tr, al> (*this, another, includemidblank);
|
||||
}
|
||||
bool equals (const base &another) const { return equals (another, default_include_blank_in_str); }
|
||||
int64_t compare (const base &another, bool includemidblank) const
|
||||
{
|
||||
return NormalizeStringCompare <ct, tr, al> (*this, another, includemidblank);
|
||||
}
|
||||
int64_t compare (const base &another) const { return compare (another, default_include_blank_in_str); }
|
||||
base &string () { return *this; }
|
||||
base to_string (bool upper, bool includemidblank) const { return this->normalize (upper, includemidblank); }
|
||||
base to_string (bool upper) const { return this->normalize (upper, default_include_blank_in_str); }
|
||||
base to_string () const { return this->normalize (default_upper); }
|
||||
bool operator == (const base &other) const { return equals (other, false); }
|
||||
bool operator != (const base &other) const { return !equals (other, false); }
|
||||
bool operator < (const base &other) const { return compare (other, false) < 0; }
|
||||
bool operator > (const base &other) const { return compare (other, false) > 0; }
|
||||
bool operator <= (const base &other) const { return compare (other, false) <= 0; }
|
||||
bool operator >= (const base &other) const { return compare (other, false) >= 0; }
|
||||
int64_t operator - (const base &other) const { return compare (other, false); }
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static bool equals (const std::basic_string <E> &l, const std::basic_string <E> &r, bool remove_mid_blank = false)
|
||||
{
|
||||
return IsNormalizeStringEquals <E, TR, AL> (l, r, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static int64_t compare (const std::basic_string <E> &l, const std::basic_string <E> &r, bool remove_mid_blank = false)
|
||||
{
|
||||
return NormalizeStringCompare <E, TR, AL> (l, r, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_string <E, TR, AL> normalize (const std::basic_string <E> &str, bool to_upper = false, bool remove_mid_blank = false)
|
||||
{
|
||||
return NormalizeString <E, TR, AL> (str, to_upper, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_string <E, TR, AL> trim (const std::basic_string <E> &str, bool remove_mid_blank = false)
|
||||
{
|
||||
return StringTrim <E, TR, AL> (str, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static size_t length (const std::basic_string <E> &str, bool remove_mid_blank = false)
|
||||
{
|
||||
return GetNormalizeStringLength <E, TR, AL> (str, remove_mid_blank);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static bool empty (const std::basic_string <E> &str)
|
||||
{
|
||||
return IsNormalizeStringEmpty <E, TR, AL> (str);
|
||||
}
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_nstring <E, TR, AL> to_nstring (std::basic_string <E> &str) { return std::basic_nstring <E> (str); }
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_nstring <E, TR, AL> toupper (const std::basic_nstring <E, TR, AL> &str) { return l0km::toupper (str); }
|
||||
template <typename E, typename TR = std::char_traits <E>, typename AL = std::allocator <E>>
|
||||
static std::basic_nstring <E, TR, AL> tolower (const std::basic_nstring <E, TR, AL> &str) { return l0km::tolower (str); }
|
||||
};
|
||||
|
||||
typedef basic_nstring <char> nstring;
|
||||
typedef basic_nstring <wchar_t> wnstring;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="pugixml" version="1.15.0" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -28,11 +28,8 @@
|
||||
#include <shlobj.h>
|
||||
#include <propkey.h>
|
||||
#include <comdef.h>
|
||||
|
||||
#using <Windows.winmd>
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace ABI::Windows::UI::Notifications;
|
||||
using namespace ABI::Windows::Data::Xml::Dom;
|
||||
using namespace Microsoft::WRL::Wrappers;
|
||||
|
||||
#include <pugiconfig.hpp>
|
||||
#include <pugixml.hpp>
|
||||
Reference in New Issue
Block a user