Skip to main content
This guide covers debugging techniques and tips for developing Windows Calculator, from basic Visual Studio debugging to advanced diagnostic tools.

Debugging in Visual Studio

Visual Studio provides powerful debugging capabilities for both C++ and C# code in Calculator.

Starting a Debug Session

1

Set Your Startup Project

Right-click the Calculator project in Solution Explorer and select Set as Startup Project.
2

Choose Debug Configuration

Select Debug from the configuration dropdown in the toolbar. Debug builds include:
  • Full debugging symbols
  • Minimal optimization
  • Enabled assertions
  • Better stack traces
3

Start Debugging

Press F5 to build, deploy, and launch with debugger attached

Breakpoints

Set breakpoints to pause execution and inspect state:
1

Basic Breakpoints

  • Click in the left margin next to a line of code
  • Or press F9 with the cursor on a line
  • Breakpoint appears as a red dot
2

Conditional Breakpoints

Right-click a breakpoint and select Conditions to:
  • Break only when a condition is true
  • Break when a value changes
  • Break after a hit count threshold
// Example: Break only when result is negative
if (result < 0)  // Set condition: result < 0
{
    return result;
}
3

Function Breakpoints

Set breakpoints on function names:
  • Debug > New Breakpoint > Function Breakpoint
  • Enter function name (e.g., CalculatorManager::Calculate)

Inspecting Variables

Visual Studio provides multiple ways to examine variables:
ToolShortcutDescription
AutosCtrl+Alt+V, AShows variables in current and previous statements
LocalsCtrl+Alt+V, LDisplays all local variables in current scope
WatchCtrl+Alt+W, 1-4Custom watch windows for specific expressions
Quick WatchShift+F9Popup window for evaluating expressions
Data TipsHoverHover over variables to see their values
Pin frequently used variables in data tips to keep them visible as you step through code.

Stepping Through Code

Steps into function calls to debug the called function

Debugging Mixed C++/C# Code

Calculator uses both C++ (CalcManager, CalcViewModel) and C# (UI layer), requiring mixed-mode debugging:
1

Enable Mixed-Mode Debugging

  1. Right-click the Calculator project
  2. Select Properties
  3. Go to Debug tab
  4. Check Enable native code debugging
2

Set Breakpoints in Both Languages

  • Set breakpoints in C# UI code (Calculator project)
  • Set breakpoints in C++ code (CalcManager, CalcViewModel)
  • Debugger will break in both when hit
3

Navigate Between Managed and Native

Use the Call Stack window (Ctrl+Alt+C) to:
  • See the full call chain across C# and C++
  • Navigate between managed and native frames
  • Identify which layer a problem originates from

Debugging Specific Components

CalcManager (Calculation Engine)

The C++ calculation engine is in the CalcManager project:
// Common breakpoint locations:
// src/CalcManager/CalculatorManager.cpp
void CalculatorManager::SendCommand(_In_ Command command)
{
    // Break here to see all calculation commands
}

// src/CalcManager/Ratpack/Conv.cpp
void ChangeBase(/* ... */)
{
    // Break here for base conversion debugging
}
CalcManager uses arbitrary-precision arithmetic. Watch the internal number representation in the Number class for precision-related issues.

CalcViewModel (View Models)

The C++ view models bridge the UI and calculation engine:
// Common breakpoint locations:
// src/CalcViewModel/StandardCalculatorViewModel.cpp
void StandardCalculatorViewModel::OnButtonPressed(NumbersAndOperatorsEnum button)
{
    // Break here to debug button press handling
}

// src/CalcViewModel/Common/CalculatorDisplay.cpp
void CalculatorDisplay::SetPrimaryDisplay(_In_ wstring displayString)
{
    // Break here to debug display updates
}

UI Layer (C# Code)

The XAML UI and C# code-behind:
// Common breakpoint locations:
// src/Calculator/Views/Calculator.xaml.cs
private void OnButtonClick(object sender, RoutedEventArgs e)
{
    // Break here for UI button handling
}

// src/Calculator/Views/MainPage.xaml.cs  
private void OnNavigationViewSelectionChanged(/* ... */)
{
    // Break here for mode switching
}

Advanced Debugging Techniques

Memory Analysis

For investigating memory leaks or high memory usage:
1

Take Memory Snapshots

  1. Debug > Performance Profiler
  2. Select .NET Object Allocation Tracking and Memory Usage
  3. Start debugging
  4. Take snapshots at different points
  5. Compare snapshots to find leaks
2

Analyze Native Memory

For C++ components:
  • Use the Diagnostic Tools window (Ctrl+Alt+F2)
  • Monitor memory usage over time
  • Look for steadily increasing memory

Performance Profiling

Profile Calculator to identify performance bottlenecks:
1

CPU Profiling

  1. Debug > Performance Profiler
  2. Select CPU Usage
  3. Click Start
  4. Perform operations in Calculator
  5. Stop profiling and analyze results
2

Identify Hot Paths

Look for:
  • Functions with high Self CPU time
  • Functions called frequently
  • Unexpected calculation overhead

XAML Debugging

Debug UI issues with XAML-specific tools:
1

Live Visual Tree

Debug > Windows > Live Visual Tree to:
  • Inspect the visual element hierarchy
  • Find elements by type or name
  • Navigate to XAML source
2

Live Property Explorer

Debug > Windows > Live Property Explorer to:
  • View and modify properties in real-time
  • See style and template sources
  • Debug data binding issues
3

XAML Binding Failures

Enable binding failure breaks:
  1. Debug > Windows > Exception Settings
  2. Check Common Language Runtime Exceptions
  3. Look for binding errors in Output window

Diagnostic Data

Calculator includes diagnostic telemetry that can be enabled for debugging:
1

Enable Diagnostics

Add the SEND_DIAGNOSTICS build flag:
msbuild ./src/Calculator.sln `
  -p:Platform=x64 `
  -p:Configuration=Debug `
  -p:DefineConstants=SEND_DIAGNOSTICS
2

View Diagnostic Output

Diagnostic events appear in:
  • Visual Studio Output window
  • Windows Event Viewer
  • ETW trace sessions
Diagnostic data is disabled by default in development builds and requires explicit opt-in via the build flag.

Logging and Tracing

Calculator uses the TraceLogging project for diagnostic output:
// Example: Add custom trace logging
#include "TraceLogging.h"

TraceLoggingWrite(
    g_calculatorProvider,
    "CalculationPerformed",
    TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
    TraceLoggingValue(command, "Command"),
    TraceLoggingValue(result, "Result")
);
View traces using:
  • Windows Performance Recorder (WPR)
  • Windows Performance Analyzer (WPA)
  • PerfView

Common Debugging Scenarios

Calculation Errors

1

Set Breakpoint in CalcManager

// src/CalcManager/CalculatorManager.cpp
void CalculatorManager::SendCommand(_In_ Command command)
2

Inspect Command Flow

Watch:
  • command parameter value
  • Current state in m_currentState
  • Display value in m_displayValue
3

Step Into Calculation Logic

Press F11 to step into the calculation engine and trace the exact computation.

UI Not Updating

1

Check Data Binding

In Live Property Explorer, verify:
  • Binding source is correct
  • Property change notifications fire
  • Values are being updated
2

Verify ViewModel Updates

Set breakpoint in view model property setters:
void StandardCalculatorViewModel::SetDisplayValue(wstring value)
{
    // Break here to see when display updates
}

Crashes on Startup

1

Enable First-Chance Exceptions

Debug > Windows > Exception SettingsCheck:
  • C++ Exceptions
  • Common Language Runtime Exceptions
2

Check Call Stack on Crash

When the exception breaks, examine:
  • Call Stack window for crash location
  • Locals for invalid values
  • Exception details for error message

Debugging Tests

Unit Tests

Debug failing unit tests:
1

Open Test Explorer

Test > Test Explorer (Ctrl+E, T)
2

Debug Individual Test

  • Right-click a test
  • Select Debug
  • Set breakpoints in test or code under test

UI Tests

Debug WinAppDriver UI tests:
1

Attach to Both Processes

Attach debugger to:
  • CalculatorUITests.exe (test process)
  • Calculator.exe (app under test)
2

Add Delays for Debugging

// Add temporary delay to attach debugger
System.Threading.Thread.Sleep(10000);
3

Enable WinAppDriver Logging

Start WinAppDriver with verbose logging:
"C:\Program Files\Windows Application Driver\WinAppDriver.exe" /log

Debugging Tools

Built into Visual Studio

  • Diagnostic Tools - Real-time CPU, memory, and events
  • Performance Profiler - Deep performance analysis
  • Live Visual Tree - XAML element inspection
  • IntelliTrace - Historical debugging (Enterprise only)

External Tools

  • WinDbg - Advanced native debugging
  • PerfView - Performance and memory analysis
  • Sysinternals Suite - Process Explorer, Process Monitor
  • ETW/WPR/WPA - Event tracing and analysis

Tips and Best Practices

1

Use Meaningful Variable Names

Clear names make debugging easier in watch windows and call stacks.
2

Add Debug Assertions

assert(denominator != 0 && "Division by zero");
Assertions catch bugs early in debug builds.
3

Log at Key Points

Add TraceLogging at important decision points to reconstruct execution flow.
4

Reproduce Consistently

Find the exact steps to reproduce issues before deep debugging.
5

Debug in Isolation

Test components independently when possible:
  • Unit test CalcManager logic separately
  • Test view models without UI
  • Mock dependencies

Next Steps

Contributing Guidelines

Learn how to contribute fixes and features

Architecture

Understand Calculator’s architecture

Build docs developers (and LLMs) love