Skip to content

Native Library Overview

Calvindd2f edited this page Jan 14, 2026 · 1 revision

Native Library Overview

Relevant source files

The following files were used as context for generating this wiki page:

This document introduces the OfficeScrubNative.dll native library, which provides high-performance system operations through compiled C# code. The library achieves 10-50x performance improvements over pure PowerShell implementations through direct Win32 API calls, parallel processing, and memory-efficient algorithms.

For detailed documentation of individual helper classes, see Helper Classes. For performance optimization techniques, see Performance Optimizations. For Win32 API integration details, see P/Invoke and Win32 APIs.

Purpose and Scope

The native library serves as the performance-critical layer of OfficeScrubC2R, handling operations that would be prohibitively slow in pure PowerShell:

  • Registry Operations: 30x faster than PowerShell registry cmdlets through direct Win32 API calls
  • File System Operations: 15x faster with parallel deletion and native cmd.exe integration
  • Process Management: Concurrent termination with proper timeout handling
  • Windows Installer Cleanup: Efficient MSI metadata enumeration and GUID decoding
  • COM Type Library Cleanup: Automated COM registration cleanup with file validation
  • License Management: WMI-based OSPP/SPP operations for Office activation cleanup
  • Service Management: Reliable service termination and deletion
  • Shell Integration: Taskbar and Start menu unpinning with localization support

The library is distributed as a pre-compiled DLL (OfficeScrubNative.dll) but includes the full C# source code for fallback compilation in environments where pre-compiled binaries are blocked.

Sources: OfficeScrubC2R-Native.cs:1-1408

Library Architecture

OfficeScrubOrchestrator Facade

The OfficeScrubOrchestrator class implements the facade pattern, providing a unified entry point for all native operations. This class instantiates and manages all helper classes, exposing them as public properties.

classDiagram
    class OfficeScrubOrchestrator {
        +RegistryHelper Registry
        +FileHelper Files
        +ProcessHelper Processes
        +ShellHelper Shell
        +WindowsInstallerHelper WindowsInstaller
        +TypeLibHelper TypeLib
        +LicenseHelper License
        +ServiceHelper Services
        +bool IsC2RPath(string path)
        +bool IsInScope(string productCode)
    }
    
    class RegistryHelper {
        +bool KeyExists()
        +bool DeleteKey()
        +string[] EnumerateKeys()
        +object GetValue()
    }
    
    class FileHelper {
        +bool DeleteFile()
        +bool DeleteDirectory()
        +void ScheduleDeleteOnReboot()
    }
    
    class ProcessHelper {
        +List~int~ TerminateProcesses()
        +bool IsProcessRunning()
    }
    
    class WindowsInstallerHelper {
        +void CleanupUpgradeCodes()
        +void CleanupProducts()
        +void CleanupComponents()
    }
    
    class TypeLibHelper {
        +void CleanupKnownTypeLibs()
    }
    
    class LicenseHelper {
        +void CleanOSPP()
        +void ClearVNextLicenseCache()
    }
    
    class ServiceHelper {
        +bool DeleteService()
    }
    
    class ShellHelper {
        +bool UnpinFromTaskbar()
        +bool UnpinFromStartMenu()
        +void RestartExplorer()
    }
    
    class GuidHelper {
        +string GetExpandedGuid()
        +string GetCompressedGuid()
        +bool GetDecodedGuid()
    }
    
    OfficeScrubOrchestrator --> RegistryHelper
    OfficeScrubOrchestrator --> FileHelper
    OfficeScrubOrchestrator --> ProcessHelper
    OfficeScrubOrchestrator --> ShellHelper
    OfficeScrubOrchestrator --> WindowsInstallerHelper
    OfficeScrubOrchestrator --> TypeLibHelper
    OfficeScrubOrchestrator --> LicenseHelper
    OfficeScrubOrchestrator --> ServiceHelper
    WindowsInstallerHelper --> RegistryHelper
    WindowsInstallerHelper --> GuidHelper
    TypeLibHelper --> RegistryHelper
Loading

Figure 1: OfficeScrubOrchestrator Class Hierarchy

The orchestrator is instantiated once during module initialization and stored in the PowerShell module scope for reuse throughout the cleanup process.

Sources: OfficeScrubC2R-Native.cs:1347-1405

Namespace and Type Organization

All native types are defined in the OfficeScrubNative namespace, organized into logical regions:

Region Lines Purpose
Enums and Constants 19-58 RegistryHiveType enum and OfficeConstants static class
P/Invoke Declarations 60-167 Native method signatures and COM interface definitions
GUID Utilities 169-330 Static GuidHelper class for GUID transformations
Registry Operations 332-617 RegistryHelper class with WOW64 support
File Operations 620-768 FileHelper class with reboot scheduling
Process Operations 771-859 ProcessHelper class with parallel termination
Shell Integration 862-975 ShellHelper class for taskbar/Start menu
Windows Installer Helper 978-1129 WindowsInstallerHelper class for MSI cleanup
TypeLib Helper 1132-1210 TypeLibHelper class for COM cleanup
License/SPP Helper 1213-1274 LicenseHelper class for activation cleanup
Service Helper 1277-1344 ServiceHelper class for service management
Orchestrator 1347-1407 OfficeScrubOrchestrator facade class

Sources: OfficeScrubC2R-Native.cs:17-1408

Helper Classes Overview

The native library provides nine specialized helper classes, each targeting a specific Windows subsystem:

Helper Class Summary

Helper Class Primary Responsibility Key Performance Feature Lines
RegistryHelper Registry operations with WOW64 support HashSet-based deduplication, 30x faster enumeration 334-616
FileHelper File and directory deletion with reboot scheduling cmd.exe batch deletion, 15x faster 622-767
ProcessHelper Process termination and detection Parallel process termination with Task.Run 773-858
WindowsInstallerHelper MSI metadata cleanup (Products, Components, UpgradeCodes) Compressed GUID decoding, predicate-based filtering 980-1128
TypeLibHelper COM type library cleanup Known TypeLib array, file existence validation 1134-1209
LicenseHelper Office license and SPP operations WMI-based OSPP cleanup, VNext cache deletion 1215-1273
ServiceHelper Windows service management WMI service control with sc.exe fallback 1279-1343
GuidHelper GUID encoding/decoding utilities Static methods for compressed/expanded/decoded GUIDs 171-328
ShellHelper Shell integration (taskbar, Start menu) COM automation with multi-language support 864-974

Sources: OfficeScrubC2R-Native.cs:171-1343

RegistryHelper

Provides registry operations with automatic WOW64 redirection handling. On 64-bit systems, operations automatically check both native and WOW6432Node locations.

Key Methods:

  • KeyExists(RegistryHiveType hive, string subKey): Check if registry key exists in any view
  • DeleteKey(RegistryHiveType hive, string subKey, bool recursive): Delete key from all views
  • EnumerateKeys(RegistryHiveType hive, string subKey): List subkeys from both views (deduplicated)
  • EnumerateValues(RegistryHiveType hive, string subKey): List values from both views (deduplicated)
  • GetValue/SetValue: Read/write registry values with view fallback
  • AddPendingFileRenameOperation: Schedule file deletion on reboot via Session Manager

Sources: OfficeScrubC2R-Native.cs:334-616

FileHelper

Handles file system operations with fallback strategies for locked files. Uses cmd.exe for large directory trees for optimal performance.

Key Methods:

  • DeleteFile(string filePath, bool scheduleOnFail): Delete file with attribute reset
  • DeleteDirectory(string directoryPath, bool recursive, bool scheduleOnFail): Delete directory using cmd.exe rd with .NET fallback
  • ScheduleDeleteOnReboot(string filePath): Schedule file deletion via MoveFileEx
  • ScheduleDirectoryDeleteOnReboot(string directoryPath): Recursively schedule directory deletion
  • GetPendingDeletes(): Retrieve list of files scheduled for deletion
  • IsFileLocked(string filePath): Check if file is locked by another process

Sources: OfficeScrubC2R-Native.cs:622-767

WindowsInstallerHelper

Cleans up Windows Installer metadata for Office products. Requires RegistryHelper instance for registry access.

Key Methods:

  • CleanupUpgradeCodes(Func<string, bool> shouldDelete): Remove UpgradeCode entries matching predicate
  • CleanupProducts(Func<string, bool> shouldDelete): Clean Products registry under UserData and Classes
  • CleanupComponents(Func<string, bool> shouldDelete): Remove component values matching predicate
  • CleanupPublishedComponents(Func<string, bool> shouldDelete): Parse and filter PublishedComponents multi-string values

All methods use GUID helper functions to decode compressed GUIDs (32 characters) and encoded GUIDs (20 characters) from registry keys and values.

Sources: OfficeScrubC2R-Native.cs:980-1128

GuidHelper

Static utility class for GUID format transformations used in Windows Installer metadata.

GUID Formats:

  • Expanded: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} (38 chars, standard format)
  • Compressed: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (32 chars, byte-reversed segments)
  • Encoded: XXXXXXXXXXXXXXXXXXXX (20 chars, base-85 encoding)

Key Methods:

  • GetExpandedGuid(string compressedGuid): Convert compressed → expanded format
  • GetCompressedGuid(string expandedGuid): Convert expanded → compressed format
  • GetDecodedGuid(string encodedGuid, out string decodedGuid): Decode base-85 encoded GUID

Sources: OfficeScrubC2R-Native.cs:171-328

Integration with PowerShell

PowerShell to Native Call Flow

The following diagram illustrates how PowerShell functions in the utilities module call into the native library:

sequenceDiagram
    participant PS as "PowerShell Function"
    participant Script as "$script:orchestrator"
    participant Orch as "OfficeScrubOrchestrator"
    participant Helper as "RegistryHelper/FileHelper/etc"
    participant Win32 as "Win32 APIs"
    
    Note over PS: From OfficeScrubC2R-Utilities.psm1
    
    PS->>Script: Access $script:orchestrator
    Script->>Orch: Get helper property
    Orch->>Helper: Return helper instance
    PS->>Helper: Call helper method
    Helper->>Win32: P/Invoke native API
    Win32-->>Helper: Return result
    Helper-->>PS: Return result
    
    Note over PS,Win32: Example: Remove-RegistryKey
    PS->>Script: $script:orchestrator.Registry
    Script-->>PS: RegistryHelper instance
    PS->>Helper: DeleteKey(hive, subKey, recursive)
    Helper->>Win32: RegDeleteKeyEx
    Win32-->>Helper: ERROR_SUCCESS
    Helper-->>PS: $true
Loading

Figure 2: PowerShell to Native Library Call Flow

Sources: OfficeScrubC2R-Native.cs:1347-1405

Module-Level Orchestrator Instance

The PowerShell module creates a single OfficeScrubOrchestrator instance during module initialization and stores it in module scope:

Initialization Pattern (from OfficeScrubC2R.psm1):

# Load native library based on PowerShell edition
$dllPath = if ($PSVersionTable.PSEdition -eq 'Core') {
    Join-Path $PSScriptRoot 'OfficeScrubNative.Core.dll'
} else {
    Join-Path $PSScriptRoot 'OfficeScrubNative.dll'
}

# Load and instantiate orchestrator
[System.Reflection.Assembly]::LoadFrom($dllPath)
$script:orchestrator = [OfficeScrubNative.OfficeScrubOrchestrator]::new(
    [Environment]::Is64BitOperatingSystem
)

Helper Access Pattern (from OfficeScrubC2R-Utilities.psm1):

function Remove-RegistryKey {
    [CmdletBinding()]
    param(
        [string]$KeyPath,
        [switch]$Recursive
    )
    
    $hive = [OfficeScrubNative.RegistryHiveType]::LocalMachine
    $script:orchestrator.Registry.DeleteKey($hive, $KeyPath, $Recursive.IsPresent)
}

function Stop-OfficeProcesses {
    [CmdletBinding()]
    param([string[]]$ProcessNames)
    
    $script:orchestrator.Processes.TerminateProcesses($ProcessNames, 5000)
}

function Test-OfficeC2RPath {
    [CmdletBinding()]
    param([string]$Path)
    
    $script:orchestrator.IsC2RPath($Path)
}

Sources: OfficeScrubC2R-Native.cs:1349-1382, docs/memory-bank/structure.md:110-132

Type Access Patterns

PowerShell code accesses native types through several patterns:

Access Pattern Comparison:

flowchart LR
    PSCode["PowerShell Code"] --> Enum["[OfficeScrubNative.RegistryHiveType]<br/>Enum Access"]
    PSCode --> Orch["$script:orchestrator.Registry<br/>Helper via Orchestrator"]
    PSCode --> Static["[OfficeScrubNative.GuidHelper]<br/>Static Utility Methods"]
    PSCode --> Direct["[OfficeScrubNative.RegistryHelper]::new()<br/>Direct Construction"]
    
    Orch --> Helper["RegistryHelper Instance"]
    Helper --> Method["DeleteKey() / EnumerateKeys()"]
Loading
Access Pattern Code Example Usage Context
Enum Members [OfficeScrubNative.RegistryHiveType]::LocalMachine Registry hive selection
Via Orchestrator $script:orchestrator.Registry.DeleteKey($hive, $key, $true) Preferred: Helper class methods
Static Helpers [OfficeScrubNative.GuidHelper]::GetExpandedGuid($compressed) GUID transformation utilities
Direct Construction [OfficeScrubNative.FileHelper]::new() Rare: Orchestrator manages instances
Constants [OfficeScrubNative.OfficeConstants]::OFFICE_PROCESSES Static data arrays

Module-Scoped Access (internal to utilities module):

# Helper property accessors
$regHelper = $script:orchestrator.Registry
$fileHelper = $script:orchestrator.Files
$procHelper = $script:orchestrator.Processes

# Validation methods
$isC2R = $script:orchestrator.IsC2RPath($installPath)
$inScope = $script:orchestrator.IsInScope($productGuid)

Sources: OfficeScrubC2R-Native.cs:17-1408, OfficeScrubC2R-Native.cs:1349-1405

Compilation and Distribution

Target Framework Strategy

The OfficeScrubC2R-Native.cs source file supports compilation for two .NET targets:

Target Binary Name Compiler PowerShell Compatibility
.NET Framework 4.5+ OfficeScrubNative.dll csc.exe Windows PowerShell 5.1
.NET Core 7+ OfficeScrubNative.Core.dll dotnet build PowerShell Core 7+

Framework Selection Logic:

flowchart LR
    PSEdition{"$PSVersionTable.PSEdition"}
    PSEdition -->|Desktop| Framework["Load OfficeScrubNative.dll<br/>.NET Framework 4.5+"]
    PSEdition -->|Core| NetCore["Load OfficeScrubNative.Core.dll<br/>.NET Core 7+"]
    Framework --> Orchestrator["OfficeScrubOrchestrator"]
    NetCore --> Orchestrator
Loading

Sources: docs/memory-bank/structure.md:111-124, docs/memory-bank/tech.md:17-27

Build Process

The build.ps1 script compiles both target frameworks:

Compilation Workflow:

flowchart TD
    BuildScript["build.ps1"] --> CheckFramework{"Framework<br/>Available?"}
    CheckFramework -->|"csc.exe found"| CompileFramework["csc.exe /target:library<br/>/out:OfficeScrubNative.dll<br/>/optimize+<br/>/reference:System.Management.dll"]
    CheckFramework -->|"dotnet found"| CompileCore["dotnet build<br/>-c Release<br/>-o OfficeScrubNative.Core.dll"]
    CompileFramework --> VerifyFW["Verify-NativeBuild.ps1<br/>Test .NET Framework"]
    CompileCore --> VerifyCore["Verify-NativeBuild.ps1<br/>Test .NET Core"]
    VerifyFW --> Success["Build Artifacts Ready"]
    VerifyCore --> Success
Loading

Compiler Configuration (.NET Framework):

# From build.ps1
$cscPath = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
$arguments = @(
    "/target:library"
    "/out:OfficeScrubNative.dll"
    "/optimize+"
    "/warn:4"
    "/reference:System.Management.dll"
    "/reference:Microsoft.CSharp.dll"
    "OfficeScrubC2R-Native.cs"
)

Compiler Configuration (.NET Core):

# From build.ps1
dotnet build OfficeScrubC2R-Native.cs `
    -c Release `
    -f net7.0 `
    -o ./bin/Core

Sources: docs/memory-bank/structure.md:117-124, docs/memory-bank/tech.md:29-55

Pre-Compiled DLL Strategy

The module ships with pre-compiled binaries for both targets to provide immediate availability:

flowchart TD
    ModuleImport["Import-Module OfficeScrubC2R"] --> CheckEdition{"$PSVersionTable<br/>.PSEdition"}
    CheckEdition -->|Desktop| CheckFW{"OfficeScrubNative.dll<br/>exists?"}
    CheckEdition -->|Core| CheckCore{"OfficeScrubNative.Core.dll<br/>exists?"}
    
    CheckFW -->|Yes| LoadFW["[System.Reflection.Assembly]<br/>::LoadFrom(dll path)"]
    CheckFW -->|No| CompileFW["Add-Type -TypeDefinition<br/>-ReferencedAssemblies"]
    
    CheckCore -->|Yes| LoadCore["[System.Reflection.Assembly]<br/>::LoadFrom(dll path)"]
    CheckCore -->|No| CompileCore["Add-Type -TypeDefinition<br/>-ReferencedAssemblies"]
    
    LoadFW --> CreateOrch["new OfficeScrubOrchestrator<br/>$script:orchestrator"]
    LoadCore --> CreateOrch
    CompileFW --> CreateOrch
    CompileCore --> CreateOrch
Loading

Sources: docs/memory-bank/structure.md:126-132, docs/memory-bank/tech.md:56-70

Fallback Compilation

If pre-compiled binaries are unavailable, blocked, or incompatible, the module compiles from source:

Add-Type Parameters:

# From OfficeScrubC2R.psm1 (conceptual)
Add-Type -TypeDefinition $sourceCode `
         -Language CSharp `
         -ReferencedAssemblies @(
             'System.Management'
             'Microsoft.CSharp'
             'System.Core'
         ) `
         -CompilerOptions '/optimize+'

Fallback Advantages:

  • Works with restrictive execution policies (bypasses DLL blocking)
  • Functions even if binaries corrupted or deleted
  • Enables source code inspection and verification
  • Supports environment-specific modifications

Compilation Performance:

  • Initial Compilation: 5-10 seconds (one-time cost)
  • Session Caching: Assembly cached for PowerShell session lifetime
  • Runtime Performance: Identical to pre-compiled DLL after loading

Sources: docs/memory-bank/tech.md:56-80, OfficeScrubC2R-Native.cs:1-17

Assembly References

Both compilation targets require the same external assemblies:

Assembly Purpose APIs Used
System.Management.dll WMI operations ManagementScope, ManagementObjectSearcher, SelectQuery
Microsoft.CSharp.dll Dynamic binding CSharpArgumentInfo, CSharpBinderFlags (for Shell.Application COM)
System.Core.dll LINQ extensions Enumerable.Any, Enumerable.ToArray, Task.Run

P/Invoke Dependencies (No external DLLs required):

  • kernel32.dll: MoveFileEx, SetFileAttributes, RemoveDirectory
  • advapi32.dll: RegOpenKeyEx, RegDeleteKeyEx, RegEnumKeyEx, RegQueryValueEx
  • shell32.dll: ILCreateFromPath, SHCreateShellItem, ILFree

Sources: OfficeScrubC2R-Native.cs:1-16, OfficeScrubC2R-Native.cs:60-167, docs/memory-bank/tech.md:82-94

Constants and Enumerations

RegistryHiveType Enum

The RegistryHiveType enum provides type-safe registry hive identifiers:

public enum RegistryHiveType
{
    ClassesRoot = unchecked((int)0x80000000),    // HKEY_CLASSES_ROOT
    CurrentUser = unchecked((int)0x80000001),    // HKEY_CURRENT_USER
    LocalMachine = unchecked((int)0x80000002),   // HKEY_LOCAL_MACHINE
    Users = unchecked((int)0x80000003)           // HKEY_USERS
}

These values match the Win32 HKEY predefined key values used in registry API calls.

Sources: OfficeScrubC2R-Native.cs:21-27

OfficeConstants Class

The OfficeConstants static class defines Office-specific constants and patterns:

Constant Value Purpose
OFFICE_ID "0000000FF1CE}" Office product GUID suffix
PROD_LEN 13 Product code length
SQUISHED 20 Encoded GUID length
COMPRESSED 32 Compressed GUID length
C2R_PATTERNS string[] Click-to-Run path detection patterns
OFFICE_PROCESSES string[] Office process names for termination

C2R Pattern Detection: The C2R_PATTERNS array contains 7 path patterns used to identify Click-to-Run installations:

  • "\ROOT\OFFICE1"
  • "Microsoft Office\Root\"
  • "\microsoft shared\ClickToRun"
  • "\Microsoft Office\PackageManifests"
  • "\Microsoft Office\PackageSunrisePolicies"
  • "Microsoft Office 15"
  • "Microsoft Office 16"

Office Process List: The OFFICE_PROCESSES array lists 24 Office-related process names that should be terminated during cleanup, including core applications (Word, Excel, PowerPoint, Outlook) and supporting processes (ClickToRun, integrator, firstrun).

Sources: OfficeScrubC2R-Native.cs:29-56

Performance Characteristics

Benchmark Comparison

Operation Pure PowerShell Native Library Speedup
Registry key enumeration (1000 keys) ~10 seconds ~0.3 seconds 30x
Recursive directory deletion ~15 seconds ~1 second 15x
Process termination (10 processes) ~2 seconds ~0.2 seconds 10x
GUID decoding (100 GUIDs) ~0.5 seconds ~0.05 seconds 10x
Overall cleanup operation 5-10 minutes 30-60 seconds 10-50x

Optimization Techniques Applied

The native library employs several performance optimization techniques:

  1. Direct Win32 API Calls: Bypass .NET registry/file abstractions
  2. Parallel Processing: Task.Run and Parallel.ForEach for concurrent operations
  3. Memory Efficiency: Span for string manipulation (zero-copy)
  4. Smart Caching: Static caching of decode tables and hive keys
  5. HashSet Lookups: O(1) deduplication vs O(n) array searches
  6. StringComparison.OrdinalIgnoreCase: 2x faster than culture-aware comparisons
  7. cmd.exe Integration: Native batch deletion faster than .NET for large trees

For detailed performance analysis, see Performance Optimizations.

Sources: docs/memory-bank/tech.md:85-95, OfficeScrubC2R-Native.cs:1-1408


This native library forms the foundation of OfficeScrubC2R's performance advantages, providing PowerShell with access to highly optimized system operations while maintaining code clarity and maintainability through the facade pattern.

Clone this wiki locally