// priformatcli.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h" #include "priformatcli.h" #include "prifile.h" #include "typestrans.h" #include "mpstr.h" #include "nstring.h" #include "themeinfo.h" #include "localeex.h" #include "syncutil.h" #include #include #include #include #include #include const std::wstring g_swMsResUriProtocolName = L"ms-resource:"; const size_t g_cbMsResPNameLength = lstrlenW (g_swMsResUriProtocolName.c_str ()); std::wstring g_swExcept = L""; CriticalSection g_csLastErr; CriticalSection g_threadlock; CriticalSection g_iterlock; struct destruct { std::function endtask = nullptr; destruct (std::function init): endtask (init) {} ~destruct () { if (endtask) endtask (); } }; void SetPriLastError (const std::wstring &lpMsg) { CreateScopedLock (g_csLastErr); g_swExcept = lpMsg; } enum class OpenType { Unknown, IStream, Stream }; ref class PriFileInst { public: PriFile ^inst = nullptr; OpenType opentype = OpenType::Unknown; IStream *isptr = nullptr; System::IO::FileStream ^fsptr = nullptr; operator PriFile ^ () { return inst; } operator IStream * () { return isptr; } operator System::IO::FileStream ^ () { return fsptr; } explicit operator bool () { return inst && (int)opentype && ((bool)isptr ^ (fsptr != nullptr)); } operator System::IO::Stream ^ () { if (isptr) return gcnew ComStreamWrapper (ComIStreamToCliIStream (isptr)); else return fsptr; } size_t Seek (int64_t offset, System::IO::SeekOrigin origin) { if (isptr) { ULARGE_INTEGER ul; ul.QuadPart = 0; LARGE_INTEGER lo; lo.QuadPart = offset; DWORD dwOrigin = 0; switch (origin) { case System::IO::SeekOrigin::Begin: dwOrigin = STREAM_SEEK_SET; break; case System::IO::SeekOrigin::Current: dwOrigin = STREAM_SEEK_CUR; break; case System::IO::SeekOrigin::End: dwOrigin = STREAM_SEEK_END; break; default: break; } HRESULT hr = isptr->Seek (lo, dwOrigin, &ul); return ul.QuadPart; } else if (fsptr) { return fsptr->Seek (offset, origin); } throw gcnew NullReferenceException ("Error: cannot get the stream."); return 0; } !PriFileInst () { if (fsptr) { fsptr->Close (); delete fsptr; fsptr = nullptr; } if (inst) { delete inst; inst = nullptr; } } ~PriFileInst () { if (fsptr) { fsptr->Close (); delete fsptr; fsptr = nullptr; } if (inst) { delete inst; inst = nullptr; } } }; std::wstring GetStringLeft (const std::wstring &str, size_t length = 1) { std::wstring ret = L""; ret.reserve (length + 1); size_t slen = lstrlenW (str.c_str ()); for (size_t i = 0; i < length && i < slen; i ++) { ret += str.at (i); } return ret; } std::wstring GetStringRight (const std::wstring &str, size_t length = 1) { std::wstring ret = L""; ret.reserve (length + 1); size_t slen = lstrlenW (str.c_str ()); for (size_t i = ((int64_t)slen - length) < 0 ? 0 : slen - length; i < slen; i ++) ret += str.at (i); return ret; } std::string GetStringLeft (const std::string &str, size_t length = 1) { std::string ret = ""; ret.reserve (length + 1); size_t slen = strlen (str.c_str ()); for (size_t i = 0; i < length && i < slen; i ++) { ret += str.at (i); } return ret; } std::string GetStringRight (const std::string &str, size_t length = 1) { std::string ret = ""; ret.reserve (length + 1); size_t slen = strlen (str.c_str ()); for (size_t i = ((int64_t)slen - length) < 0 ? 0 : slen - length; i < slen; i ++) ret += str.at (i); return ret; } size_t KeyToPath (const std::wstring &key, std::vector &output); typedef struct _TASKITEM_SEARCH { std::wstring swKey; int iTaskType; // 0: 字符串,1: 文件路径 operator std::wstring () { return swKey; } operator LPCWSTR () { return swKey.c_str (); } operator std::wnstring () { return swKey; } void set_key (const std::wstring &value) { iTaskType = std::wnstring (GetStringLeft (std::wnstring::trim (value), g_cbMsResPNameLength)) != g_swMsResUriProtocolName; swKey = value; } bool isuri () const { return std::wnstring (GetStringLeft (std::wnstring::trim (swKey), g_cbMsResPNameLength)) == g_swMsResUriProtocolName; } bool isfulluri () const { const std::wstring root = L"//"; return std::wnstring (GetStringLeft (std::wnstring::trim (swKey), g_cbMsResPNameLength + root.length ())) == g_swMsResUriProtocolName + root; } bool isfilepath () const { return !isuri (); } bool isrelativeuri () const { return !isfulluri () && isuri (); } size_t get_path (std::vector &output) const { output.clear (); auto &path = output; KeyToPath (swKey, path); if (isrelativeuri ()) { std::wstring nopre = GetStringRight (swKey, swKey.length () - g_cbMsResPNameLength); std::wstring firstch = GetStringLeft (nopre, 1); if (firstch [0] != L'/') path.insert (path.begin (), L"resources"); } else if (isfilepath ()) path.insert (path.begin (), L"Files"); return output.size (); } _TASKITEM_SEARCH &operator = (const std::wstring &v) { set_key (v); return *this; } explicit _TASKITEM_SEARCH (const std::wstring &v, int type = -1) { if (type < 0 || type > 1) set_key (v); else { swKey = v; iTaskType = type; } } _TASKITEM_SEARCH (int type, const std::wstring &v = L"") { if (type < 0 || type > 1) set_key (v); else { swKey = v; iTaskType = type; } } _TASKITEM_SEARCH () = default; bool operator == (const _TASKITEM_SEARCH &another) const { return std::wnstring (swKey).equals (another.swKey); } bool operator < (const _TASKITEM_SEARCH &another) const { return std::wnstring (swKey).compare (another.swKey) < 0; } } TASKITEM_SEARCH; typedef struct _TASKRESULT_FIND { std::wstring swValue = L""; int iFindResult = -1; // -1 未进行查找,0:查找但未找到,1:查找且已找到 operator std::wstring () { return swValue; } operator LPCWSTR () { return swValue.c_str (); } operator std::wnstring () { return swValue; } _TASKRESULT_FIND (const std::wstring &v, int findres = -1): swValue (v), iFindResult (findres) {} _TASKRESULT_FIND (int findres, const std::wstring &v = L""): swValue (v), iFindResult (findres) {} _TASKRESULT_FIND () = default; // 是否查找到 bool is_find () const { return iFindResult > 0; } // 是否进行过查找 bool has_search () const { return iFindResult >= 0; } } TASKRESULT_FIND; typedef struct _TASKINFO_SEARCH { bool bIsRunning = false; std::map mapTasks; operator std::map () { return mapTasks; } } TASKINFO_SEARCH; size_t UriToPath (System::Uri ^uri, std::vector &output) { output.clear (); try { auto path = uri->AbsolutePath; auto arr = path->Split ('/'); for (size_t i = 0; i < arr->Length; i ++) { auto str = arr [i]; std::wnstring cppstr = MPStringToStdW (str); if (cppstr.empty ()) continue; output.push_back (cppstr); } } catch (Exception ^e) { SetPriLastError (MPStringToStdW (e->Message)); } return output.size (); } std::vector split_wcstok (const std::wstring &str, const std::wstring &delim) { std::vector result; std::wstring cpy = L"" + str; LPWSTR context = nullptr; LPWSTR token = wcstok ((LPWSTR)cpy.c_str (), delim.c_str (), &context); while (token) { result.push_back (token); token = wcstok (nullptr, delim.c_str (), &context); } return result; } std::vector VecWStringToWNString (const std::vector &vec) { std::vector wns; wns.reserve (vec.size ()); for (auto &it : vec) wns.push_back (it); return wns; } size_t KeyToPath (const std::wstring &key, std::vector &output) { output.clear (); try { // 1: 字符串,0: 文件路径 int iTaskType = std::wnstring (GetStringLeft (key, g_cbMsResPNameLength)) == g_swMsResUriProtocolName; if (iTaskType) { Uri ^uri = gcnew Uri (CStringToMPString (key.c_str ())); size_t ret = UriToPath (uri, output); delete uri; uri = nullptr; return ret; } else { auto arr = split_wcstok (key, L"\\"); for (auto &it : arr) { if (std::wnstring (it).empty ()) continue; else output.push_back (it); } } } catch (Exception ^e) { auto arr = split_wcstok (key, L"\\"); for (auto &it : arr) { if (std::wnstring (it).empty ()) continue; else output.push_back (it); } } return output.size (); } size_t KeyToPath (const TASKITEM_SEARCH &key, std::vector &output) { return KeyToPath (key.swKey, output); } bool PathEquals (const std::vector &left, const std::vector &right) { if (left.size () != right.size ()) return false; try { for (size_t i = 0; i < left.size () && i < right.size (); i ++) { if (left.at (i) != right.at (i)) return false; } return true; } catch (const std::exception &e) {} return false; } std::map g_tasklist; PCSPRIFILE CreatePriFileInstanceFromStream (PCOISTREAM pStream) { if (!pStream) return nullptr; try { HRESULT hr = S_OK; if (pStream) hr = ((IStream *)pStream)->Seek (LARGE_INTEGER {}, STREAM_SEEK_SET, nullptr); auto pri = PriFile::Parse (ComIStreamToCliIStream (reinterpret_cast (pStream))); PriFileInst ^inst = gcnew PriFileInst (); inst->inst = pri; inst->opentype = OpenType::IStream; inst->isptr = reinterpret_cast (pStream); auto handle = System::Runtime::InteropServices::GCHandle::Alloc (inst); IntPtr token = System::Runtime::InteropServices::GCHandle::ToIntPtr (handle); return reinterpret_cast (token.ToPointer ()); } catch (System::Exception ^e) { SetPriLastError (MPStringToStdW (e->Message)); } return nullptr; } PCSPRIFILE CreatePriFileInstanceFromPath (LPCWSTR lpswFilePath) { if (!lpswFilePath) return nullptr; if (!*lpswFilePath) return nullptr; try { auto fstream = System::IO::File::OpenRead (CStringToMPString (lpswFilePath ? lpswFilePath : L"")); auto pri = PriFile::Parse (fstream); PriFileInst ^inst = gcnew PriFileInst (); inst->inst = pri; inst->opentype = OpenType::Stream; inst->fsptr = fstream; auto handle = System::Runtime::InteropServices::GCHandle::Alloc (inst); IntPtr token = System::Runtime::InteropServices::GCHandle::ToIntPtr (handle); return reinterpret_cast (token.ToPointer ()); } catch (System::Exception ^e) { SetPriLastError (MPStringToStdW (e->Message)); } return nullptr; } void DestroyPriFileInstance (PCSPRIFILE pFilePri) { if (!pFilePri) return; try { if (g_tasklist.find (pFilePri) != g_tasklist.end ()) { g_tasklist [pFilePri].bIsRunning = false; g_tasklist.erase (pFilePri); } IntPtr handlePtr = IntPtr (pFilePri); System::Runtime::InteropServices::GCHandle handle = System::Runtime::InteropServices::GCHandle::FromIntPtr (handlePtr); PriFileInst ^inst = safe_cast (handle.Target); delete inst; handle.Free (); System::GC::Collect (); System::GC::WaitForPendingFinalizers (); System::GC::Collect (); } catch (System::Exception ^e) { SetPriLastError (MPStringToStdW (e->Message)); } } LPCWSTR PriFileGetLastError () { CreateScopedLock (g_csLastErr); return g_swExcept.c_str (); } enum class Contrast { None, White, Black, High, Low }; struct candidate_value { int type; // 1:语言;2:缩放和对比度;0:未知 std::wstring value; union restitem { struct // type==1 { std::wstring languages; }; struct // type==2 { uint32_t scale; Contrast contrast; }; struct // type==0 { std::wstring not_support_restrict; }; restitem () {} // 不做初始化,由外层控制构造 ~restitem () {} // 不自动析构,由外层控制析构 } restitems; candidate_value (const std::wstring &val, const std::wstring &lang): type (1), value (val) { new(&restitems.languages) std::wstring (lang); } candidate_value (const std::wstring &val, uint32_t scale, Contrast contrast = Contrast::None): type (2), value (val) { restitems.scale = scale; restitems.contrast = contrast; } candidate_value (const std::wstring &val): type (0), value (val) { new (&restitems.not_support_restrict) std::wstring (L""); } candidate_value (const candidate_value &other): type (other.type), value (other.value) { if (type == 1) new(&restitems.languages) std::wstring (other.restitems.languages); else if (type == 2) { restitems.scale = other.restitems.scale; restitems.contrast = other.restitems.contrast; } else new (&restitems.not_support_restrict) std::wstring (other.restitems.not_support_restrict); } candidate_value &operator = (const candidate_value &other) { if (this != &other) { this->~candidate_value (); // 先析构旧内容 new (this) candidate_value (other); // 再调用拷贝构造 } return *this; } ~candidate_value () { if (type == 1) restitems.languages.~basic_string (); else if (type == 0) restitems.not_support_restrict.~basic_string (); } std::wstring get_language () const { return type == 1 ? restitems.languages : L""; } uint32_t get_scale () const { return type == 2 ? restitems.scale : 0; } Contrast get_contrast () const { return type == 2 ? restitems.contrast : Contrast::None; } }; std::wstring GetStringValueByLocale (std::vector &stringcand, const std::wstring &llc) { for (auto &it : stringcand) { if (LocaleNameCompare (it.get_language (), llc)) return it.value; } std::vector scrc; for (auto &it : stringcand) { std::wstring rc; scrc.push_back (rc = GetLocaleRestrictedCodeFromLcidW (LocaleCodeToLcidW (it.get_language ()))); if (LocaleNameCompare (rc, llc)) return it.value; } std::wstring lrc = GetLocaleRestrictedCodeFromLcidW (LocaleCodeToLcidW (llc)); for (size_t i = 0; i < stringcand.size (); i ++) { auto &rc = scrc.at (i); auto &it = stringcand.at (i); if (LocaleNameCompare (rc, llc)) return it.value; } return L""; } std::wstring GetSuitableStringValue (std::vector &stringcand) { std::wstring ret = GetStringValueByLocale (stringcand, GetComputerLocaleCodeW ()); if (ret.empty () || std::wnstring::trim (ret).length () == 0) ret = GetStringValueByLocale (stringcand, L"en-US"); if (ret.empty () || std::wnstring::trim (ret).length () == 0) { for (auto &it : stringcand) return it.value; } return ret; } std::wstring GetSuitablePathValueByDPI (std::vector &pathcand) { std::sort (pathcand.begin (), pathcand.end (), [] (const candidate_value &v1, const candidate_value &v2) { return v1.get_scale () < v2.get_scale (); }); if (pathcand.empty ()) return L""; uint32_t nowdpi = GetDPI (); for (auto &cv : pathcand) if (cv.get_scale () >= nowdpi) return cv.value; return pathcand.back ().value; } std::wstring GetSuitablePathValue (std::vector &pathcand) { std::vector contrasted; for (auto &it : pathcand) if (it.get_contrast () == Contrast::None) contrasted.emplace_back (it); std::wstring ret = GetSuitablePathValueByDPI (contrasted); if (std::wnstring (ret).empty ()) { contrasted.clear (); for (auto &it: pathcand) if (it.get_contrast () == Contrast::White) contrasted.emplace_back (it); ret = GetSuitablePathValueByDPI (contrasted); } if (std::wnstring (ret).empty ()) { contrasted.clear (); for (auto &it : pathcand) if (it.get_contrast () == Contrast::Black) contrasted.emplace_back (it); ret = GetSuitablePathValueByDPI (contrasted); } if (std::wnstring (ret).empty ()) { contrasted.clear (); for (auto &it : pathcand) contrasted.emplace_back (it); ret = GetSuitablePathValueByDPI (contrasted); } return ret; } void PriFileIterateTask (PCSPRIFILE pFilePri) { CreateScopedLock (g_threadlock); if (g_tasklist.find (pFilePri) == g_tasklist.end ()) g_tasklist [pFilePri] = TASKINFO_SEARCH (); try { g_tasklist.at (pFilePri); } catch (const std::exception &e) { return; } auto &task = g_tasklist.at (pFilePri); if (task.bIsRunning == false) task.bIsRunning = true; else return; destruct endt ([&task] () { task.bIsRunning = false; }); auto &taskitems = task.mapTasks; IntPtr handlePtr = IntPtr (pFilePri); System::Runtime::InteropServices::GCHandle handle = System::Runtime::InteropServices::GCHandle::FromIntPtr (handlePtr); auto pri = safe_cast (handle.Target); auto &priFile = pri; auto resmapsect = pri->inst->PriDescriptorSection->ResourceMapSections; bool isallsearched = true; size_t allitemslen = 0; std::map mapitemscnt; auto begtime = System::DateTime::Now; SearchLoop: allitemslen = 0; for (size_t i = 0; i < resmapsect->Count; i ++) { CreateScopedLock (g_iterlock); auto resourceMapSectionRef = resmapsect [i]; auto resourceMapSection = pri->inst->GetSectionByRef (resourceMapSectionRef); if (resourceMapSection->HierarchicalSchemaReference != nullptr) continue; auto decisionInfoSection = pri->inst->GetSectionByRef (resourceMapSection->DecisionInfoSection); for each (auto candidateSet in resourceMapSection->CandidateSets->Values) { // 超时强制退出(也就没有遍及的必要了) if ((System::DateTime::Now - begtime).TotalSeconds > 20) return; allitemslen ++; auto item = pri->inst->GetResourceMapItemByRef (candidateSet->ResourceMapItem); std::wstring itemfullname = MPStringToStdW (item->FullName); std::vector itempath; { auto ips = split_wcstok (itemfullname, L"\\"); for (auto &it : ips) { if (std::wnstring::empty (it)) continue; itempath.push_back (it); } } bool willcont = true; TASKITEM_SEARCH *taskkey = nullptr; for (auto &it : taskitems) { auto &key = it.first; auto &value = it.second; mapitemscnt [key.swKey] ++; if (value.has_search ()) continue; std::vector namepath; key.get_path (namepath); // KeyToPath (key, namepath); if (PathEquals (itempath, namepath)) { taskkey = (TASKITEM_SEARCH *)&key; willcont = false; break; } } if (willcont) continue; auto keyname = taskkey->swKey; auto keytype = taskkey->iTaskType; std::vector cands; for each (auto candidate in candidateSet->Candidates) { System::String ^value = nullptr; if (candidate->SourceFile.HasValue) { // 内嵌资源,暂无法处理 // value = System::String::Format ("", pri->GetReferencedFileByRef (candidate->SourceFile.Value)->FullName); value = pri->inst->GetReferencedFileByRef (candidate->SourceFile.Value)->FullName; } else { ByteSpan ^byteSpan = nullptr; if (candidate->DataItem.HasValue) byteSpan = priFile->inst->GetDataItemByRef (candidate->DataItem.Value); else byteSpan = candidate->Data.Value; pri->Seek (byteSpan->Offset, System::IO::SeekOrigin::Begin); auto binaryReader = gcnew System::IO::BinaryReader (pri, System::Text::Encoding::Default, true); auto data = binaryReader->ReadBytes ((int)byteSpan->Length); switch (candidate->Type) { case ResourceValueType::AsciiPath: case ResourceValueType::AsciiString: value = System::Text::Encoding::ASCII->GetString (data)->TrimEnd ('\0'); break; case ResourceValueType::Utf8Path: case ResourceValueType::Utf8String: value = System::Text::Encoding::UTF8->GetString (data)->TrimEnd ('\0'); break; case ResourceValueType::Path: case ResourceValueType::String: value = System::Text::Encoding::Unicode->GetString (data)->TrimEnd ('\0'); break; case ResourceValueType::EmbeddedData: value = Convert::ToBase64String (data); break; } delete binaryReader; delete data; binaryReader = nullptr; data = nullptr; } auto qualifierSet = decisionInfoSection->QualifierSets [candidate->QualifierSet]; auto qualis = gcnew System::Collections::Generic::Dictionary (); for each (auto quali in qualifierSet->Qualifiers) { auto type = quali->Type; auto value = quali->Value; qualis->Add (type, value); } if (qualis->ContainsKey (QualifierType::Language)) { cands.push_back (candidate_value (MPStringToStdW (value ? value : System::String::Empty), MPStringToStdW (qualis [QualifierType::Language]->ToString ()))); } else if (qualis->ContainsKey (QualifierType::Scale)) { if (qualis->ContainsKey (QualifierType::Contrast)) { Contrast ct = Contrast::None; auto contstr = std::wnstring (MPStringToStdW (qualis [QualifierType::Contrast]->ToString ()->Trim ()->ToUpper ())); if (contstr.equals (L"WHITE")) ct = Contrast::White; else if (contstr.equals (L"BLACK")) ct = Contrast::Black; else if (contstr.equals (L"HIGH")) ct = Contrast::High; cands.push_back (candidate_value ( MPStringToStdW (value ? value : System::String::Empty), Convert::ToUInt32 (qualis [QualifierType::Scale]), ct )); } else { cands.push_back (candidate_value ( MPStringToStdW (value ? value : System::String::Empty), Convert::ToUInt32 (qualis [QualifierType::Scale]) )); } } else cands.push_back (candidate_value (MPStringToStdW (value ? value : System::String::Empty))); delete qualis; qualis = nullptr; } switch (keytype) { case 0: { TASKRESULT_FIND tfind; tfind.iFindResult = 1; tfind.swValue = GetSuitableStringValue (cands); taskitems [*taskkey] = tfind; } break; case 1: { TASKRESULT_FIND tfind; tfind.iFindResult = 1; tfind.swValue = GetSuitablePathValue (cands); taskitems [*taskkey] = tfind; } break; default: { TASKRESULT_FIND tfind; tfind.iFindResult = 0; try { tfind.swValue = cands.at (0).value; } catch (const std::exception &e) {} taskitems [*taskkey] = tfind; } break; } } // delete resourceMapSection; resourceMapSection = nullptr; } isallsearched = true; for (auto &it : mapitemscnt) { auto &result = taskitems [TASKITEM_SEARCH (it.first)]; isallsearched = isallsearched && (it.second >= allitemslen && result.has_search ()); if (it.second >= allitemslen) { if (!result.has_search ()) result.iFindResult = 0; } it.second = 0; } if (!isallsearched) { for (auto &it : mapitemscnt) it.second = 0; goto SearchLoop; } // task.bIsRunning = false; } void PriFileIterateTaskCli (Object^ pFilePriObj) { if (pFilePriObj == nullptr) return; IntPtr ptr = safe_cast (pFilePriObj); PCSPRIFILE pFilePri = (PCSPRIFILE)ptr.ToPointer (); PriFileIterateTask (pFilePri); } void AddPriResourceName (PCSPRIFILE pFilePri, const std::vector &urilist) { if (!pFilePri) return; if (!urilist.size ()) return; try { g_tasklist.at (pFilePri); } catch (const std::exception &e) { g_tasklist [pFilePri] = TASKINFO_SEARCH (); } auto &task = g_tasklist.at (pFilePri); bool isallfined = true; { CreateScopedLock (g_threadlock); CreateScopedLock (g_iterlock); for (auto &it : urilist) { if (it.empty ()) continue; try { if (task.mapTasks [TASKITEM_SEARCH (it)].has_search ()) { isallfined = isallfined && true; continue; } else isallfined = isallfined && false; } catch (const std::exception &e) { task.mapTasks [TASKITEM_SEARCH (it)] = TASKRESULT_FIND (); isallfined = isallfined && false; } } } if (isallfined) return; // while (task.bIsRunning) { Sleep (200); } System::Threading::Thread ^t = nullptr; if (!task.bIsRunning) { // task.bIsRunning = true; t = gcnew System::Threading::Thread (gcnew System::Threading::ParameterizedThreadStart (PriFileIterateTaskCli)); t->IsBackground = true; t->Start (IntPtr (pFilePri)); } } void FindPriResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hUriList) { if (!pFilePri) return; if (!hUriList || !hUriList->dwLength) return; std::vector list; for (size_t i = 0; i < hUriList->dwLength; i ++) { auto &str = hUriList->aswArray [i]; if (!str || !*str) continue; std::wnstring wstr (str); if (wstr.empty ()) continue; list.emplace_back (wstr); } AddPriResourceName (pFilePri, list); } void FindPriStringResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hUriList) { FindPriResource (pFilePri, hUriList); } void FindPriPathResource (PCSPRIFILE pFilePri, HLPCWSTRLIST hPathList) { FindPriResource (pFilePri, hPathList); } LPWSTR GetPriResource (PCSPRIFILE pFilePri, LPCWSTR lpswResId) { if (!pFilePri || !lpswResId || !*lpswResId) return nullptr; try { g_tasklist.at (pFilePri); } catch (const std::exception &e) { g_tasklist [pFilePri]; } auto &task = g_tasklist.at (pFilePri); { auto &result = task.mapTasks [TASKITEM_SEARCH (lpswResId)]; if (result.has_search ()) return _wcsdup (result.swValue.c_str ()); } BYTE buf [sizeof (LPCWSTRLIST) + sizeof (LPCWSTR)] = {0}; HLPCWSTRLIST hStrList = (HLPCWSTRLIST)buf; hStrList->dwLength = 1; hStrList->aswArray [0] = lpswResId; FindPriResource (pFilePri, hStrList); while (task.bIsRunning) { Sleep (200); } try { auto item = task.mapTasks.at (TASKITEM_SEARCH (lpswResId)); if (!item.has_search ()) return GetPriResource (pFilePri, lpswResId); return _wcsdup (item.swValue.c_str ()); } catch (const std::exception &e) { SetPriLastError (StringToWString (e.what () ? e.what () : "Error: cannot find the resource.")); return nullptr; } } LPWSTR GetPriStringResource (PCSPRIFILE pFilePri, LPCWSTR lpswUri) { return GetPriResource (pFilePri, lpswUri); } LPWSTR GetPriPathResource (PCSPRIFILE pFilePri, LPCWSTR lpswFilePath) { return GetPriResource (pFilePri, lpswFilePath); } void ClearPriCacheData () { g_tasklist.clear (); } BOOL IsMsResourcePrefix (LPCWSTR pResName) { return std::wnstring (GetStringLeft (std::wnstring::trim (std::wstring (pResName ? pResName : L"")), g_cbMsResPNameLength)) == g_swMsResUriProtocolName; } BOOL IsMsResourceUriFull (LPCWSTR pResUri) { const std::wstring root = L"//"; return std::wnstring (GetStringLeft (std::wnstring::trim (std::wstring (pResUri)), g_cbMsResPNameLength + root.length ())) == g_swMsResUriProtocolName + root; } BOOL IsMsResourceUri (LPCWSTR pResUri) { if (!IsMsResourcePrefix (pResUri)) return false; try { Uri ^uri = gcnew Uri (gcnew String (pResUri ? pResUri : L"")); delete uri; } catch (Exception ^e) { return false; } return true; }