← All Insights

When Application Crashes Are Really Runtime Problems: Diagnosing VC++ Dependencies at Scale

When a Windows application crashes, the application itself is the obvious place to start looking. But sometimes the executable named in the error is only the victim. The actual problem is a shared dependency installed elsewhere on the system.

CBITS

We encountered this while investigating recurring crashes in a professional Windows application. Windows event data pointed toward Microsoft Visual C++ runtime DLLs rather than a straightforward application failure. More importantly, the issue wasn't isolated to a single machine. Comparing systems began to reveal inconsistencies in the runtime environment that warranted a broader look.

That changed the troubleshooting question. Instead of asking only, "How do we repair this application?" we started asking, "How do we determine whether the Windows runtime environment is healthy across the entire device fleet?"

Reading Beyond the Faulting Application

Windows application crash events usually provide several useful pieces of information, including the faulting application, faulting module and exception code.

The distinction between the application and module is important.

In one of the crashes we investigated, the application executable was listed as the faulting application, but MSVCP140.dll appeared as the faulting module. That DLL is part of Microsoft's Visual C++ runtime rather than the application itself.

That doesn't automatically prove that the runtime is responsible. Applications can pass invalid data into otherwise healthy libraries, and a crash occurring inside a DLL is not enough by itself to establish root cause.

But it is a strong reason to investigate the dependency.

The affected system also contained a notably old version of the runtime DLL. That gave us another useful signal: instead of repeatedly reinstalling or repairing the application, we needed to understand the state of the Microsoft Visual C++ redistributables on the machine.

Architecture Matters: x86 and x64 Are Not Interchangeable

One of the most useful findings came from testing repairs separately.

On an affected machine, repairing the x86 Visual C++ redistributable did not resolve the application problem. Repairing the x64 runtime did.

That distinction matters because 64-bit Windows systems commonly contain both x86 and x64 redistributables. Seeing "Microsoft Visual C++" in the installed application list does not necessarily tell you whether the dependency required by a particular process is healthy.

For a 64-bit application loading a 64-bit runtime DLL, repairing an unrelated 32-bit package may leave the actual dependency untouched.

This sounds obvious when stated explicitly, but it changes how runtime problems should be investigated. A useful inventory needs to preserve architecture rather than reducing everything to a simple "VC++ installed" result.

The same principle applies to version information. Presence alone is not enough. For troubleshooting, we want to know what is installed and what Windows is actually loading.

A Successful Repair Is Also Diagnostic Evidence

A repair operation is useful for more than restoring service.

When a targeted runtime repair consistently changes application behavior, it gives us additional evidence about the dependency chain.

In our case, we had seen a system experience the application issue, recover after Visual C++ runtime repair, and later experience a similar problem again. Another affected system was resolved specifically through repair of the x64 runtime.

That raised a more interesting operational question.

Why were systems reaching a state where runtime repair was necessary in the first place?

A help-desk procedure that says "repair the redistributable when the application crashes" may restore the user quickly, but it doesn't provide much visibility into whether the same condition exists elsewhere or whether it is recurring.

That is where the troubleshooting effort began turning into an endpoint-management problem.

From One Computer to Fleet-Wide Runtime Health

Once multiple Windows devices could potentially be relevant, checking them manually stopped being attractive.

The environment was already managed with Microsoft Intune, so we began designing a read-only health collection process that could run across managed endpoints.

The goal was not to automatically replace DLLs or perform aggressive repairs. It was to gather consistent evidence.

Useful runtime-health data includes things such as:

  • Installed Visual C++ redistributable packages
  • x86 versus x64 architecture
  • Installed package versions
  • Relevant runtime DLL versions
  • Device information needed to correlate the result with the managed endpoint

This creates a much better starting point for comparison.

A known-affected machine can be compared with a repaired machine and with systems that have not reported the application problem. Instead of relying on screenshots or manually checking Programs and Features, each endpoint can be evaluated using the same collection logic.

Keeping Detection Separate From Remediation

An important design decision was to keep the initial health process read-only.

It can be tempting to detect an unexpected runtime version and immediately reinstall the latest redistributable. At fleet scale, that is a much more consequential decision than repairing one known-broken workstation.

Detection and remediation answer different questions.

Detection asks:

What state is this computer in?

Remediation asks:

What should we change?

Keeping those operations separate lets us collect a baseline before making assumptions about what "normal" looks like across the environment. It also preserves evidence from affected systems that might otherwise disappear as soon as an automated repair runs.

Once enough data exists to identify a reliable failure condition, remediation can be designed around that specific condition rather than around a broad assumption.

That is safer and easier to validate.

Intune as the Distribution Layer

Microsoft Intune provides an important advantage for this type of investigation: the endpoints are already managed.

Instead of arranging remote sessions with individual users, a PowerShell-based collection process can be distributed to selected devices through the existing management plane.

That also changes how troubleshooting scales.

A script can first be assigned to a controlled group. Additional devices can then be brought into scope as the investigation expands. Each machine executes the same checks locally, eliminating much of the variability that comes from manual inspection.

For this project, we also worked toward sending the resulting health data to centralized Azure Blob storage. The endpoint performs the inspection and produces a structured result, while the central repository makes those results available for comparison.

This is a relatively simple architecture:

Managed Windows endpoint → Intune-delivered PowerShell → structured health result → centralized Azure storage

The value isn't architectural complexity. It is consistency.

Every machine is evaluated using the same criteria, and the resulting records can be reviewed together rather than as isolated troubleshooting sessions.

Structured Data Makes Patterns Visible

Machine-readable output was another deliberate choice.

A text log is useful when a technician is investigating one computer. Structured JSON is much more useful when dozens of computers may need to be compared.

With structured results, fields such as architecture, package version and DLL version can be evaluated consistently across machines.

That makes questions like these much easier to answer:

  • Is a particular runtime version common to affected machines?
  • Are x64 components inconsistent while x86 components remain current?
  • Does a repaired machine now differ from its pre-repair state?
  • Are apparently healthy devices already showing the same runtime condition?
  • Is the condition isolated, or does it justify a broader remediation plan?

This is the point where endpoint telemetry becomes more valuable than another troubleshooting checklist.

The objective isn't to collect data for its own sake. It is to turn an intermittent desktop problem into something measurable.

Capture the Evidence Before the Fix

One of the most valuable opportunities in troubleshooting is the state of a computer immediately before a known repair.

If health information is collected before remediation and again afterward, the two records provide a much stronger comparison than memory or screenshots.

That is particularly useful with dependency problems. A user may report only that an application "started working again." The before-and-after system state can help establish exactly what changed.

In this investigation, collecting runtime-health information from an affected system before performing the successful repair gave us a useful reference point for subsequent analysis.

This is a practice worth applying beyond Visual C++ runtimes. When practical, capture the relevant state before changing it.

Why This Matters

The larger lesson is not that every application crash should be fixed by reinstalling Visual C++.

It shouldn't.

The lesson is that shared dependencies deserve to be treated as part of the managed application environment.

Modern Windows applications depend on layers of components outside their own installation directories: runtimes, frameworks, drivers, system libraries and other shared services. An application can therefore fail even when its own files are perfectly intact.

Good troubleshooting follows the evidence through those layers.

And once the same class of problem appears on more than one managed device, the response should evolve. Manual troubleshooting can establish the hypothesis. Endpoint management and structured telemetry can test it across the fleet.

That progression looks like this:

Crash evidence → dependency hypothesis → targeted repair → validation → standardized detection → fleet-wide comparison

It turns a recurring support issue into an engineering problem that can be measured and managed.

Next Steps

Our next step is to continue using the collected endpoint data to distinguish isolated runtime corruption from patterns that can be identified reliably across managed Windows devices.

Only after that baseline is understood does automated remediation become the logical next question.

For organizations already managing Windows endpoints with Microsoft Intune, this approach can extend well beyond Visual C++ runtimes. The same management infrastructure can help turn difficult, intermittent workstation problems into structured health signals that IT can investigate centrally.

CBITS works with Microsoft 365 and Windows environments to solve these kinds of operational problems: first understanding what is actually failing, then using the management tools already available to make the solution repeatable.