From 985b6bb4902dcfa311c42ee155736f537b2e41fc Mon Sep 17 00:00:00 2001 From: Peter Repukat Date: Sun, 2 Oct 2022 02:29:37 +0200 Subject: [PATCH] Introduce GlosSIWatchdog: Restore HidHide state if GlosSITarget was force-killed --- GlosSI.sln | 16 +- GlosSITarget/AppLauncher.cpp | 60 +++-- GlosSITarget/AppLauncher.h | 4 +- GlosSITarget/HidHide.cpp | 8 +- GlosSITarget/HidHide.h | 5 + GlosSITarget/Resource.rc | 248 +----------------- GlosSITarget/SteamTarget.cpp | 1 + GlosSIWatchdog/GlosSIWatchdog.rc | 100 +++++++ GlosSIWatchdog/GlosSIWatchdog.vcxproj | 161 ++++++++++++ GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters | 38 +++ GlosSIWatchdog/main.cpp | 77 ++++++ GlosSIWatchdog/resource.h | 14 + 12 files changed, 468 insertions(+), 264 deletions(-) create mode 100644 GlosSIWatchdog/GlosSIWatchdog.rc create mode 100644 GlosSIWatchdog/GlosSIWatchdog.vcxproj create mode 100644 GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters create mode 100644 GlosSIWatchdog/main.cpp create mode 100644 GlosSIWatchdog/resource.h diff --git a/GlosSI.sln b/GlosSI.sln index 2356eb3..4be7ecb 100644 --- a/GlosSI.sln +++ b/GlosSI.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31729.503 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32922.545 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GlosSITarget", "GlosSITarget\GlosSITarget.vcxproj", "{076E263E-0687-4435-836E-8F4EF6668843}" EndProject @@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GlosSIConfig", "GlosSIConfi EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UWPOverlayEnablerDLL", "UWPOverlayEnablerDLL\UWPOverlayEnablerDLL.vcxproj", "{50212575-87E2-40AB-87EE-EAED19C8EBB2}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GlosSIWatchdog", "GlosSIWatchdog\GlosSIWatchdog.vcxproj", "{BF273B90-CB69-43C8-9AF6-F3256DAFD41E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -39,12 +41,20 @@ Global {50212575-87E2-40AB-87EE-EAED19C8EBB2}.Release|x64.Build.0 = Release|x64 {50212575-87E2-40AB-87EE-EAED19C8EBB2}.Release|x86.ActiveCfg = Release|Win32 {50212575-87E2-40AB-87EE-EAED19C8EBB2}.Release|x86.Build.0 = Release|Win32 + {BF273B90-CB69-43C8-9AF6-F3256DAFD41E}.Debug|x64.ActiveCfg = Debug|x64 + {BF273B90-CB69-43C8-9AF6-F3256DAFD41E}.Debug|x64.Build.0 = Debug|x64 + {BF273B90-CB69-43C8-9AF6-F3256DAFD41E}.Debug|x86.ActiveCfg = Debug|Win32 + {BF273B90-CB69-43C8-9AF6-F3256DAFD41E}.Debug|x86.Build.0 = Debug|Win32 + {BF273B90-CB69-43C8-9AF6-F3256DAFD41E}.Release|x64.ActiveCfg = Release|x64 + {BF273B90-CB69-43C8-9AF6-F3256DAFD41E}.Release|x64.Build.0 = Release|x64 + {BF273B90-CB69-43C8-9AF6-F3256DAFD41E}.Release|x86.ActiveCfg = Release|Win32 + {BF273B90-CB69-43C8-9AF6-F3256DAFD41E}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {789386B6-7D1E-4F9C-BF2E-9B5EDC3BB7C8} Qt5Version = 6.2.2_msvc2019_64 + SolutionGuid = {789386B6-7D1E-4F9C-BF2E-9B5EDC3BB7C8} EndGlobalSection EndGlobal diff --git a/GlosSITarget/AppLauncher.cpp b/GlosSITarget/AppLauncher.cpp index a9f3066..771ab86 100644 --- a/GlosSITarget/AppLauncher.cpp +++ b/GlosSITarget/AppLauncher.cpp @@ -34,12 +34,13 @@ limitations under the License. AppLauncher::AppLauncher( std::vector& process_hwnds, - std::function shutdown) : process_hwnds_(process_hwnds), shutdown_(std::move(shutdown)) + std::function shutdown) : shutdown_(std::move(shutdown)), process_hwnds_(process_hwnds) { #ifdef _WIN32 + spdlog::debug("Unpatching Valve CreateProcess Hooks"); + UnPatchValveHooks(); if (Settings::launch.launch) { spdlog::debug("App launch requested"); - UnPatchValveHooks(); } #endif }; @@ -111,6 +112,29 @@ void AppLauncher::close() #endif } +void AppLauncher::launchWatchdog() +{ + // wchar_t buff[MAX_PATH]; + // GetModuleFileName(GetModuleHandle(NULL), buff, MAX_PATH); + // const std::wstring glossipath(buff); + + // GetWindowsDirectory(buff, MAX_PATH); + // const std::wstring winpath(buff); + + // launchWin32App( + // (glossipath.substr(0, 1 + glossipath.find_last_of(L'\\')) + L"GlosSIWatchdog.exe"), + // L"", + // true); + + spdlog::debug("Launching GlosSIWatchdog"); + + char buff[MAX_PATH]; + GetModuleFileNameA(GetModuleHandle(NULL), buff, MAX_PATH); + const std::string glossipath(buff); + // hack to start a TRULY detached process... + system(("start " + (glossipath.substr(0, 1 + glossipath.find_last_of(L'\\')) + "GlosSIWatchdog.exe")).data()); +} + #ifdef _WIN32 bool AppLauncher::IsProcessRunning(DWORD pid) { @@ -180,41 +204,43 @@ void AppLauncher::UnPatchValveHooks() // need to load addresses that way.. Otherwise we may land before some jumps... auto kernel32dll = GetModuleHandle(L"kernel32.dll"); if (kernel32dll) { - UnhookUtil::UnPatchHook("CreateProcessW", kernel32dll); + UnhookUtil::UnPatchHook("CreateProcessW", kernel32dll); } else { spdlog::error("kernel32.dll not found... sure..."); } } -void AppLauncher::launchWin32App(const std::wstring& path, const std::wstring& args) +void AppLauncher::launchWin32App(const std::wstring& path, const std::wstring& args, bool watchdog) { const auto native_seps_path = std::regex_replace(path, std::wregex(L"(\\/|\\\\)"), L"\\"); - //std::wstring launch_dir; - //std::wsmatch m; - //if (!std::regex_search(native_seps_path, m, std::wregex(L"(.*?\\\\)*"))) { - // spdlog::warn("Couldn't detect launch application directory"); // Shouldn't ever happen... - //} else { - // launch_dir = m[0]; - //} + // std::wstring launch_dir; + // std::wsmatch m; + // if (!std::regex_search(native_seps_path, m, std::wregex(L"(.*?\\\\)*"))) { + // spdlog::warn("Couldn't detect launch application directory"); // Shouldn't ever happen... + // } else { + // launch_dir = m[0]; + // } std::wstring args_cpy(args); spdlog::debug(L"Launching Win32App app \"{}\"; args \"{}\"", native_seps_path, args_cpy); if (CreateProcessW(native_seps_path.data(), args_cpy.data(), nullptr, nullptr, - TRUE, - 0, + watchdog ? FALSE : TRUE, + watchdog ? DETACHED_PROCESS : 0, nullptr, - nullptr, //launch_dir.empty() ? nullptr : launch_dir.data(), + nullptr, // launch_dir.empty() ? nullptr : launch_dir.data(), &info, &process_info)) { - //spdlog::info(L"Started Program: \"{}\" in directory: \"{}\"", native_seps_path, launch_dir); + // spdlog::info(L"Started Program: \"{}\" in directory: \"{}\"", native_seps_path, launch_dir); spdlog::info(L"Started Program: \"{}\"; PID: {}", native_seps_path, process_info.dwProcessId); - pids_.push_back(process_info.dwProcessId); + if (!watchdog) { + pids_.push_back(process_info.dwProcessId); + } } else { - //spdlog::error(L"Couldn't start program: \"{}\" in directory: \"{}\"", native_seps_path, launch_dir); + // spdlog::error(L"Couldn't start program: \"{}\" in directory: \"{}\"", native_seps_path, launch_dir); spdlog::error(L"Couldn't start program: \"{}\"", native_seps_path); } } diff --git a/GlosSITarget/AppLauncher.h b/GlosSITarget/AppLauncher.h index 6a0fbf0..4a0074a 100644 --- a/GlosSITarget/AppLauncher.h +++ b/GlosSITarget/AppLauncher.h @@ -34,6 +34,8 @@ class AppLauncher { void update(); void close(); + void launchWatchdog(); + private: std::function shutdown_; sf::Clock process_check_clock_; @@ -47,7 +49,7 @@ class AppLauncher { std::wstring launched_uwp_path_; static void UnPatchValveHooks(); - void launchWin32App(const std::wstring& path, const std::wstring& args = L""); + void launchWin32App(const std::wstring& path, const std::wstring& args = L"", bool watchdog = false); void launchUWPApp(LPCWSTR package_full_name, const std::wstring& args = L""); void launchURL(const std::wstring& url, const std::wstring& args = L"", const std::wstring& verb = L"open"); STARTUPINFO info{sizeof(info)}; diff --git a/GlosSITarget/HidHide.cpp b/GlosSITarget/HidHide.cpp index e0cb83f..82798d4 100644 --- a/GlosSITarget/HidHide.cpp +++ b/GlosSITarget/HidHide.cpp @@ -29,7 +29,10 @@ limitations under the License. #include // +#ifndef WATCHDOG #include "Overlay.h" +#endif + #include "Settings.h" #include @@ -71,7 +74,9 @@ void HidHide::closeCtrlDevice() void HidHide::hideDevices(const std::filesystem::path& steam_path) { steam_path_ = steam_path; +#ifndef WATCHDOG enableOverlayElement(); +#endif if (!Settings::devices.hideDevices) { spdlog::info("Hiding devices is disabled; Not un-patching valve hooks, not looking for HidHide"); return; @@ -185,7 +190,7 @@ void HidHide::UnPatchValveHooks() } } - +#ifndef WATCHDOG void HidHide::enableOverlayElement() { Overlay::AddOverlayElem([this](bool window_has_focus, ImGuiID dockspace_id) { @@ -265,6 +270,7 @@ void HidHide::enableOverlayElement() ImGui::End(); }); } +#endif std::wstring HidHide::DosDeviceForVolume(const std::wstring& volume) { diff --git a/GlosSITarget/HidHide.h b/GlosSITarget/HidHide.h index e526afa..72095b0 100644 --- a/GlosSITarget/HidHide.h +++ b/GlosSITarget/HidHide.h @@ -25,7 +25,9 @@ limitations under the License. #include #include #include +#ifndef WATCHDOG #include +#endif class HidHide { private: @@ -74,8 +76,11 @@ class HidHide { static void UnPatchValveHooks(); + +#ifndef WATCHDOG void enableOverlayElement(); sf::Clock overlay_elem_clock_; +#endif std::vector blacklisted_devices_; std::vector avail_devices_; diff --git a/GlosSITarget/Resource.rc b/GlosSITarget/Resource.rc index 7706e63..3b1b5a1 100644 --- a/GlosSITarget/Resource.rc +++ b/GlosSITarget/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,0,9,1025000308740 - PRODUCTVERSION 0,0,9,1025000308740 + FILEVERSION 0,0,9,1040000008386 + PRODUCTVERSION 0,0,9,1040000008386 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "FileDescription", "GlosSI - SteamTarget" - VALUE "FileVersion", "0.0.9.1-25-gc3b874c" + VALUE "FileVersion", "0.0.9.1-40-gdae8386" VALUE "InternalName", "GlosSITarget" - VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware" + VALUE "LegalCopyright", "Copyright (C) 2021-2022 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSITarget.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.0.9.1-25-gc3b874c" + VALUE "ProductVersion", "0.0.9.1-40-gdae8386" END END BLOCK "VarFileInfo" @@ -91,7 +91,7 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -IDI_ICON1 ICON "..\GlosSI_Icon.ico" +IDI_ICON1 ICON "..\\GlosSI_Icon.ico" #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// @@ -160,242 +160,6 @@ IDI_ICON1 ICON "..\GlosSI_Icon.ico" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/GlosSITarget/SteamTarget.cpp b/GlosSITarget/SteamTarget.cpp index 89feee7..5e05f98 100644 --- a/GlosSITarget/SteamTarget.cpp +++ b/GlosSITarget/SteamTarget.cpp @@ -74,6 +74,7 @@ Application will not function!"); if (!overlay_.expired()) overlay_.lock()->setEnabled(false); steam_overlay_present_ = true; + launcher_.launchWatchdog(); } getXBCRebindingEnabled(); diff --git a/GlosSIWatchdog/GlosSIWatchdog.rc b/GlosSIWatchdog/GlosSIWatchdog.rc new file mode 100644 index 0000000..e745c83 --- /dev/null +++ b/GlosSIWatchdog/GlosSIWatchdog.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040704b0" + BEGIN + VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" + VALUE "FileDescription", "GlosSI - SteamTarget Watchdog" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "GlosSIWatchdog" + VALUE "LegalCopyright", "Copyright (C) 2021-2022 Peter Repukat - FlatspotSoftware" + VALUE "OriginalFilename", "GlosSIWatchdog.exe" + VALUE "ProductName", "GlosSI" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x407, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/GlosSIWatchdog/GlosSIWatchdog.vcxproj b/GlosSIWatchdog/GlosSIWatchdog.vcxproj new file mode 100644 index 0000000..14ad355 --- /dev/null +++ b/GlosSIWatchdog/GlosSIWatchdog.vcxproj @@ -0,0 +1,161 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {bf273b90-cb69-43c8-9af6-f3256dafd41e} + GlosSIWatchdog + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + ..\deps\spdlog\include;..\deps\json\include;$(IncludePath) + + + ..\deps\spdlog\include;..\deps\json\include;$(IncludePath) + + + + Level3 + true + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + Level3 + true + _DEBUG;_WINDOWS;%(PreprocessorDefinitions);WATCHDOG;SPDLOG_WCHAR_TO_UTF8_SUPPORT;SPDLOG_WCHAR_FILENAMES;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING + true + stdcpp20 + + + Windows + true + hid.lib;Cfgmgr32.lib;setupapi.lib;%(AdditionalDependencies) + + + powershell.exe $(SolutionDir)version_help.ps1 + Upading version based on git;%(Outputs) + + + + + Level3 + true + true + true + NDEBUG;_WINDOWS;%(PreprocessorDefinitions);WATCHDOG;SPDLOG_WCHAR_TO_UTF8_SUPPORT;SPDLOG_WCHAR_FILENAMES;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING + true + stdcpp20 + + + Windows + true + true + true + hid.lib;Cfgmgr32.lib;setupapi.lib;%(AdditionalDependencies) + + + Upading version based on git;%(Outputs) + powershell.exe $(SolutionDir)version_help.ps1 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters b/GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters new file mode 100644 index 0000000..57db483 --- /dev/null +++ b/GlosSIWatchdog/GlosSIWatchdog.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/GlosSIWatchdog/main.cpp b/GlosSIWatchdog/main.cpp new file mode 100644 index 0000000..2de92ba --- /dev/null +++ b/GlosSIWatchdog/main.cpp @@ -0,0 +1,77 @@ +/* +Copyright 2021-2022 Peter Repukat - FlatspotSoftware + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#define NOMINMAX +#include + +#include + +#include +#include +#include + +#include "../version.hpp" +#include "../GlosSITarget/HidHide.h" + +int APIENTRY wWinMain(_In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPWSTR lpCmdLine, + _In_ int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + auto configDirPath = std::filesystem::temp_directory_path() + .parent_path() + .parent_path() + .parent_path(); + + configDirPath /= "Roaming"; + configDirPath /= "GlosSI"; + if (!std::filesystem::exists(configDirPath)) + std::filesystem::create_directories(configDirPath); + + auto logPath = configDirPath; + logPath /= "GlosSIWatchdog.log"; + const auto file_sink = std::make_shared(logPath.wstring(), true); + std::vector sinks{ file_sink }; + auto logger = std::make_shared("log", sinks.begin(), sinks.end()); + logger->set_level(spdlog::level::trace); + logger->flush_on(spdlog::level::trace); + spdlog::set_default_logger(logger); + + spdlog::info("GlosSIWatchdog loaded"); + spdlog::info("Version: {}", version::VERSION_STR); + + auto glossi_hwnd = FindWindowA(nullptr, "GlosSITarget"); + if (!glossi_hwnd) + { + spdlog::error("Couldn't find GlosSITarget window. Exiting..."); + return 1; + } + spdlog::debug("Found GlosSITarget window; Starting watch loop"); + + while (glossi_hwnd) + { + glossi_hwnd = FindWindowA(nullptr, "GlosSITarget"); + Sleep(1337); + } + spdlog::info("GlosSITarget was closed. Cleaning up..."); + HidHide hidhide; + hidhide.disableHidHide(); + + return 0; +} diff --git a/GlosSIWatchdog/resource.h b/GlosSIWatchdog/resource.h new file mode 100644 index 0000000..6c8a25b --- /dev/null +++ b/GlosSIWatchdog/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by GlosSIWatchdog.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif