diff --git a/change/react-native-windows-f1eeb076-2cad-486c-88ba-7d9f68b8fc3a.json b/change/react-native-windows-f1eeb076-2cad-486c-88ba-7d9f68b8fc3a.json new file mode 100644 index 00000000000..bb18b2b3b0e --- /dev/null +++ b/change/react-native-windows-f1eeb076-2cad-486c-88ba-7d9f68b8fc3a.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "fix outstanding modern debugger issues", + "packageName": "react-native-windows", + "email": "74712637+iamAbhi-916@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Desktop.UnitTests/UtilsTest.cpp b/vnext/Desktop.UnitTests/UtilsTest.cpp index 2899d0592e7..76ae83f5098 100644 --- a/vnext/Desktop.UnitTests/UtilsTest.cpp +++ b/vnext/Desktop.UnitTests/UtilsTest.cpp @@ -268,6 +268,85 @@ TEST_CLASS(UtilsTest) } #pragma endregion Base64 Tests + +#pragma region FormatString Tests + + TEST_METHOD(UtilsTest_StringFormat_Simple) + { + std::string result = Microsoft::React::FormatString("Hello, %s!", "World"); + Assert::AreEqual("Hello, World!", result.c_str()); + } + + TEST_METHOD(UtilsTest_StringFormat_Integer) + { + std::string result = Microsoft::React::FormatString("Port: %d", 8081); + Assert::AreEqual("Port: 8081", result.c_str()); + } + + TEST_METHOD(UtilsTest_StringFormat_Multiple) + { + std::string result = Microsoft::React::FormatString("%s:%d", "localhost", 8081); + Assert::AreEqual("localhost:8081", result.c_str()); + } + + TEST_METHOD(UtilsTest_StringFormat_Complex) + { + std::string result = Microsoft::React::FormatString( + "http://%s/%s.bundle?platform=%s&dev=%s&hot=%s", + "localhost:8081", + "index", + "windows", + "true", + "false"); + Assert::AreEqual( + "http://localhost:8081/index.bundle?platform=windows&dev=true&hot=false", + result.c_str()); + } + + TEST_METHOD(UtilsTest_StringFormat_EmptyString) + { + std::string result = Microsoft::React::FormatString(""); + Assert::AreEqual("", result.c_str()); + } + + TEST_METHOD(UtilsTest_StringFormat_NullPtr) + { + std::string result = Microsoft::React::FormatString(nullptr); + Assert::AreEqual("", result.c_str()); + } + + TEST_METHOD(UtilsTest_StringFormat_NoArgs) + { + std::string result = Microsoft::React::FormatString("no args here"); + Assert::AreEqual("no args here", result.c_str()); + } + + TEST_METHOD(UtilsTest_StringFormat_LargeString) + { + std::string longString(1000, 'a'); + std::string result = Microsoft::React::FormatString("%s", longString.c_str()); + Assert::AreEqual(longString.c_str(), result.c_str()); + } + + TEST_METHOD(UtilsTest_StringFormat_MixedTypes) + { + std::string result = Microsoft::React::FormatString( + "Int: %d, Uint: %u, Hex: %x, String: %s, Float: %.2f", + -42, + 42u, + 255, + "test", + 3.14159); + Assert::AreEqual("Int: -42, Uint: 42, Hex: ff, String: test, Float: 3.14", result.c_str()); + } + + TEST_METHOD(UtilsTest_StringFormat_SpecialChars) + { + std::string result = Microsoft::React::FormatString("100%% complete"); + Assert::AreEqual("100% complete", result.c_str()); + } + +#pragma endregion FormatString Tests }; // clang-format on diff --git a/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp b/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp index 22f895d2e90..8d42df77eae 100644 --- a/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +++ b/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp @@ -177,7 +177,6 @@ ReactInstanceWin::ReactInstanceWin( propBag = m_options.Properties, reactContext = m_reactContext]() noexcept { whenLoaded.TryCancel(); // It only has an effect if whenLoaded was not set before - Microsoft::ReactNative::HermesRuntimeHolder::storeTo(ReactPropertyBag(reactContext->Properties()), nullptr); if (onDestroyed) { onDestroyed.Get()->Invoke(reactContext); } diff --git a/vnext/Microsoft.ReactNative/Views/DevMenu.cpp b/vnext/Microsoft.ReactNative/Views/DevMenu.cpp index 598a421935f..b90c364b6e1 100644 --- a/vnext/Microsoft.ReactNative/Views/DevMenu.cpp +++ b/vnext/Microsoft.ReactNative/Views/DevMenu.cpp @@ -6,7 +6,6 @@ #include "DevMenu.h" #include -#include "Hermes/HermesSamplingProfiler.h" #include "IReactDispatcher.h" #include "Modules/DevSettingsModule.h" @@ -68,30 +67,11 @@ void ToggleFastRefresh(Mso::CntPtr const &reactContex DevSettings::Reload(React::ReactPropertyBag(reactContext->Properties())); } -winrt::fire_and_forget ToggleHermesProfiler(Mso::CntPtr const &reactContext) noexcept { - if (!Microsoft::ReactNative::HermesSamplingProfiler::IsStarted()) { - Microsoft::ReactNative::HermesSamplingProfiler::Start(reactContext); - } else { - auto traceFilePath = co_await Microsoft::ReactNative::HermesSamplingProfiler::Stop(reactContext); - auto uiDispatcher = React::implementation::ReactDispatcher::GetUIDispatcher(reactContext->Properties()); - uiDispatcher.Post([traceFilePath]() { - DataTransfer::DataPackage data; - data.SetText(winrt::to_hstring(traceFilePath)); - DataTransfer::Clipboard::SetContentWithOptions(data, nullptr); - }); - } -} - const wchar_t *FastRefreshLabel(Mso::CntPtr const &reactContext) noexcept { return Mso::React::ReactOptions::UseFastRefresh(reactContext->Properties()) ? L"Disable Fast Refresh" : L"Enable Fast Refresh"; } -const wchar_t *HermesProfilerLabel(Mso::CntPtr const &reactContext) noexcept { - return !Microsoft::ReactNative::HermesSamplingProfiler::IsStarted() ? L"Start Hermes sampling profiler" - : L"Stop and copy trace path to clipboard"; -} - struct WindowsPopupMenuDevMenu : public IDevMenu, public std::enable_shared_from_this { WindowsPopupMenuDevMenu(Mso::CntPtr const &reactContext) : m_context(reactContext) {} @@ -127,12 +107,6 @@ struct WindowsPopupMenuDevMenu : public IDevMenu, public std::enable_shared_from DevSettings::ToggleElementInspector(*context); })); - if (Mso::React::ReactOptions::JsiEngine(m_context->Properties()) == Mso::React::JSIEngine::Hermes) { - m_menu.Commands().Append(winrt::Windows::UI::Popups::UICommand( - HermesProfilerLabel(m_context), - [context = m_context](winrt::Windows::UI::Popups::IUICommand const &) { ToggleHermesProfiler(context); })); - } - m_menu.ShowAsync({0, 0}); } diff --git a/vnext/Shared/DevServerHelper.h b/vnext/Shared/DevServerHelper.h index 9fc4cbcf4d9..e61b0c89452 100644 --- a/vnext/Shared/DevServerHelper.h +++ b/vnext/Shared/DevServerHelper.h @@ -4,6 +4,7 @@ #pragma once #include +#include "Utils.h" namespace facebook { namespace react { @@ -13,13 +14,14 @@ class DevServerHelper { DevServerHelper() = default; static std::string get_WebsocketProxyUrl(const std::string &sourceBundleHost, const uint16_t sourceBundlePort) { - return string_format(WebsocketProxyUrlFormat, GetDeviceLocalHost(sourceBundleHost, sourceBundlePort).c_str()); + return Microsoft::React::FormatString( + WebsocketProxyUrlFormat, GetDeviceLocalHost(sourceBundleHost, sourceBundlePort).c_str()); } static std::string get_LaunchDevToolsCommandUrl( const std::string &sourceBundleHost, const uint16_t sourceBundlePort) { - return string_format( + return Microsoft::React::FormatString( LaunchDevToolsCommandUrlFormat, GetDeviceLocalHost(sourceBundleHost, sourceBundlePort).c_str()); } @@ -36,16 +38,17 @@ class DevServerHelper { std::string hermesBytecodeVersionQuery; if (hermesBytecodeVersion > 0) { static constexpr const char HermesBytecodeVersionQueryFormat[] = "&runtimeBytecodeVersion=%d"; - hermesBytecodeVersionQuery = string_format(HermesBytecodeVersionQueryFormat, hermesBytecodeVersion); + hermesBytecodeVersionQuery = + Microsoft::React::FormatString(HermesBytecodeVersionQueryFormat, hermesBytecodeVersion); } std::string appIdQuery; if (bundleAppId.size() > 0) { static constexpr const char AppIdQueryFormat[] = "&app=%s"; - appIdQuery = string_format(AppIdQueryFormat, bundleAppId.c_str()); + appIdQuery = Microsoft::React::FormatString(AppIdQueryFormat, bundleAppId.c_str()); } - return string_format( + return Microsoft::React::FormatString( BundleUrlFormat, GetDeviceLocalHost(sourceBundleHost, sourceBundlePort).c_str(), jsbundle.c_str(), @@ -58,17 +61,19 @@ class DevServerHelper { } static std::string get_OnChangeEndpointUrl(const std::string &sourceBundleHost, const uint16_t sourceBundlePort) { - return string_format(OnChangeEndpointUrlFormat, GetDeviceLocalHost(sourceBundleHost, sourceBundlePort).c_str()); + return Microsoft::React::FormatString( + OnChangeEndpointUrlFormat, GetDeviceLocalHost(sourceBundleHost, sourceBundlePort).c_str()); } static std::string get_PackagerConnectionUrl(const std::string &sourceBundleHost, const uint16_t sourceBundlePort) { - return string_format(PackagerConnectionUrlFormat, GetDeviceLocalHost(sourceBundleHost, sourceBundlePort).c_str()); + return Microsoft::React::FormatString( + PackagerConnectionUrlFormat, GetDeviceLocalHost(sourceBundleHost, sourceBundlePort).c_str()); } static std::string get_PackagerOpenStackFrameUrl( const std::string &sourceBundleHost, const uint16_t sourceBundlePort) { - return string_format( + return Microsoft::React::FormatString( PackagerOpenStackFrameUrlFormat, GetDeviceLocalHost(sourceBundleHost, sourceBundlePort).c_str()); } @@ -78,7 +83,7 @@ class DevServerHelper { const std::string &deviceName, const std::string &packageName, const std::string &deviceId) { - return string_format( + return Microsoft::React::FormatString( InspectorDeviceUrlFormat, GetDeviceLocalHost(packagerHost, packagerPort).c_str(), deviceName.c_str(), @@ -88,7 +93,7 @@ class DevServerHelper { static std::string get_OpenDebuggerUrl(const std::string &packagerHost, const uint16_t packagerPort, const std::string &deviceId) { - return string_format( + return Microsoft::React::FormatString( OpenDebuggerUrlFormat, GetDeviceLocalHost(packagerHost, packagerPort).c_str(), deviceId.c_str()); } @@ -97,7 +102,7 @@ class DevServerHelper { private: static std::string GetDeviceLocalHost(const std::string &sourceBundleHost, const uint16_t sourceBundlePort) { - return string_format( + return Microsoft::React::FormatString( DeviceLocalHostFormat, sourceBundleHost.empty() ? DefaultPackagerHost : sourceBundleHost.c_str(), sourceBundlePort ? sourceBundlePort : DefaultPackagerPort); @@ -118,15 +123,6 @@ class DevServerHelper { static constexpr const char PackagerOkStatus[] = "packager-status:running"; const int LongPollFailureDelayMs = 5000; - - // TODO: [vmoroz] avoid using vaiadic args for the format and move it to a utility class. - template - static std::string string_format(const char *format, Args... args) { - size_t size = snprintf(nullptr, 0, format, args...) + 1; - std::unique_ptr buf(new char[size]); - snprintf(buf.get(), size, format, args...); - return std::string(buf.get(), buf.get() + size - 1); - } }; } // namespace react diff --git a/vnext/Shared/DevSupportManager.cpp b/vnext/Shared/DevSupportManager.cpp index 6a57328a22e..ddb16934bb9 100644 --- a/vnext/Shared/DevSupportManager.cpp +++ b/vnext/Shared/DevSupportManager.cpp @@ -253,22 +253,6 @@ void DevSupportManager::StopPollingLiveReload() { m_cancellation_token = true; } -// TODO: (vmoroz) Use or delete this function -void DevSupportManager::OpenDevTools(const std::string &bundleAppId) { - winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter filter; - filter.CacheControl().ReadBehavior(winrt::Windows::Web::Http::Filters::HttpCacheReadBehavior::NoCache); - winrt::Windows::Web::Http::HttpClient httpClient(filter); - // TODO: Use currently configured dev server host - winrt::Windows::Foundation::Uri uri( - Microsoft::Common::Unicode::Utf8ToUtf16(facebook::react::DevServerHelper::get_OpenDebuggerUrl( - std::string{DevServerHelper::DefaultPackagerHost}, - DevServerHelper::DefaultPackagerPort, - GetDeviceId(GetPackageName(bundleAppId))))); - - winrt::Windows::Web::Http::HttpRequestMessage request(winrt::Windows::Web::Http::HttpMethod::Post(), uri); - httpClient.SendRequestAsync(request); -} - void DevSupportManager::EnsureInspectorPackagerConnection( [[maybe_unused]] const std::string &packagerHost, [[maybe_unused]] const uint16_t packagerPort, diff --git a/vnext/Shared/DevSupportManager.h b/vnext/Shared/DevSupportManager.h index 860839ab531..216bd6c4932 100644 --- a/vnext/Shared/DevSupportManager.h +++ b/vnext/Shared/DevSupportManager.h @@ -45,7 +45,6 @@ class DevSupportManager final : public facebook::react::IDevSupportManager { const uint16_t sourceBundlePort, std::function onChangeCallback) override; virtual void StopPollingLiveReload() override; - virtual void OpenDevTools(const std::string &bundleAppId) override; virtual void EnsureInspectorPackagerConnection( const std::string &packagerHost, diff --git a/vnext/Shared/Hermes/HermesRuntimeTargetDelegate.cpp b/vnext/Shared/Hermes/HermesRuntimeTargetDelegate.cpp index 4e64a6b3e9f..2b28d08d199 100644 --- a/vnext/Shared/Hermes/HermesRuntimeTargetDelegate.cpp +++ b/vnext/Shared/Hermes/HermesRuntimeTargetDelegate.cpp @@ -15,6 +15,7 @@ #include "HermesRuntimeTargetDelegate.h" #include +#include #include #include "HermesRuntimeAgentDelegate.h" @@ -268,7 +269,10 @@ tracing::RuntimeSamplingProfile HermesRuntimeTargetDelegate::collectSamplingProf // Return the complete profile with samples. Wrap the raw profile since it owns the strings. return tracing::RuntimeSamplingProfile( - "Hermes", 1234, std::move(readerState.samples), std::make_unique(std::move(profile))); + "Hermes", + GetCurrentProcessId(), + std::move(readerState.samples), + std::make_unique(std::move(profile))); } } // namespace Microsoft::ReactNative diff --git a/vnext/Shared/Hermes/HermesSamplingProfiler.cpp b/vnext/Shared/Hermes/HermesSamplingProfiler.cpp deleted file mode 100644 index d2fddb83334..00000000000 --- a/vnext/Shared/Hermes/HermesSamplingProfiler.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#include "pch.h" - -#include -#include -#include - -#include "HermesRuntimeHolder.h" -#include "HermesSamplingProfiler.h" -#include "IReactDispatcher.h" -#include "ReactPropertyBag.h" -#include "Utils.h" - -using namespace facebook::react; -using namespace winrt::Microsoft::ReactNative; -using namespace winrt::Windows::Foundation; - -namespace Microsoft::ReactNative { - -namespace { - -// Implements an awaiter for Mso::DispatchQueue -auto resume_in_dispatcher(const IReactDispatcher &dispatcher) noexcept { - struct awaitable { - awaitable(const IReactDispatcher &dispatcher) noexcept : dispatcher_(dispatcher) {} - - bool await_ready() const noexcept { - return false; - } - - void await_resume() const noexcept {} - - void await_suspend(std::experimental::coroutine_handle<> resume) noexcept { - callback_ = [context = resume.address()]() noexcept { - std::experimental::coroutine_handle<>::from_address(context)(); - }; - dispatcher_.Post(std::move(callback_)); - } - - private: - IReactDispatcher dispatcher_; - ReactDispatcherCallback callback_; - }; - - return awaitable{dispatcher}; -} - -IAsyncOperation getTraceFilePath() noexcept { - winrt::hstring hermesDataPath = co_await Microsoft::React::getApplicationDataPath(L"Hermes"); - std::wostringstream os; - auto now = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) - .count(); - - os << hermesDataPath.c_str() << L"\\cpu_" << now << L".cpuprofile"; - co_return winrt::hstring(os.view()); -} - -} // namespace - -std::atomic_bool HermesSamplingProfiler::s_isStarted{false}; -winrt::hstring HermesSamplingProfiler::s_lastTraceFilePath; - -winrt::hstring HermesSamplingProfiler::GetLastTraceFilePath() noexcept { - return s_lastTraceFilePath; -} - -winrt::fire_and_forget HermesSamplingProfiler::Start( - Mso::CntPtr const &reactContext) noexcept { - bool expectedIsStarted = false; - if (s_isStarted.compare_exchange_strong(expectedIsStarted, true)) { - IReactDispatcher jsDispatcher = implementation::ReactDispatcher::GetJSDispatcher(reactContext->Properties()); - ReactPropertyBag propertyBag = ReactPropertyBag(reactContext->Properties()); - - co_await resume_in_dispatcher(jsDispatcher); - std::shared_ptr hermesRuntimeHolder = HermesRuntimeHolder::loadFrom(propertyBag); - hermesRuntimeHolder->addToProfiling(); - - co_await winrt::resume_background(); - HermesRuntimeHolder::enableSamplingProfiler(); - } - - co_return; -} - -IAsyncOperation HermesSamplingProfiler::Stop( - Mso::CntPtr const &reactContext) noexcept { - bool expectedIsStarted = true; - if (s_isStarted.compare_exchange_strong(expectedIsStarted, false)) { - IReactDispatcher jsDispatcher = implementation::ReactDispatcher::GetJSDispatcher(reactContext->Properties()); - ReactPropertyBag propertyBag = ReactPropertyBag(reactContext->Properties()); - - co_await winrt::resume_background(); - HermesRuntimeHolder::disableSamplingProfiler(); - - s_lastTraceFilePath = co_await getTraceFilePath(); - HermesRuntimeHolder::dumpSampledTraceToFile(winrt::to_string(s_lastTraceFilePath)); - - co_await resume_in_dispatcher(jsDispatcher); - std::shared_ptr hermesRuntimeHolder = HermesRuntimeHolder::loadFrom(propertyBag); - hermesRuntimeHolder->removeFromProfiling(); - - co_await winrt::resume_background(); - } - - co_return s_lastTraceFilePath; -} - -bool HermesSamplingProfiler::IsStarted() noexcept { - return s_isStarted.load(); -} - -} // namespace Microsoft::ReactNative diff --git a/vnext/Shared/Hermes/HermesSamplingProfiler.h b/vnext/Shared/Hermes/HermesSamplingProfiler.h deleted file mode 100644 index fa2fcaf529b..00000000000 --- a/vnext/Shared/Hermes/HermesSamplingProfiler.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -#pragma once - -#include -#include -#include -#include - -namespace Microsoft::ReactNative { - -class HermesSamplingProfiler final { - public: - static winrt::fire_and_forget Start(Mso::CntPtr const &reactContext) noexcept; - static winrt::Windows::Foundation::IAsyncOperation Stop( - Mso::CntPtr const &reactContext) noexcept; - static winrt::hstring GetLastTraceFilePath() noexcept; - static bool IsStarted() noexcept; - - private: - static std::atomic_bool s_isStarted; - static winrt::hstring s_lastTraceFilePath; -}; - -} // namespace Microsoft::ReactNative diff --git a/vnext/Shared/HermesRuntimeHolder.cpp b/vnext/Shared/HermesRuntimeHolder.cpp index 8c0b45790f1..bca82091a19 100644 --- a/vnext/Shared/HermesRuntimeHolder.cpp +++ b/vnext/Shared/HermesRuntimeHolder.cpp @@ -319,37 +319,6 @@ void HermesRuntimeHolder::crashHandler(int fileDescriptor) noexcept { CRASH_ON_ERROR(getHermesApi().hermes_dump_crash_data(m_runtime, fileDescriptor)); } -std::shared_ptr HermesRuntimeHolder::loadFrom( - React::ReactPropertyBag const &propertyBag) noexcept { - return *(propertyBag.Get(HermesRuntimeHolderProperty())); -} - -void HermesRuntimeHolder::storeTo( - React::ReactPropertyBag const &propertyBag, - std::shared_ptr const &holder) noexcept { - propertyBag.Set(HermesRuntimeHolderProperty(), holder); -} - -void HermesRuntimeHolder::addToProfiling() const noexcept { - CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_add(m_runtime)); -} - -void HermesRuntimeHolder::removeFromProfiling() const noexcept { - CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_remove(m_runtime)); -} - -/*static*/ void HermesRuntimeHolder::enableSamplingProfiler() noexcept { - CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_enable()); -} - -/*static*/ void HermesRuntimeHolder::disableSamplingProfiler() noexcept { - CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_disable()); -} - -/*static*/ void HermesRuntimeHolder::dumpSampledTraceToFile(const std::string &fileName) noexcept { - CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_dump_to_file(fileName.c_str())); -} - hermes_runtime HermesRuntimeHolder::getHermesRuntime() noexcept { return reinterpret_cast(m_runtime); } diff --git a/vnext/Shared/HermesRuntimeHolder.h b/vnext/Shared/HermesRuntimeHolder.h index d30f4b8ac23..b7111cfde67 100644 --- a/vnext/Shared/HermesRuntimeHolder.h +++ b/vnext/Shared/HermesRuntimeHolder.h @@ -231,20 +231,6 @@ class HermesRuntimeHolder : public Microsoft::JSI::RuntimeHolderLazyInit, std::shared_ptr createRuntimeTargetDelegate() override; - static std::shared_ptr loadFrom( - winrt::Microsoft::ReactNative::ReactPropertyBag const &propertyBag) noexcept; - - static void storeTo( - winrt::Microsoft::ReactNative::ReactPropertyBag const &propertyBag, - std::shared_ptr const &holder) noexcept; - - void addToProfiling() const noexcept; - void removeFromProfiling() const noexcept; - - static void enableSamplingProfiler() noexcept; - static void disableSamplingProfiler() noexcept; - static void dumpSampledTraceToFile(const std::string &fileName) noexcept; - hermes_runtime getHermesRuntime() noexcept; private: diff --git a/vnext/Shared/IDevSupportManager.h b/vnext/Shared/IDevSupportManager.h index e8ab8cc3d20..c9c2f9c7341 100644 --- a/vnext/Shared/IDevSupportManager.h +++ b/vnext/Shared/IDevSupportManager.h @@ -22,7 +22,6 @@ struct IDevSupportManager { const uint16_t sourceBundlePort, std::function onChangeCallback) = 0; virtual void StopPollingLiveReload() = 0; - virtual void OpenDevTools(const std::string &bundleAppId) = 0; virtual void EnsureInspectorPackagerConnection( const std::string &packagerHost, diff --git a/vnext/Shared/Shared.vcxitems b/vnext/Shared/Shared.vcxitems index 3568b832da0..c10a07a1cdd 100644 --- a/vnext/Shared/Shared.vcxitems +++ b/vnext/Shared/Shared.vcxitems @@ -153,7 +153,6 @@ - @@ -315,7 +314,6 @@ - diff --git a/vnext/Shared/Shared.vcxitems.filters b/vnext/Shared/Shared.vcxitems.filters index ab85279f9c2..97a569d3f85 100644 --- a/vnext/Shared/Shared.vcxitems.filters +++ b/vnext/Shared/Shared.vcxitems.filters @@ -313,9 +313,6 @@ Hermes - - Hermes - Inspector @@ -774,9 +771,6 @@ Hermes - - Hermes - Inspector diff --git a/vnext/Shared/Utils.cpp b/vnext/Shared/Utils.cpp index 79c6f3c2249..93ea7224ede 100644 --- a/vnext/Shared/Utils.cpp +++ b/vnext/Shared/Utils.cpp @@ -11,6 +11,7 @@ #include #include +#include #include using std::string; @@ -18,6 +19,31 @@ using winrt::Windows::Foundation::IAsyncOperation; namespace Microsoft::React { +std::string FormatString(const char *format, ...) { + if (format == nullptr) { + return ""; + } + + va_list args; + va_start(args, format); + + // Get required size + va_list args_copy; + va_copy(args_copy, args); + int size = vsnprintf(nullptr, 0, format, args_copy); + va_end(args_copy); + + if (size < 0) { + va_end(args); + return ""; + } + + std::string result(size, '\0'); + vsnprintf(result.data(), size + 1, format, args); + va_end(args); + return result; +} + namespace { IAsyncOperation getPackagedApplicationDataPath(const wchar_t *childFolder) { auto localFolder = winrt::Windows::Storage::ApplicationData::Current().LocalFolder(); diff --git a/vnext/Shared/Utils.h b/vnext/Shared/Utils.h index b62d7912a10..81e4e1d5576 100644 --- a/vnext/Shared/Utils.h +++ b/vnext/Shared/Utils.h @@ -22,4 +22,7 @@ struct Url { winrt::Windows::Foundation::IAsyncOperation getApplicationDataPath(const wchar_t *childfolder); +// string formatting +std::string FormatString(_Printf_format_string_ const char *format, ...); + } // namespace Microsoft::React