Merge pull request #1 from microsoft/master

Sync with master
This commit is contained in:
Chris Davis 2019-11-08 12:05:57 -08:00 committed by GitHub
commit b9b60a1346
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 349 additions and 213 deletions

View File

@ -6,7 +6,7 @@
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [ ] Closes #xxx
* [] Applies to #xxx
* [] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/PowerToys) and sign the CLA
* [] Tests added/passed
* [] Requires documentation to be updated

View File

@ -6,7 +6,6 @@ The list below is the set of utilities we're considering and the rough priority
* Maximize to new desktop widget - The MTND widget shows a pop-up button when a user hovers over the maximize / restore button on any window. Clicking it creates a new desktop, sends the app to that desktop and maximizes the app on the new desktop.
* [Process terminate tool](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/Terminate%20Spec.md)
* [Batch file renamer](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/File%20Classification%20Spec.md)
* [Animated gif screen recorder](https://github.com/indierawk2k2/PowerToys-1/blob/master/specs/GIF%20Maker%20Spec.md)
## Backlog

View File

@ -98,6 +98,7 @@
<ClInclude Include="d2d_window.h" />
<ClInclude Include="dpi_aware.h" />
<ClInclude Include="monitors.h" />
<ClInclude Include="on_thread_executor.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="settings_helpers.h" />
<ClInclude Include="settings_objects.h" />
@ -117,6 +118,7 @@
<ClCompile Include="d2d_window.cpp" />
<ClCompile Include="dpi_aware.cpp" />
<ClCompile Include="monitors.cpp" />
<ClCompile Include="on_thread_executor.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>

View File

@ -69,6 +69,9 @@
<ClInclude Include="version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="on_thread_executor.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="d2d_svg.cpp">
@ -108,5 +111,8 @@
<ClCompile Include="dpi_aware.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="on_thread_executor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -38,3 +38,7 @@ void DPIAware::Convert(HMONITOR monitor_handle, int &width, int &height) {
height = height * dpi_y / DEFAULT_DPI;
}
}
void DPIAware::EnableDPIAwarenessForThisProcess() {
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}

View File

@ -1,12 +1,11 @@
#pragma once
#include "windef.h"
class DPIAware {
private:
static const int DEFAULT_DPI = 96;
struct DPIAware {
static constexpr int DEFAULT_DPI = 96;
public:
static HRESULT GetScreenDPIForWindow(HWND hwnd, UINT & dpi_x, UINT & dpi_y);
static HRESULT GetScreenDPIForPoint(POINT p, UINT& dpi_x, UINT& dpi_y);
static void Convert(HMONITOR monitor_handle, int &width, int &height);
static void EnableDPIAwarenessForThisProcess();
};

View File

@ -0,0 +1,38 @@
#include "pch.h"
#include "on_thread_executor.h"
OnThreadExecutor::OnThreadExecutor()
:_worker_thread{[this]() { worker_thread(); }}
{}
std::future<void> OnThreadExecutor::submit(task_t task) {
auto future = task.get_future();
std::lock_guard lock{_task_mutex};
_task_queue.emplace(std::move(task));
_task_cv.notify_one();
return future;
}
void OnThreadExecutor::worker_thread() {
while(_active) {
task_t task;
{
std::unique_lock task_lock{_task_mutex};
_task_cv.wait(task_lock, [this] { return !_task_queue.empty() || !_active; });
if(!_active) {
break;
}
task = std::move(_task_queue.front());
_task_queue.pop();
}
task();
}
}
OnThreadExecutor::~OnThreadExecutor() {
_active = false;
_task_cv.notify_one();
_worker_thread.join();
}

View File

@ -0,0 +1,30 @@
#pragma once
#include <future>
#include <thread>
#include <functional>
#include <queue>
#include <atomic>
// OnThreadExecutor allows its caller to off-load some work to a persistently running background thread.
// This might come in handy if you use the API which sets thread-wide global state and the state needs
// to be isolated.
class OnThreadExecutor final {
public:
using task_t = std::packaged_task<void()>;
OnThreadExecutor();
~OnThreadExecutor();
std::future<void> submit(task_t task);
private:
void worker_thread();
std::thread _worker_thread;
std::mutex _task_mutex;
std::condition_variable _task_cv;
std::atomic_bool _active;
std::queue<std::packaged_task<void()>> _task_queue;
};

View File

@ -220,6 +220,7 @@ private:
void MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept;
void MoveSizeUpdate(POINT const& ptScreen) noexcept;
HANDLE m_movedWindow = nullptr;
winrt::com_ptr<IFancyZones> m_app;
winrt::com_ptr<IFancyZonesSettings> m_settings;
};
@ -298,6 +299,7 @@ void FancyZonesModule::MoveSizeStart(HWND window, POINT const& ptScreen) noexcep
{
if (auto monitor = MonitorFromPoint(ptScreen, MONITOR_DEFAULTTONULL))
{
m_movedWindow = window;
m_app.as<IFancyZonesCallback>()->MoveSizeStart(window, monitor, ptScreen);
}
}
@ -305,8 +307,9 @@ void FancyZonesModule::MoveSizeStart(HWND window, POINT const& ptScreen) noexcep
void FancyZonesModule::MoveSizeEnd(HWND window, POINT const& ptScreen) noexcept
{
if (IsInterestingWindow(window))
if (IsInterestingWindow(window) || (window != nullptr && window == m_movedWindow))
{
m_movedWindow = nullptr;
m_app.as<IFancyZonesCallback>()->MoveSizeEnd(window, ptScreen);
}
}

View File

@ -23,6 +23,9 @@ namespace FancyZonesEditor
/// </summary>
public partial class MainWindow : MetroWindow
{
// TODO: share the constants b/w C# Editor and FancyZoneLib
public static int MAX_ZONES = 40;
public MainWindow()
{
InitializeComponent();
@ -57,7 +60,7 @@ namespace FancyZonesEditor
private void IncrementZones_Click(object sender, RoutedEventArgs e)
{
if (_settings.ZoneCount < 40)
if (_settings.ZoneCount < MAX_ZONES)
{
_settings.ZoneCount++;
}

View File

@ -279,7 +279,7 @@ namespace FancyZonesEditor
// 1 = unique key for per-monitor settings
// 2 = layoutid used to generate current layout (used to pick the default layout to show)
// 3 = handle to monitor (passed back to engine to persist data)
// 4 = X_Y_Width_Height (where EditorOverlay shows up)
// 4 = X_Y_Width_Height in a dpi-scaled-but-unaware coords (where EditorOverlay shows up)
// 5 = resolution key (passed back to engine to persist data)
// 6 = monitor DPI (float)

View File

@ -1,13 +1,14 @@
#include "pch.h"
#include "common/dpi_aware.h"
#include "common/on_thread_executor.h"
struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZonesCallback, IZoneWindowHost>
{
public:
FancyZones(HINSTANCE hinstance, IFancyZonesSettings* settings) noexcept
: m_hinstance(hinstance)
, m_settings(settings)
{
m_settings.attach(settings);
m_settings->SetCallback(this);
}
@ -84,10 +85,12 @@ private:
bool m_dragEnabled{}; // True if we should be showing zone hints while dragging
std::map<HMONITOR, winrt::com_ptr<IZoneWindow>> m_zoneWindowMap; // Map of monitor to ZoneWindow (one per monitor)
winrt::com_ptr<IZoneWindow> m_zoneWindowMoveSize; // "Active" ZoneWindow, where the move/size is happening. Will update as drag moves between monitors.
winrt::com_ptr<IFancyZonesSettings> m_settings;
IFancyZonesSettings* m_settings{};
GUID m_currentVirtualDesktopId{};
wil::unique_handle m_terminateEditorEvent;
OnThreadExecutor m_dpiUnawareThread;
static UINT WM_PRIV_VDCHANGED;
static UINT WM_PRIV_EDITOR;
@ -120,13 +123,18 @@ IFACEMETHODIMP_(void) FancyZones::Run() noexcept
RegisterHotKey(m_window, 1, m_settings->GetSettings().editorHotkey.get_modifiers(), m_settings->GetSettings().editorHotkey.get_code());
VirtualDesktopChanged();
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{[]{
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR_MIXED);
}}).wait();
}
// IFancyZones
IFACEMETHODIMP_(void) FancyZones::Destroy() noexcept
{
std::unique_lock writeLock(m_lock);
m_zoneWindowMap.clear();
BufferedPaintUnInit();
if (m_window)
{
@ -239,22 +247,22 @@ void FancyZones::ToggleEditor() noexcept
}
HMONITOR monitor{};
UINT dpi_x = 96;
UINT dpi_y = 96;
HWND foregroundWindow{};
if (m_settings->GetSettings().use_cursorpos_editor_startupscreen)
{
UINT dpi_x = DPIAware::DEFAULT_DPI;
UINT dpi_y = DPIAware::DEFAULT_DPI;
const bool use_cursorpos_editor_startupscreen = m_settings->GetSettings().use_cursorpos_editor_startupscreen;
POINT currentCursorPos{};
if (use_cursorpos_editor_startupscreen)
{
GetCursorPos(&currentCursorPos);
monitor = MonitorFromPoint(currentCursorPos, MONITOR_DEFAULTTOPRIMARY);
DPIAware::GetScreenDPIForPoint(currentCursorPos, dpi_x, dpi_y);
}
else
{
const HWND foregroundWindow = GetForegroundWindow();
foregroundWindow = GetForegroundWindow();
monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTOPRIMARY);
DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y);
}
@ -272,21 +280,33 @@ void FancyZones::ToggleEditor() noexcept
MONITORINFOEX mi;
mi.cbSize = sizeof(mi);
m_dpiUnawareThread.submit(OnThreadExecutor::task_t{[&]{
GetMonitorInfo(monitor, &mi);
}}).wait();
// X/Y need to start in unscaled screen coordinates to get to the proper top/left of the monitor
// From there, we need to scale the difference between the monitor and workarea rects to get the
// appropriate offset where the overlay should appear.
// This covers the cases where the taskbar is not at the bottom of the screen.
const auto x = mi.rcMonitor.left + MulDiv(mi.rcWork.left - mi.rcMonitor.left, 96, dpi_x);
const auto y = mi.rcMonitor.top + MulDiv(mi.rcWork.top - mi.rcMonitor.top, 96, dpi_y);
if(use_cursorpos_editor_startupscreen)
{
DPIAware::GetScreenDPIForPoint(currentCursorPos, dpi_x, dpi_y);
}
else
{
DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y);
}
// Location that the editor should occupy, scaled by DPI
std::wstring editorLocation =
const auto taskbar_x_offset = MulDiv(mi.rcWork.left - mi.rcMonitor.left, DPIAware::DEFAULT_DPI, dpi_x);
const auto taskbar_y_offset = MulDiv(mi.rcWork.top - mi.rcMonitor.top, DPIAware::DEFAULT_DPI, dpi_y);
// Do not scale window params by the dpi, that will be done in the editor - see LayoutModel.Apply
const auto x = mi.rcMonitor.left + taskbar_x_offset;
const auto y = mi.rcMonitor.top + taskbar_y_offset;
const auto width = mi.rcWork.right - mi.rcWork.left;
const auto height = mi.rcWork.bottom - mi.rcWork.top;
const std::wstring editorLocation =
std::to_wstring(x) + L"_" +
std::to_wstring(y) + L"_" +
std::to_wstring(MulDiv(mi.rcWork.right - mi.rcWork.left, 96, dpi_x)) + L"_" +
std::to_wstring(MulDiv(mi.rcWork.bottom - mi.rcWork.top, 96, dpi_y));
std::to_wstring(width) + L"_" +
std::to_wstring(height);
const std::wstring params =
iter->second->UniqueId() + L" " +
@ -294,7 +314,7 @@ void FancyZones::ToggleEditor() noexcept
std::to_wstring(reinterpret_cast<UINT_PTR>(monitor)) + L" " +
editorLocation + L" " +
iter->second->WorkAreaKey() + L" " +
std::to_wstring(static_cast<float>(dpi_x) / 96.0f);
std::to_wstring(static_cast<float>(dpi_x) / DPIAware::DEFAULT_DPI);
SHELLEXECUTEINFO sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
@ -652,18 +672,26 @@ void FancyZones::MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT cons
RECT windowRect{};
::GetWindowRect(window, &windowRect);
windowRect.top += 6;
windowRect.left += 8;
windowRect.right -= 8;
windowRect.bottom -= 6;
const auto padding_x = 8;
const auto padding_y = 6;
windowRect.top += padding_y;
windowRect.left += padding_x;
windowRect.right -= padding_x;
windowRect.bottom -= padding_y;
if (PtInRect(&windowRect, ptScreen))
if (PtInRect(&windowRect, ptScreen) == FALSE)
{
return;
}
m_inMoveSize = true;
auto iter = m_zoneWindowMap.find(monitor);
if (iter != m_zoneWindowMap.end())
if (iter == end(m_zoneWindowMap))
{
return;
}
m_windowMoveSize = window;
// This updates m_dragEnabled depending on if the shift key is being held down.
@ -680,8 +708,6 @@ void FancyZones::MoveSizeStartInternal(HWND window, HMONITOR monitor, POINT cons
m_zoneWindowMoveSize = nullptr;
}
}
}
}
void FancyZones::MoveSizeEndInternal(HWND window, POINT const& ptScreen, require_write_lock) noexcept
{

View File

@ -11,7 +11,7 @@ public:
LoadSettings(name, true /*fromFile*/);
}
IFACEMETHODIMP_(void) SetCallback(IFancyZonesCallback* callback) { m_callback.attach(callback); }
IFACEMETHODIMP_(void) SetCallback(IFancyZonesCallback* callback) { m_callback = callback; }
IFACEMETHODIMP_(bool) GetConfig(_Out_ PWSTR buffer, _Out_ int *buffer_sizeg) noexcept;
IFACEMETHODIMP_(void) SetConfig(PCWSTR config) noexcept;
IFACEMETHODIMP_(void) CallCustomAction(PCWSTR action) noexcept;
@ -21,7 +21,7 @@ private:
void LoadSettings(PCWSTR config, bool fromFile) noexcept;
void SaveSettings() noexcept;
winrt::com_ptr<IFancyZonesCallback> m_callback;
IFancyZonesCallback* m_callback{};
const HINSTANCE m_hinstance;
PCWSTR m_name{};

View File

@ -34,13 +34,15 @@ interface __declspec(uuid("{E4839EB7-669D-49CF-84A9-71A2DFD851A3}")) IZoneSet :
#define VERSION_PERSISTEDDATA 0x0000F00D
struct ZoneSetPersistedData
{
static constexpr inline size_t MAX_ZONES = 40;
DWORD Version{VERSION_PERSISTEDDATA};
WORD LayoutId{};
DWORD ZoneCount{};
ZoneSetLayout Layout{};
DWORD PaddingInner{};
DWORD PaddingOuter{};
RECT Zones[40]{};
RECT Zones[MAX_ZONES]{};
};
struct ZoneSetConfig

View File

@ -1,4 +1,6 @@
#include "pch.h"
#include <common/dpi_aware.h>
#include <ShellScalingApi.h>
struct ZoneWindow : public winrt::implements<ZoneWindow, IZoneWindow>
@ -116,8 +118,10 @@ ZoneWindow::ZoneWindow(
MONITORINFO mi{};
mi.cbSize = sizeof(mi);
if (GetMonitorInfoW(m_monitor, &mi))
if (!GetMonitorInfoW(m_monitor, &mi))
{
return;
}
const UINT dpi = GetDpiForMonitor();
const Rect monitorRect(mi.rcMonitor);
const Rect workAreaRect(mi.rcWork, dpi);
@ -152,12 +156,14 @@ ZoneWindow::ZoneWindow(
}
}
}
}
IFACEMETHODIMP ZoneWindow::ShowZoneWindow(bool activate, bool fadeIn) noexcept
{
if (m_window)
if (!m_window)
{
return E_FAIL;
}
m_flashMode = false;
UINT flags = SWP_NOSIZE | SWP_NOMOVE;
@ -184,11 +190,8 @@ IFACEMETHODIMP ZoneWindow::ShowZoneWindow(bool activate, bool fadeIn) noexcept
AnimateWindow(m_window.get(), m_showAnimationDuration, AW_BLEND);
InvalidateRect(m_window.get(), nullptr, true);
}
return S_OK;
}
return E_FAIL;
}
IFACEMETHODIMP ZoneWindow::HideZoneWindow() noexcept
{
@ -356,8 +359,11 @@ void ZoneWindow::InitializeZoneSets() noexcept
void ZoneWindow::LoadZoneSetsFromRegistry() noexcept
{
if (wil::unique_hkey key{ RegistryHelpers::OpenKey(m_workArea) })
wil::unique_hkey key{RegistryHelpers::OpenKey(m_workArea)};
if (!key)
{
return;
}
ZoneSetPersistedData data{};
DWORD dataSize = sizeof(data);
wchar_t value[256]{};
@ -387,12 +393,12 @@ void ZoneWindow::LoadZoneSetsFromRegistry() noexcept
zoneSet->AddZone(MakeZone(data.Zones[j]), false);
}
m_zoneSets.emplace_back(zoneSet);
if (zoneSetId == m_activeZoneSetId)
{
UpdateActiveZoneSet(zoneSet.get());
}
m_zoneSets.emplace_back(std::move(zoneSet));
}
}
}
@ -405,7 +411,6 @@ void ZoneWindow::LoadZoneSetsFromRegistry() noexcept
dataSize = sizeof(data);
}
}
}
winrt::com_ptr<IZoneSet> ZoneWindow::AddZoneSet(ZoneSetLayout layout, int numZones, int paddingOuter, int paddingInner) noexcept
{
@ -716,8 +721,10 @@ void ZoneWindow::DrawZone(wil::unique_hdc& hdc, ColorSetting const& colorSetting
}
FillRectARGB(hdc, &zoneRect, colorSetting.fillAlpha, colorSetting.fill, false);
if (!m_flashMode)
if (m_flashMode)
{
return;
}
COLORREF const colorFill = RGB(255, 255, 255);
size_t const index = zone->Id();
@ -747,7 +754,6 @@ void ZoneWindow::DrawZone(wil::unique_hdc& hdc, ColorSetting const& colorSetting
offset.x = zoneRect.left + padding;
DrawIndex(hdc, offset, index, padding, size, false, true, colorFill); // bottom left
}
}
void ZoneWindow::DrawIndex(wil::unique_hdc& hdc, POINT offset, size_t index, int padding, int size, bool flipX, bool flipY, COLORREF colorFill)
{
@ -817,11 +823,15 @@ void ZoneWindow::DrawActiveZoneSet(wil::unique_hdc& hdc, RECT const& clientRect)
ColorSetting const colorFlash { 200, RGB(81, 92, 107), 200, RGB(104, 118, 138), -2 };
auto zones = m_activeZoneSet->GetZones();
size_t colorIndex = zones.size() - 1;
const size_t maxColorIndex = min(size(zones) - 1, size(colors) - 1);
size_t colorIndex = maxColorIndex;
for (auto iter = zones.rbegin(); iter != zones.rend(); iter++)
{
if (winrt::com_ptr<IZone> zone = iter->try_as<IZone>())
winrt::com_ptr<IZone> zone = iter->try_as<IZone>();
if (!zone)
{
continue;
}
if (zone != m_highlightZone)
{
if (m_flashMode)
@ -842,8 +852,7 @@ void ZoneWindow::DrawActiveZoneSet(wil::unique_hdc& hdc, RECT const& clientRect)
DrawZone(hdc, colorViewer, zone);
}
}
colorIndex--;
}
colorIndex = colorIndex != 0 ? colorIndex - 1 : maxColorIndex;
}
if (m_highlightZone)
@ -930,7 +939,7 @@ void ZoneWindow::OnPaint(wil::unique_hdc& hdc) noexcept
RECT clientRect;
GetClientRect(m_window.get(), &clientRect);
wil::unique_hdc hdcMem;;
wil::unique_hdc hdcMem;
HPAINTBUFFER bufferedPaint = BeginBufferedPaint(hdc.get(), &clientRect, BPBF_TOPDOWNDIB, nullptr, &hdcMem);
if (bufferedPaint)
{
@ -1284,7 +1293,7 @@ UINT ZoneWindow::GetDpiForMonitor() noexcept
}
}
return (dpi == 0) ? 96 : dpi;
return (dpi == 0) ? DPIAware::DEFAULT_DPI : dpi;
}
#pragma endregion

View File

@ -18,7 +18,16 @@ namespace {
}
}
// Prevent system-wide input lagging while paused in the debugger
//#define DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED
void start_lowlevel_keyboard_hook() {
#if defined(_DEBUG) && defined(DISABLE_LOWLEVEL_KBHOOK_WHEN_DEBUGGED)
if(IsDebuggerPresent()) {
return;
}
#endif
if (!hook_handle) {
hook_handle = SetWindowsHookEx(WH_KEYBOARD_LL, hook_proc, GetModuleHandle(NULL), NULL);
hook_handle_copy = hook_handle;

View File

@ -8,6 +8,8 @@
#include "trace.h"
#include "general_settings.h"
#include <common/dpi_aware.h>
#if _DEBUG && _WIN64
#include "unhandled_exception_handler.h"
#endif
@ -32,6 +34,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
return 0;
}
DPIAware::EnableDPIAwarenessForThisProcess();
#if _DEBUG && _WIN64
//Global error handlers to diagnose errors.
//We prefer this not not show any longer until there's a bug to diagnose.

View File

@ -67,7 +67,7 @@
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<EnableDpiAwareness>false</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@ -92,7 +92,7 @@
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
<Manifest>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<EnableDpiAwareness>false</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>

View File

@ -60,6 +60,7 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<CustomBuildStep>
<Command>
@ -88,6 +89,7 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>