From d97cfb9819377225a652b71fe7e8ad2b75fbef30 Mon Sep 17 00:00:00 2001 From: aemony Date: Sat, 3 Feb 2024 01:21:19 +0100 Subject: [PATCH] Registry optimizations --- include/stores/SKIF/custom_library.h | 3 +- include/stores/Steam/steam_library.h | 4 +- src/SKIF.cpp | 5 +- src/stores/GOG/gog_library.cpp | 95 +++++++------- src/stores/SKIF/custom_library.cpp | 186 +++++++++++---------------- src/stores/Steam/steam_library.cpp | 96 +++++++------- src/tabs/library.cpp | 6 +- 7 files changed, 184 insertions(+), 211 deletions(-) diff --git a/include/stores/SKIF/custom_library.h b/include/stores/SKIF/custom_library.h index 7ebd1312..47af2c0c 100644 --- a/include/stores/SKIF/custom_library.h +++ b/include/stores/SKIF/custom_library.h @@ -3,7 +3,6 @@ #include bool SKIF_RemoveCustomAppID (uint32_t appid); -int SKIF_AddCustomAppID (std::vector>* apps, - std::wstring name, std::wstring path, std::wstring args); +int SKIF_AddCustomAppID (std::wstring name, std::wstring path, std::wstring args); bool SKIF_ModifyCustomAppID (app_record_s* pApp, std::wstring_view path, std::wstring_view args); void SKIF_GetCustomAppIDs (std::vector > *apps); diff --git a/include/stores/Steam/steam_library.h b/include/stores/Steam/steam_library.h index 4becc5c3..c4ae9124 100644 --- a/include/stores/Steam/steam_library.h +++ b/include/stores/Steam/steam_library.h @@ -265,6 +265,6 @@ void SKIF_Steam_GetInstalledAppIDs (std::vector > *apps, std::set *apptickets); SteamId3_t SKIF_Steam_GetCurrentUser (void); DWORD SKIF_Steam_GetActiveProcess (void); -std::wstring SKIF_Steam_GetAppStateString (AppId_t appid, const wchar_t *wszStateKey); -wchar_t SKIF_Steam_GetAppStateDWORD (AppId_t appid, const wchar_t *wszStateKey, DWORD *pdwStateVal); +std::wstring SKIF_Steam_GetAppStateString (HKEY* hKey, const wchar_t *wszStateKey); +wchar_t SKIF_Steam_GetAppStateDWORD (HKEY* hKey, const wchar_t *wszStateKey, DWORD *pdwStateVal); bool SKIF_Steam_UpdateAppState (app_record_s *pApp); \ No newline at end of file diff --git a/src/SKIF.cpp b/src/SKIF.cpp index f0681893..e1c93585 100644 --- a/src/SKIF.cpp +++ b/src/SKIF.cpp @@ -446,8 +446,7 @@ SKIF_Startup_AddGame (LPWSTR lpCmdLine) cmdLineArgs = cmdLineArgs.substr(1); extern std::wstring SKIF_Util_GetProductName (const wchar_t* wszName); - extern int SKIF_AddCustomAppID (std::vector>* apps, - std::wstring name, std::wstring path, std::wstring args); + extern int SKIF_AddCustomAppID (std::wstring name, std::wstring path, std::wstring args); if (PathFileExists (cmdLine.c_str())) { @@ -456,7 +455,7 @@ SKIF_Startup_AddGame (LPWSTR lpCmdLine) if (productName == L"") productName = std::filesystem::path (cmdLine).replace_extension().filename().wstring(); - SelectNewSKIFGame = (uint32_t)SKIF_AddCustomAppID (nullptr, productName, cmdLine, cmdLineArgs); + SelectNewSKIFGame = (uint32_t)SKIF_AddCustomAppID (productName, cmdLine, cmdLineArgs); // If a running instance of SKIF already exists, terminate this one as it has served its purpose if (SelectNewSKIFGame > 0 && _Signal._RunningInstance != 0) diff --git a/src/stores/GOG/gog_library.cpp b/src/stores/GOG/gog_library.cpp index 60a2419d..7634fcf0 100644 --- a/src/stores/GOG/gog_library.cpp +++ b/src/stores/GOG/gog_library.cpp @@ -67,70 +67,77 @@ SKIF_GOG_GetInstalledAppIDs (std::vector - GOG(record.names.normal, record); + dwSize = sizeof(szData) / sizeof(WCHAR); + if (RegGetValueW (hSubKey, NULL, L"launchParam", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) + lc.launch_options = szData; - apps->emplace_back(GOG); + record.launch_configs.emplace (0, lc); - dwRead++; + record.specialk.profile_dir = lc.executable; + record.specialk.profile_dir_utf8 = SK_WideCharToUTF8(record.specialk.profile_dir); + record.specialk.injection.injection.type = InjectionType::Global; + + std::pair + GOG(record.names.normal, record); + + apps->emplace_back(GOG); + + dwRead++; + } } } + + RegCloseKey (hSubKey); } } } diff --git a/src/stores/SKIF/custom_library.cpp b/src/stores/SKIF/custom_library.cpp index 37ec3e86..c4014754 100644 --- a/src/stores/SKIF/custom_library.cpp +++ b/src/stores/SKIF/custom_library.cpp @@ -19,14 +19,12 @@ bool SKIF_RemoveCustomAppID (uint32_t appid) fileOps.fFlags = FOF_NO_UI; SHFileOperationW (&fileOps); - RegDeleteKeyW (HKEY_CURRENT_USER, SKIFRegistryKey.c_str()); + RegDeleteKeyExW (HKEY_CURRENT_USER, SKIFRegistryKey.c_str(), KEY_WOW64_64KEY, 0); return true; } -int SKIF_AddCustomAppID ( - std::vector>* apps, - std::wstring name, std::wstring path, std::wstring args) +int SKIF_AddCustomAppID (std::wstring name, std::wstring path, std::wstring args) { /* name - String -- Title/Name @@ -37,7 +35,7 @@ int SKIF_AddCustomAppID ( exeFileName - Autogenerated */ - uint32_t appId = 1; // Assume 1 in case the registry fails + DWORD appId = 1; // Assume 1 in case the registry fails HKEY hKey; DWORD32 dwData = 0; @@ -56,30 +54,31 @@ int SKIF_AddCustomAppID ( //name.erase(std::find(name.begin(), name.end(), '\0'), name.end()); //args.erase(std::find(args.begin(), args.end(), '\0'), args.end()); - if (RegCreateKeyExW (HKEY_CURRENT_USER, LR"(SOFTWARE\Kaldaien\Special K\Games\)", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) + if (RegCreateKeyExW (HKEY_CURRENT_USER, LR"(SOFTWARE\Kaldaien\Special K\Games\)", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE | KEY_WOW64_64KEY, NULL, &hKey, NULL) == ERROR_SUCCESS) { if (RegGetValueW (hKey, NULL, L"NextID", RRF_RT_REG_DWORD, NULL, &dwData, &dwSize) == ERROR_SUCCESS) appId = dwData; - std::wstring wsAppID = std::to_wstring(appId); + std::wstring wsAppID = LR"(SOFTWARE\Kaldaien\Special K\Games\)" + std::to_wstring(appId); - if (ERROR_SUCCESS != RegSetKeyValue (hKey, wsAppID.c_str(), L"ID", REG_DWORD, &appId, sizeof(DWORD))) - failed = true; - if (ERROR_SUCCESS != RegSetKeyValue (hKey, wsAppID.c_str(), L"Name", REG_SZ, (LPBYTE) name .data ( ), - (DWORD) name .size ( ) * sizeof(wchar_t))) - failed = true; - if (ERROR_SUCCESS != RegSetKeyValue (hKey, wsAppID.c_str(), L"Exe", REG_SZ, (LPBYTE) exe .data ( ), - (DWORD) exe .size ( ) * sizeof(wchar_t))) - failed = true; - if (ERROR_SUCCESS != RegSetKeyValue (hKey, wsAppID.c_str(), L"ExeFileName", REG_SZ, (LPBYTE) exeFileName.data ( ), - (DWORD) exeFileName.size ( ) * sizeof(wchar_t))) - failed = true; - if (ERROR_SUCCESS != RegSetKeyValue (hKey, wsAppID.c_str(), L"InstallDir", REG_SZ, (LPBYTE) installDir. data ( ), - (DWORD) installDir. size ( ) * sizeof(wchar_t))) - failed = true; - if (ERROR_SUCCESS != RegSetKeyValue (hKey, wsAppID.c_str(), L"LaunchOptions", REG_SZ, (LPBYTE) args. data ( ), - (DWORD) args. size ( ) * sizeof(wchar_t))) - failed = true; + HKEY hSubKey; + if (RegCreateKeyExW (HKEY_CURRENT_USER, wsAppID.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE | KEY_WOW64_64KEY, NULL, &hSubKey, NULL) == ERROR_SUCCESS) + { + if (ERROR_SUCCESS != RegSetKeyValue (hSubKey, NULL, L"ID", REG_DWORD, &appId, sizeof(DWORD))) + failed = true; + if (ERROR_SUCCESS != RegSetKeyValue (hSubKey, NULL, L"Name", REG_SZ, (LPBYTE) name .data ( ), (DWORD) name .size ( ) * sizeof(wchar_t))) + failed = true; + if (ERROR_SUCCESS != RegSetKeyValue (hSubKey, NULL, L"Exe", REG_SZ, (LPBYTE) exe .data ( ), (DWORD) exe .size ( ) * sizeof(wchar_t))) + failed = true; + if (ERROR_SUCCESS != RegSetKeyValue (hSubKey, NULL, L"ExeFileName", REG_SZ, (LPBYTE) exeFileName.data ( ), (DWORD) exeFileName.size ( ) * sizeof(wchar_t))) + failed = true; + if (ERROR_SUCCESS != RegSetKeyValue (hSubKey, NULL, L"InstallDir", REG_SZ, (LPBYTE) installDir .data ( ), (DWORD) installDir .size ( ) * sizeof(wchar_t))) + failed = true; + if (ERROR_SUCCESS != RegSetKeyValue (hSubKey, NULL, L"LaunchOptions", REG_SZ, (LPBYTE) args .data ( ), (DWORD) args .size ( ) * sizeof(wchar_t))) + failed = true; + + RegCloseKey (hSubKey); + } if (! failed) { @@ -92,57 +91,17 @@ int SKIF_AddCustomAppID ( PLOG_INFO << "LaunchOptions: " << args; PLOG_INFO << "Successfully added custom game to SKIF!"; - uint32_t appIdNext = appId + 1; + DWORD appIdNext = appId + 1; RegSetKeyValue(hKey, NULL, L"NextID", REG_DWORD, &appIdNext, sizeof(DWORD)); } RegCloseKey (hKey); } - if (! failed) - { - app_record_s record(appId); - - record.store = app_record_s::Store::Custom; - record.store_utf8 = "Custom"; - record._status.installed = true; - record.names.normal = SK_WideCharToUTF8(name); - - // Strip game names from special symbols - const char *chars = (const char *)u8"\u00A9\u00AE\u2122"; // Copyright (c), Registered (R), Trademark (TM) - for (unsigned int i = 0; i < strlen(chars); ++i) - record.names.normal.erase(std::remove(record.names.normal.begin(), record.names.normal.end(), chars[i]), record.names.normal.end()); - - // Strip null terminators - record.names.normal.erase(std::find(record.names.normal.begin(), record.names.normal.end(), '\0'), record.names.normal.end()); - record.ImGuiLabelAndID = SK_FormatString("%s (recently added)###%i-%i", record.names.normal.c_str(), (int)record.store, record.id); - record.ImGuiPushID = SK_FormatString("###%i-%i", (int)record.store, record.id); - record.install_dir = installDir; - - app_record_s::launch_config_s lc; - lc.id = 0; - lc.valid = 1; - lc.executable = exeFileName; - lc.executable_path = exe; - lc.install_dir = record.install_dir; - lc.working_dir = record.install_dir; - lc.launch_options = args; - - record.launch_configs.emplace (0, lc); - record.specialk.profile_dir = exeFileName; // THIS CAN BE WRONG!!!! - record.specialk.profile_dir_utf8 = SK_WideCharToUTF8(record.specialk.profile_dir); - record.specialk.injection.injection.type = InjectionType::Global; - - std::pair - SKIF(record.names.normal, record); - - if (apps != nullptr) - apps->emplace_back(SKIF); - - return appId; - } + if (failed) + appId = 0; - return 0; + return appId; } bool SKIF_ModifyCustomAppID (app_record_s* pApp, std::wstring_view path, std::wstring_view args) @@ -171,7 +130,7 @@ bool SKIF_ModifyCustomAppID (app_record_s* pApp, std::wstring_view path, std::ws // Strip null terminators //args.erase(std::find(args.begin(), args.end(), '\0'), args.end()); - if (RegOpenKeyExW (HKEY_CURRENT_USER, key.c_str(), 0, KEY_READ | KEY_WRITE, &hKey) == ERROR_SUCCESS) + if (RegOpenKeyExW (HKEY_CURRENT_USER, key.c_str(), 0, KEY_READ | KEY_WRITE | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS) { std::wstring wsAppID = std::to_wstring (pApp->id); @@ -221,7 +180,7 @@ void SKIF_GetCustomAppIDs (std::vector>* ap extern uint32_t SelectNewSKIFGame; /* Load custom titles from registry */ - if (RegOpenKeyExW (HKEY_CURRENT_USER, LR"(SOFTWARE\Kaldaien\Special K\Games\)", 0, KEY_READ, &hKey) == ERROR_SUCCESS) + if (RegOpenKeyExW (HKEY_CURRENT_USER, LR"(SOFTWARE\Kaldaien\Special K\Games\)", 0, KEY_READ | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS) { if (RegQueryInfoKeyW (hKey, NULL, NULL, NULL, &dwIndex, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { @@ -237,54 +196,61 @@ void SKIF_GetCustomAppIDs (std::vector>* ap if (dwResult == ERROR_SUCCESS) { - dwSize = sizeof (DWORD32); - if (RegGetValueW (hKey, szSubKey, L"ID", RRF_RT_REG_DWORD, NULL, &dwData, &dwSize) == ERROR_SUCCESS) + HKEY hSubKey = nullptr; + + if (RegOpenKeyExW (HKEY_CURRENT_USER, SK_FormatStringW (LR"(SOFTWARE\Kaldaien\Special K\Games\%ws)", szSubKey).c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &hSubKey) == ERROR_SUCCESS) { - app_record_s record (dwData); - - record.id = dwData; - record.store = app_record_s::Store::Custom; - record.store_utf8 = "Custom"; - record._status.installed = true; + dwSize = sizeof (DWORD32); + if (RegGetValueW (hSubKey, NULL, L"ID", RRF_RT_REG_DWORD, NULL, &dwData, &dwSize) == ERROR_SUCCESS) + { + app_record_s record (dwData); - dwSize = sizeof(szData) / sizeof (WCHAR); - if (RegGetValueW (hKey, szSubKey, L"Name", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) - record.names.normal = SK_WideCharToUTF8 (szData); - record.names.original = record.names.normal; + record.id = dwData; + record.store = app_record_s::Store::Custom; + record.store_utf8 = "Custom"; + record._status.installed = true; - dwSize = sizeof (szData) / sizeof (WCHAR); - if (RegGetValueW (hKey, szSubKey, L"InstallDir", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) - record.install_dir = szData; - - dwSize = sizeof (szData) / sizeof (WCHAR); - if (RegGetValueW (hKey, szSubKey, L"ExeFileName", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) // L"Exe" - { - app_record_s::launch_config_s lc; - lc.id = 0; - lc.valid = 1; - lc.executable = szData; - lc.install_dir = record.install_dir; - lc.working_dir = record.install_dir; + dwSize = sizeof(szData) / sizeof (WCHAR); + if (RegGetValueW (hSubKey, NULL, L"Name", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) + record.names.normal = SK_WideCharToUTF8 (szData); + record.names.original = record.names.normal; dwSize = sizeof (szData) / sizeof (WCHAR); - if (RegGetValueW (hKey, szSubKey, L"Exe", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) - lc.executable_path = szData; + if (RegGetValueW (hSubKey, NULL, L"InstallDir", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) + record.install_dir = szData; dwSize = sizeof (szData) / sizeof (WCHAR); - if (RegGetValueW (hKey, szSubKey, L"LaunchOptions", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) - lc.launch_options = szData; - - record.launch_configs.emplace (0, lc); - - record.specialk.profile_dir = lc.executable; - record.specialk.profile_dir_utf8 = SK_WideCharToUTF8(record.specialk.profile_dir); - record.specialk.injection.injection.type = InjectionType::Global; - - std::pair - pair (record.names.normal, record); - - apps->emplace_back (pair); + if (RegGetValueW (hSubKey, NULL, L"ExeFileName", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) // L"Exe" + { + app_record_s::launch_config_s lc; + lc.id = 0; + lc.valid = 1; + lc.executable = szData; + lc.install_dir = record.install_dir; + lc.working_dir = record.install_dir; + + dwSize = sizeof (szData) / sizeof (WCHAR); + if (RegGetValueW (hSubKey, NULL, L"Exe", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) + lc.executable_path = szData; + + dwSize = sizeof (szData) / sizeof (WCHAR); + if (RegGetValueW (hSubKey, NULL, L"LaunchOptions", RRF_RT_REG_SZ, NULL, &szData, &dwSize) == ERROR_SUCCESS) + lc.launch_options = szData; + + record.launch_configs.emplace (0, lc); + + record.specialk.profile_dir = lc.executable; + record.specialk.profile_dir_utf8 = SK_WideCharToUTF8(record.specialk.profile_dir); + record.specialk.injection.injection.type = InjectionType::Global; + + std::pair + pair (record.names.normal, record); + + apps->emplace_back (pair); + } } + + RegCloseKey (hSubKey); } } } diff --git a/src/stores/Steam/steam_library.cpp b/src/stores/Steam/steam_library.cpp index 2cee7432..cbe54f73 100644 --- a/src/stores/Steam/steam_library.cpp +++ b/src/stores/Steam/steam_library.cpp @@ -1312,20 +1312,18 @@ SKIF_Steam_GetActiveProcess (void) } std::wstring -SKIF_Steam_GetAppStateString ( AppId_t appid, - const wchar_t *wszStateKey ) +SKIF_Steam_GetAppStateString (HKEY* hKey, const wchar_t *wszStateKey) { std::wstring str ( MAX_PATH, L'\0' ); DWORD len = MAX_PATH; LSTATUS status = - RegGetValueW ( HKEY_CURRENT_USER, - SK_FormatStringW ( LR"(SOFTWARE\Valve\Steam\Apps\%lu)", - appid ).c_str (), - wszStateKey, - RRF_RT_REG_SZ, - nullptr, - str.data (), - &len ); + RegGetValueW ( *hKey, + NULL, + wszStateKey, + RRF_RT_REG_SZ, + nullptr, + str.data (), + &len ); if (status == ERROR_SUCCESS) return str; @@ -1334,20 +1332,17 @@ SKIF_Steam_GetAppStateString ( AppId_t appid, } wchar_t -SKIF_Steam_GetAppStateDWORD ( AppId_t appid, - const wchar_t *wszStateKey, - DWORD *pdwStateVal ) +SKIF_Steam_GetAppStateDWORD (HKEY* hKey, const wchar_t *wszStateKey, DWORD *pdwStateVal) { DWORD len = sizeof (DWORD); LSTATUS status = - RegGetValueW ( HKEY_CURRENT_USER, - SK_FormatStringW ( LR"(SOFTWARE\Valve\Steam\Apps\%lu)", - appid ).c_str (), - wszStateKey, - RRF_RT_DWORD, - nullptr, - pdwStateVal, - &len ); + RegGetValueW ( *hKey, + NULL, + wszStateKey, + RRF_RT_DWORD, + nullptr, + pdwStateVal, + &len ); if (status == ERROR_SUCCESS) return TRUE; @@ -1361,42 +1356,49 @@ SKIF_Steam_UpdateAppState (app_record_s *pApp) if (! pApp) return false; - SKIF_Steam_GetAppStateDWORD ( - pApp->id, L"Installed", - &pApp->_status.installed ); - - if (pApp->_status.installed != 0x0) - { pApp->_status.running = 0x0; + HKEY hKey = nullptr; + if (ERROR_SUCCESS == RegOpenKeyExW (HKEY_CURRENT_USER, SK_FormatStringW (LR"(SOFTWARE\Valve\Steam\Apps\%lu)", pApp->id).c_str(), 0, KEY_READ | KEY_WOW64_64KEY, &hKey)) + { SKIF_Steam_GetAppStateDWORD ( - pApp->id, L"Running", - &pApp->_status.running ); + &hKey, L"Installed", + &pApp->_status.installed); + + if (pApp->_status.installed != 0x0) + { pApp->_status.running = 0x0; - if (! pApp->_status.running) - { SKIF_Steam_GetAppStateDWORD ( - pApp->id, L"Updating", - &pApp->_status.updating ); - } + &hKey, L"Running", + &pApp->_status.running); - else - { - pApp->_status.updating = 0x0; - } + if (! pApp->_status.running) + { + SKIF_Steam_GetAppStateDWORD ( + &hKey, L"Updating", + &pApp->_status.updating); + } - if (pApp->names.normal.empty ()) - { - std::wstring wide_name = - SKIF_Steam_GetAppStateString ( - pApp->id, L"Name" - ); + else + { + pApp->_status.updating = 0x0; + } - if (! wide_name.empty ()) + if (pApp->names.normal.empty ()) { - pApp->names.normal = - SK_WideCharToUTF8 (wide_name); + std::wstring wide_name = + SKIF_Steam_GetAppStateString ( + &hKey, L"Name" + ); + + if (! wide_name.empty ()) + { + pApp->names.normal = + SK_WideCharToUTF8 (wide_name); + } } } + + RegCloseKey (hKey); } return true; diff --git a/src/tabs/library.cpp b/src/tabs/library.cpp index d7af93c6..8d4456f9 100644 --- a/src/tabs/library.cpp +++ b/src/tabs/library.cpp @@ -7487,13 +7487,13 @@ SKIF_UI_Tab_DrawLibrary (void) if (ImGui::Button ("Add Game", vButtonSize)) { - int newAppId = SKIF_AddCustomAppID(&g_apps, SK_UTF8ToWideChar(charName), SK_UTF8ToWideChar(charPath), SK_UTF8ToWideChar(charArgs)); + int newAppId = SKIF_AddCustomAppID (SK_UTF8ToWideChar(charName), SK_UTF8ToWideChar(charPath), SK_UTF8ToWideChar(charArgs)); if (newAppId > 0) { // Attempt to extract the icon from the given executable straight away - std::wstring SKIFCustomPath = SK_FormatStringW (LR"(%ws\Assets\Custom\%i\icon-original.png)", _path_cache.specialk_userdata, newAppId); - SKIF_Util_SaveExtractExeIcon (SK_UTF8ToWideChar(charPath), SKIFCustomPath); + //std::wstring SKIFCustomPath = SK_FormatStringW (LR"(%ws\Assets\Custom\%i\icon-original.png)", _path_cache.specialk_userdata, newAppId); + //SKIF_Util_SaveExtractExeIcon (SK_UTF8ToWideChar(charPath), SKIFCustomPath); _registry.iLastSelectedGame = newAppId; _registry.iLastSelectedStore = (int)app_record_s::Store::Custom;