Skip to content

Reference

Calvindd2f edited this page Jan 14, 2026 · 1 revision

Reference

Relevant source files

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

This page provides comprehensive reference documentation for the OfficeScrubC2R system, including all constants, enums, function signatures, registry paths, error codes, and data structures. This serves as a technical lookup guide for developers working with or extending the codebase.

For usage examples and operational modes, see User Guide. For architectural patterns and design principles, see Architecture. For development guidelines and coding standards, see Developer Guide.


Constants Reference

OfficeConstants Class

The OfficeConstants class defines core constants used throughout the system for product identification and validation.

Constant Type Value Purpose
OFFICE_ID string "{0000000FF1CE}" Office product identifier suffix used in GUID validation
PROD_LEN int 13 Expected length for product identifiers
SQUISHED int 20 Length of Base85-encoded (squished) GUIDs
COMPRESSED int 32 Length of compressed GUIDs without dashes

Sources: OfficeScrubC2R-Native.cs:29-56

C2R Path Patterns

The C2R_PATTERNS array defines string patterns that identify Click-to-Run installations:

public static readonly string[] C2R_PATTERNS = new[]
{
    @"\ROOT\OFFICE1",
    @"Microsoft Office\Root\",
    @"\microsoft shared\ClickToRun",
    @"\Microsoft Office\PackageManifests",
    @"\Microsoft Office\PackageSunrisePolicies",
    @"Microsoft Office 15",
    @"Microsoft Office 16"
};

These patterns are used by OfficeScrubOrchestrator.IsC2RPath() to validate file paths and identify C2R installations.

Sources: OfficeScrubC2R-Native.cs:36-45

Office Process Names

The OFFICE_PROCESSES array defines process names that must be terminated during cleanup:

public static readonly string[] OFFICE_PROCESSES = new[]
{
    "appvshnotify.exe", "integratedoffice.exe", "integrator.exe", 
    "firstrun.exe", "communicator.exe", "msosync.exe", "OneNoteM.exe", 
    "iexplore.exe", "mavinject32.exe", "werfault.exe", "perfboost.exe", 
    "roamingoffice.exe", "officeclicktorun.exe", "officeondemand.exe", 
    "OfficeC2RClient.exe", "winword.exe", "excel.exe", "powerpnt.exe", 
    "outlook.exe", "onenote.exe", "mspub.exe", "msaccess.exe", 
    "lync.exe", "skype.exe", "teams.exe"
};

Sources: OfficeScrubC2R-Native.cs:47-55


Enums Reference

RegistryHiveType

Defines Windows Registry hive identifiers using unchecked integer casting to handle unsigned values:

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

These values correspond to the Win32 Registry API HKEY constants. The unchecked keyword is required because the hexadecimal values exceed int.MaxValue.

Usage: All RegistryHelper methods accept RegistryHiveType parameters to specify the target registry hive.

Sources: OfficeScrubC2R-Native.cs:21-27


Win32 API Constants

The NativeMethods class defines Win32 API constants for P/Invoke operations:

Registry Access Rights

Constant Value Purpose
KEY_WOW64_64KEY 0x0100 Access 64-bit registry view on WOW64
KEY_WOW64_32KEY 0x0200 Access 32-bit registry view on WOW64
KEY_READ 0x20019 Read access to registry keys
KEY_WRITE 0x20006 Write access to registry keys
KEY_ALL_ACCESS 0xF003F Full access to registry keys

File Operations

Constant Value Purpose
MOVEFILE_DELAY_UNTIL_REBOOT 0x4 Schedule file deletion on next reboot

Error Codes

Constant Value Purpose
ERROR_SUCCESS 0 Operation completed successfully
ERROR_NO_MORE_ITEMS 259 Registry enumeration complete

Sources: OfficeScrubC2R-Native.cs:62-153


Helper Classes Reference

Class Hierarchy and Dependencies

graph TB
    Orch["OfficeScrubOrchestrator"]
    RH["RegistryHelper"]
    FH["FileHelper"]
    PH["ProcessHelper"]
    SH["ShellHelper"]
    WIH["WindowsInstallerHelper"]
    TLH["TypeLibHelper"]
    LH["LicenseHelper"]
    SVH["ServiceHelper"]
    GH["GuidHelper"]
    
    Orch -->|"owns"| RH
    Orch -->|"owns"| FH
    Orch -->|"owns"| PH
    Orch -->|"owns"| SH
    Orch -->|"owns"| WIH
    Orch -->|"owns"| TLH
    Orch -->|"owns"| LH
    Orch -->|"owns"| SVH
    
    WIH -->|"uses"| RH
    WIH -->|"uses"| GH
    TLH -->|"uses"| RH
    
    style Orch fill:#f9f9f9
    style GH fill:#e9e9e9
Loading

Sources: OfficeScrubC2R-Native.cs:1313-1349


GuidHelper (Static Utility Class)

Provides GUID transformation utilities for Windows Installer metadata operations.

Methods

GetExpandedGuid
public static string GetExpandedGuid(string compressedGuid)

Parameters:

  • compressedGuid: 32-character compressed GUID (no dashes, byte-order reversed)

Returns: 38-character standard GUID format {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} or null if invalid

Purpose: Converts Windows Installer compressed GUIDs to standard format. Reverses byte order in first three segments and swaps byte pairs in remaining segments.

Example:

  • Input: D0DF45B14A8C7E47A9AAAAB346B3DBF0
  • Output: {D0498E0A-45B7-42AE-A9AA-ABA463DBD3BF}

Sources: OfficeScrubC2R-Native.cs:173-214

GetCompressedGuid
public static string GetCompressedGuid(string expandedGuid)

Parameters:

  • expandedGuid: 38-character standard GUID format with braces and dashes

Returns: 32-character compressed GUID or null if invalid

Purpose: Inverse operation of GetExpandedGuid. Converts standard GUIDs to compressed format for Windows Installer registry lookups.

Sources: OfficeScrubC2R-Native.cs:216-253

GetDecodedGuid
public static bool GetDecodedGuid(string encodedGuid, out string decodedGuid)

Parameters:

  • encodedGuid: 20-character Base85-encoded GUID
  • decodedGuid: (out) Decoded standard GUID format

Returns: true if decoding successful, false otherwise

Purpose: Decodes Base85 (ASCII85) encoded GUIDs found in published component registry data. Uses a 128-byte decode table for character-to-value mapping.

Algorithm: Processes input in 5-character chunks, each representing 4 bytes. Each chunk is decoded using base-85 arithmetic: value = Σ(char[i] × 85^i) for i=0 to 4.

Sources: OfficeScrubC2R-Native.cs:255-320


RegistryHelper

Provides registry operations with automatic WOW64 (32-bit/64-bit) handling.

Constructor

public RegistryHelper(bool is64Bit)

Parameters:

  • is64Bit: System architecture flag (determines WOW64 behavior)

Key Methods

KeyExists
public bool KeyExists(RegistryHiveType hive, string subKey)

Behavior: On 64-bit systems, checks both native 64-bit view and WOW64 32-bit view.

Sources: OfficeScrubC2R-Native.cs:343-347

DeleteKey
public bool DeleteKey(RegistryHiveType hive, string subKey, bool recursive = true)

Parameters:

  • hive: Target registry hive
  • subKey: Registry key path
  • recursive: If true, deletes all subkeys recursively

Returns: true if any deletion occurred (native or WOW64 view)

Behavior: On 64-bit systems, attempts deletion in both views. Uses DeleteSubKeyTree() for recursive deletion.

Sources: OfficeScrubC2R-Native.cs:349-364

DeleteValue
public bool DeleteValue(RegistryHiveType hive, string subKey, string valueName)

Purpose: Deletes a named value from a registry key. Handles both registry views on 64-bit systems.

Sources: OfficeScrubC2R-Native.cs:366-400

EnumerateKeys
public string[] EnumerateKeys(RegistryHiveType hive, string subKey)

Returns: Distinct subkey names from both registry views (case-insensitive)

Implementation: Uses HashSet<string> with StringComparer.OrdinalIgnoreCase to deduplicate results from both views.

Sources: OfficeScrubC2R-Native.cs:402-436

EnumerateValues
public string[] EnumerateValues(RegistryHiveType hive, string subKey)

Returns: Distinct value names from both registry views

Sources: OfficeScrubC2R-Native.cs:438-472

GetValue
public object GetValue(RegistryHiveType hive, string subKey, string valueName, 
                       object defaultValue = null)

Behavior: Attempts native view first, then WOW64 view on 64-bit systems.

Sources: OfficeScrubC2R-Native.cs:474-502

SetValue
public bool SetValue(RegistryHiveType hive, string subKey, string valueName, 
                     object value, RegistryValueKind kind)

Behavior: Creates key if it doesn't exist. Only writes to native view.

Sources: OfficeScrubC2R-Native.cs:504-521

AddPendingFileRenameOperation
public void AddPendingFileRenameOperation(string filePath)

Purpose: Adds entry to HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations for deletion on reboot.

Format: Adds two entries: \\??\{filePath} followed by empty string.

Sources: OfficeScrubC2R-Native.cs:595-615

WOW64 Path Transformation

The private GetWow64Key() method transforms registry paths for 32-bit view access:

Input Pattern Transformation Output Pattern
Software\Classes\X Insert after Classes\ Software\Classes\Wow6432Node\X
Software\X Insert after first \ Software\Wow6432Node\X
X Prepend Wow6432Node\X

Sources: OfficeScrubC2R-Native.cs:583-593


FileHelper

Provides file system operations with reboot scheduling for locked files.

Methods

DeleteFile
public bool DeleteFile(string filePath, bool scheduleOnFail = true)

Behavior:

  1. Returns true if file doesn't exist
  2. Removes ReadOnly attribute if present
  3. Attempts File.Delete()
  4. On failure, schedules deletion via MoveFileEx if scheduleOnFail is true

Sources: OfficeScrubC2R-Native.cs:626-651

DeleteDirectory
public bool DeleteDirectory(string directoryPath, bool recursive = true, 
                           bool scheduleOnFail = true)

Performance Optimization: First attempts deletion using cmd.exe /c rd /s /q for 15x performance improvement on large directories. Falls back to Directory.Delete() if command fails.

Reboot Scheduling: If deletion fails and scheduleOnFail is true, schedules all files first, then directories in reverse depth order (deepest first).

Sources: OfficeScrubC2R-Native.cs:653-687

ScheduleDeleteOnReboot
public void ScheduleDeleteOnReboot(string filePath)

Implementation: Calls MoveFileEx(filePath, null, MOVEFILE_DELAY_UNTIL_REBOOT) and tracks in _pendingDeletes list.

Sources: OfficeScrubC2R-Native.cs:689-697

ScheduleDirectoryDeleteOnReboot
public void ScheduleDirectoryDeleteOnReboot(string directoryPath)

Algorithm:

  1. Enumerate all files recursively and schedule each
  2. Enumerate directories and sort by length descending
  3. Schedule directories in reverse depth order
  4. Schedule root directory last

Rationale: Windows processes PendingFileRenameOperations sequentially, so parent directories must be scheduled after their contents.

Sources: OfficeScrubC2R-Native.cs:699-727

GetPendingDeletes
public List<string> GetPendingDeletes()

Returns: Copy of internal _pendingDeletes list for reporting purposes.

Sources: OfficeScrubC2R-Native.cs:729-732

IsFileLocked
public bool IsFileLocked(string filePath)

Implementation: Attempts to open file with FileShare.None. Returns true if IOException is thrown.

Sources: OfficeScrubC2R-Native.cs:750-766


ProcessHelper

Provides process management with parallel termination capabilities.

Methods

TerminateProcesses
public List<int> TerminateProcesses(string[] processNames, int timeoutMs = 5000)

Parameters:

  • processNames: Array of process names (with or without .exe extension)
  • timeoutMs: Timeout per process for WaitForExit()

Returns: List of successfully terminated process IDs

Algorithm:

  1. Enumerate all matching processes
  2. Create Task.Run() for each process
  3. Each task: check !HasExited, call Kill(), wait for exit with timeout
  4. Use lock(terminatedPids) for thread-safe list updates
  5. Call Task.WaitAll(tasks, timeoutMs * 2) to wait for all tasks

Performance: Parallel execution provides significant speedup when terminating multiple Office applications simultaneously.

Sources: OfficeScrubC2R-Native.cs:775-814

GetProcessesUsingPath
public List<string> GetProcessesUsingPath(string path)

Purpose: Identifies processes with executable paths under specified directory.

Implementation: Enumerates all processes, checks MainModule.FileName with case-insensitive prefix match.

Sources: OfficeScrubC2R-Native.cs:816-842

IsProcessRunning
public bool IsProcessRunning(string processName)

Returns: true if any instance of the process is running

Sources: OfficeScrubC2R-Native.cs:844-857


WindowsInstallerHelper

Provides cleanup of Windows Installer metadata for Office products.

Constructor

public WindowsInstallerHelper(RegistryHelper regHelper)

Dependency: Requires RegistryHelper for registry operations and WOW64 support.

Methods

CleanupUpgradeCodes
public void CleanupUpgradeCodes(Func<string, bool> shouldDelete)

Purpose: Removes upgrade code entries from HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes

Algorithm:

  1. Enumerate 32-character subkeys
  2. Expand each to standard GUID format using GuidHelper.GetExpandedGuid()
  3. Pass to shouldDelete callback (typically OfficeScrubOrchestrator.IsInScope())
  4. Delete if callback returns true

Sources: OfficeScrubC2R-Native.cs:989-1011

CleanupProducts
public void CleanupProducts(Func<string, bool> shouldDelete)

Registry Paths:

  • HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products
  • HKCR\Installer\Products

Sources: OfficeScrubC2R-Native.cs:1013-1039

CleanupComponents
public void CleanupComponents(Func<string, bool> shouldDelete)

Purpose: Removes component value entries where the value name is an Office product GUID.

Registry Path: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components

Algorithm: Enumerates component keys, then enumerates values within each. Deletes value if its name (32-char compressed GUID) expands to an in-scope product.

Sources: OfficeScrubC2R-Native.cs:1041-1067

CleanupPublishedComponents
public void CleanupPublishedComponents(Func<string, bool> shouldDelete)

Purpose: Cleans Base85-encoded GUIDs from multi-string registry values.

Registry Path: HKCR\Installer\Components

Algorithm:

  1. Enumerate component keys and their values
  2. Read REG_MULTI_SZ data
  3. For each string in multi-string data:
    • Extract first 20 characters (Base85-encoded GUID)
    • Decode using GuidHelper.GetDecodedGuid()
    • Test with shouldDelete callback
  4. If modifications made, update or delete value

Sources: OfficeScrubC2R-Native.cs:1069-1094


TypeLibHelper

Manages COM type library registry cleanup.

Known Type Libraries

The class maintains a static array of 73 known Office type library GUIDs:

private static readonly string[] KnownTypeLibs = new[]
{
    "{000204EF-0000-0000-C000-000000000046}", // Office Object Library
    "{00020813-0000-0000-C000-000000000046}", // Excel Object Library
    // ... 71 more entries
};

Sources: OfficeScrubC2R-Native.cs:1106-1118

Methods

CleanupKnownTypeLibs
public void CleanupKnownTypeLibs()

Registry Path: HKLM\Software\Classes\TypeLib\{GUID}

Algorithm:

  1. For each known type library GUID:
    • Enumerate version subkeys
    • For each version, check platform-specific paths:
      • {version}\0\Win32
      • {version}\9\Win32
      • {version}\0\Win64
      • {version}\9\Win64
    • Read default value (file path)
    • Check if file exists
    • Delete version key if no file exists
  2. Delete type library key if all versions removed

File Path Handling: Extracts safe file path by taking substring up to LastIndexOf('.') + 4 to avoid issues with embedded paths in registry data.

Sources: OfficeScrubC2R-Native.cs:1126-1176


LicenseHelper

Provides Office license cleanup operations.

Methods

CleanOSPP
public void CleanOSPP(int versionNT)

Parameters:

  • versionNT: OS version number (> 601 uses SoftwareLicensingProduct, else OfficeSoftwareProtectionProduct)

Purpose: Removes Office licenses from Software Protection Platform (SPP/OSPP).

WMI Query:

SELECT ProductKeyID FROM SoftwareLicensingProduct 
WHERE ApplicationId = '0ff1ce15-a989-479d-af46-f275c6370663' 
AND PartialProductKey <> NULL

Action: Calls UninstallProductKey() method on each matching license.

Sources: OfficeScrubC2R-Native.cs:1184-1219

ClearVNextLicenseCache
public void ClearVNextLicenseCache(string localAppData)

Purpose: Deletes local license cache directories for vNext licensing.

Paths Deleted:

  • {LocalAppData}\Microsoft\Office\Licenses
  • {LocalAppData}\Microsoft\Office\15.0\Licensing
  • {LocalAppData}\Microsoft\Office\16.0\Licensing

Sources: OfficeScrubC2R-Native.cs:1221-1239


ServiceHelper

Provides Windows service management operations.

Methods

DeleteService
public bool DeleteService(string serviceName)

Parameters:

  • serviceName: Service name (supports wildcard suffix via LIKE query)

Algorithm:

  1. Primary Method: WMI
    • Query: SELECT * FROM Win32_Service WHERE Name LIKE '{serviceName}%'
    • Stop service if running: service.InvokeMethod("StopService", null)
    • Delete: service.InvokeMethod("Delete", null)
  2. Fallback Method: sc.exe
    • Command: sc.exe delete {serviceName}
    • Returns true if exit code is 0

Sources: OfficeScrubC2R-Native.cs:1247-1309


ShellHelper

Provides Windows Shell integration operations.

Methods

UnpinFromTaskbar
public bool UnpinFromTaskbar(string shortcutPath)

Purpose: Unpins Office shortcuts from Windows taskbar.

Implementation:

  1. Uses Shell.Application COM object
  2. Enumerates verbs for the shortcut file
  3. Matches verb names against localized strings for "unpin from taskbar"
  4. Invokes matching verb

Supported Languages: English, German, French, Spanish, Swedish, Danish, Czech, Dutch, Finnish, Italian

Sources: OfficeScrubC2R-Native.cs:866-907

UnpinFromStartMenu
public bool UnpinFromStartMenu(string shortcutPath)

Purpose: Unpins Office shortcuts from Start menu.

Implementation: Similar to UnpinFromTaskbar but matches "unpin from start" verb patterns.

Sources: OfficeScrubC2R-Native.cs:909-948

RestartExplorer
public void RestartExplorer()

Purpose: Terminates and restarts Windows Explorer to release file locks.

Algorithm:

  1. Get all explorer processes
  2. Kill each with 5-second timeout
  3. Wait 1 second
  4. Start new explorer.exe instance

Sources: OfficeScrubC2R-Native.cs:950-973


OfficeScrubOrchestrator

Central coordinator class that orchestrates all helper classes and provides high-level cleanup logic.

Properties

public RegistryHelper Registry { get; private set; }
public FileHelper Files { get; private set; }
public ProcessHelper Processes { get; private set; }
public ShellHelper Shell { get; private set; }
public WindowsInstallerHelper WindowsInstaller { get; private set; }
public TypeLibHelper TypeLib { get; private set; }
public LicenseHelper License { get; private set; }
public ServiceHelper Services { get; private set; }

Sources: OfficeScrubC2R-Native.cs:1330-1337

Constructor

public OfficeScrubOrchestrator(bool is64Bit)

Initialization: Instantiates all helper classes. RegistryHelper is initialized with is64Bit flag and passed to helpers that need registry access.

Sources: OfficeScrubC2R-Native.cs:1339-1349

Product Scope Validation Methods

IsC2RPath
public bool IsC2RPath(string path)

Purpose: Determines if a file path belongs to a Click-to-Run installation.

Implementation: Returns true if path contains any pattern from OfficeConstants.C2R_PATTERNS (case-insensitive).

Sources: OfficeScrubC2R-Native.cs:1352-1359

IsInScope
public bool IsInScope(string productCode)

Purpose: Determines if a product GUID is within removal scope.

Validation Steps:

  1. Check length is exactly 38 characters
  2. Check if in special products set (3 hard-coded GUIDs)
  3. Check if ends with OfficeConstants.OFFICE_ID
  4. Parse version from positions 3-4, reject if ≤ 14
  5. Extract SKU from positions 10-13, check if in valid SKUs set

Special Products:

  • {6C1ADE97-24E1-4AE4-AEDD-86D3A209CE60}
  • {9520DDEB-237A-41DB-AA20-F2EF2360DCEB}
  • {9AC08E99-230B-47E8-9721-4577B7F124EA}

Valid SKUs: 007E, 008F, 008C, 24E1, 237A, 00DD

Sources: OfficeScrubC2R-Native.cs:1361-1382, OfficeScrubC2R-Native.cs:1318-1328


Registry Paths Reference

Click-to-Run Configuration Paths

Registry Path Purpose Data Format
HKLM\SOFTWARE\Microsoft\Office\15.0\ClickToRun Office 2013 C2R configuration Various
HKLM\SOFTWARE\Microsoft\Office\16.0\ClickToRun Office 2016/2019 C2R configuration Various
HKLM\SOFTWARE\Microsoft\Office\ClickToRun Modern Office C2R configuration Various
HKLM\SOFTWARE\Microsoft\Office\15.0\ClickToRun\Configuration O15 product configuration REG_SZ
HKLM\SOFTWARE\Microsoft\Office\16.0\ClickToRun\Configuration O16 product configuration REG_SZ
HKLM\SOFTWARE\Microsoft\Office\ClickToRun\Configuration Modern product configuration REG_SZ

Key Values:

  • PackageFolder (REG_SZ): Installation directory path
  • PackageGUID (REG_SZ): Package identifier GUID
  • ProductReleaseIds (REG_SZ): Comma-separated list of installed products

Sources: direct_conversion.cs:881-888

Product Release ID Paths

Registry Path Purpose
HKLM\SOFTWARE\Microsoft\Office\15.0\ClickToRun\ProductReleaseIDs\Active\culture O15 product versions by culture
HKLM\SOFTWARE\Microsoft\Office\16.0\ClickToRun\ProductReleaseIDs\Active\culture O16 product versions by culture
HKLM\SOFTWARE\Microsoft\Office\ClickToRun\ProductReleaseIDs Modern product release tracking
HKLM\SOFTWARE\Microsoft\Office\ClickToRun\ProductReleaseIDs\{ActiveConfiguration} Active configuration products

Values: Version strings (e.g., "16.0.12345.67890")

Sources: direct_conversion.cs:883-888

Windows Installer Metadata Paths

graph LR
    subgraph "HKLM Paths"
        UC["UpgradeCodes<br/>SOFTWARE\Microsoft\Windows\<br/>CurrentVersion\Installer\<br/>UpgradeCodes"]
        PROD["Products<br/>SOFTWARE\Microsoft\Windows\<br/>CurrentVersion\Installer\<br/>UserData\S-1-5-18\Products"]
        COMP["Components<br/>SOFTWARE\Microsoft\Windows\<br/>CurrentVersion\Installer\<br/>UserData\S-1-5-18\Components"]
    end
    
    subgraph "HKCR Paths"
        IPROD["Installer\Products"]
        ICOMP["Installer\Components"]
        IFEAT["Installer\Features"]
    end
    
    UC -->|"32-char compressed GUID keys"| PROD
    PROD -->|"32-char compressed GUID keys"| COMP
    IPROD -.->|"duplicate metadata"| PROD
    ICOMP -->|"20-char Base85 values"| COMP
Loading

Sources: OfficeScrubC2R-Native.cs:989-1094

ARP (Add/Remove Programs) Paths

Registry Path Purpose Notes
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall 64-bit application registry Native view
HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall 32-bit application registry WOW64 view

Key Values:

  • DisplayName (REG_SZ): Product display name
  • DisplayVersion (REG_SZ): Version string
  • UninstallString (REG_SZ): Uninstall command
  • SystemComponent (REG_DWORD): If 1, hidden from UI

Sources: direct_conversion.cs:881-882

Shell Integration Paths

Registry Path Purpose
HKLM\SOFTWARE\Classes\Protocols\Handler\osf Office protocol handler
HKLM\SOFTWARE\Classes\CLSID\{...} Context menu handlers
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers Icon overlays
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects Browser extensions
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved Approved extensions

Sources: direct_conversion.cs:2336-2376

Type Library Paths

Registry Path Purpose Format
HKLM\Software\Classes\TypeLib\{GUID} Type library registration root GUID key
HKLM\Software\Classes\TypeLib\{GUID}\{version} Version-specific registration Version string
HKLM\Software\Classes\TypeLib\{GUID}\{version}\0\Win32 32-bit neutral path File path
HKLM\Software\Classes\TypeLib\{GUID}\{version}\9\Win32 32-bit locale path File path
HKLM\Software\Classes\TypeLib\{GUID}\{version}\0\Win64 64-bit neutral path File path
HKLM\Software\Classes\TypeLib\{GUID}\{version}\9\Win64 64-bit locale path File path

Sources: OfficeScrubC2R-Native.cs:1126-1176

Pending File Operations Path

Registry Path Value Name Type Purpose
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager PendingFileRenameOperations REG_MULTI_SZ Files to delete/rename on reboot

Format: Pairs of strings where first is source path prefixed with \\??\ and second is empty string for deletion.

Sources: OfficeScrubC2R-Native.cs:595-615


GUID Format Reference

Windows Installer uses three GUID encodings for metadata storage:

Format Comparison Table

Format Length Example Used In
Expanded 38 chars {D0498E0A-45B7-42AE-A9AA-ABA463DBD3BF} Standard representation
Compressed 32 chars D0DF45B14A8C7E47A9AAAAB346B3DBF0 Registry key names
Base85 20 chars "_@5%G'!O75'G4@5%" Multi-string values

Sources: OfficeScrubC2R-Native.cs:29-34

GUID Transformation Diagram

graph TB
    EXP["Expanded GUID<br/>{D0498E0A-45B7-42AE-A9AA-ABA463DBD3BF}"]
    COMP["Compressed GUID<br/>D0DF45B14A8C7E47A9AAAAB346B3DBF0"]
    B85["Base85 Encoded<br/>20-char ASCII string"]
    
    EXP -->|"GetCompressedGuid()<br/>Remove braces/dashes<br/>Reverse byte order"| COMP
    COMP -->|"GetExpandedGuid()<br/>Add braces/dashes<br/>Reverse byte order"| EXP
    
    B85 -->|"GetDecodedGuid()<br/>Base85 decode<br/>Reorder segments"| EXP
    
    subgraph "Compression Algorithm"
        direction LR
        S1["Segment 1: 8 chars"]
        S2["Segment 2: 4 chars"]
        S3["Segment 3: 4 chars"]
        S4["Segment 4: 4 chars"]
        S5["Segment 5: 12 chars"]
        
        S1 -.->|"Reverse"| S1
        S2 -.->|"Reverse"| S2
        S3 -.->|"Reverse"| S3
        S4 -.->|"Swap pairs"| S4
        S5 -.->|"Swap pairs"| S5
    end
    
    subgraph "Base85 Decoding"
        direction LR
        C1["5 chars"]
        C2["5 chars"]
        C3["5 chars"]
        C4["5 chars"]
        
        C1 -.->|"Σ(char[i] × 85^i)"| B1["4 bytes"]
        C2 -.->|"Σ(char[i] × 85^i)"| B2["4 bytes"]
        C3 -.->|"Σ(char[i] × 85^i)"| B3["4 bytes"]
        C4 -.->|"Σ(char[i] × 85^i)"| B4["4 bytes"]
    end
Loading

Sources: OfficeScrubC2R-Native.cs:169-328

Compressed GUID Algorithm Details

Input: {D0498E0A-45B7-42AE-A9AA-ABA463DBD3BF}

Step 1: Remove braces and dashes

  • Result: D0498E0A45B742AEA9AAABA463DBD3BF

Step 2: Process segments

  1. First 8 chars: Reverse → A0E89804D
  2. Next 4 chars: Reverse → 7B54
  3. Next 4 chars: Reverse → EA24
  4. Next 4 chars: Swap pairs → A9AA → 9AAA
  5. Last 12 chars: Swap pairs → ABA463DBD3BF → BA4A36BD3DBF

Step 3: Concatenate

  • Result: D0DF45B14A8C7E47A9AAAAB346B3DBF0

Sources: OfficeScrubC2R-Native.cs:216-253

Base85 Decode Table

The decode table maps ASCII characters (32-127) to Base85 values (0-84):

ASCII Range Mapping
33 (!) 0x00
34-44 (" to ,) 0x01-0x0B
45 (-) Invalid (0xFF)
46-57 (. to 9) 0x0B-0x15
58-61 (: to =) Invalid (0xFF)
62 (>) 0x16
63 (?) 0x17
64-90 (@ to Z) 0x18-0x32
91 ([) Invalid (0xFF)
92-94 (\ to ^) 0x34-0x36
95-122 (_ to z) 0x37-0x52
123 ({) Invalid (0xFF)
124-126 (` to~`)

Invalid characters (marked 0xFF) will cause GetDecodedGuid() to return false.

Sources: OfficeScrubC2R-Native.cs:264-274


Error Codes Reference

VBScript Legacy Error Codes

The original VBScript implementation defined these error codes (documented for reference, not used in C# version):

Constant Value Description
ERROR_SUCCESS 0 Operation completed successfully
ERROR_FAIL 1 General failure
ERROR_REBOOT_REQUIRED 2 System reboot required
ERROR_USERCANCEL 4 User canceled operation
ERROR_STAGE1 8 Stage 1 (Uninstall) failed
ERROR_STAGE2 16 Stage 2 (Cleanup) failed
ERROR_INCOMPLETE 32 Removal incomplete
ERROR_DCAF_FAILURE 64 Second cleanup attempt failed
ERROR_ELEVATION_USERDECLINED 128 User declined elevation prompt
ERROR_ELEVATION 256 Elevation failed
ERROR_SCRIPTINIT 512 Initialization error
ERROR_RELAUNCH 1024 Relaunch attempt failed
ERROR_UNKNOWN 2048 Unknown error
ERROR_ALL 4095 All error flags set
ERROR_USER_ABORT -1073741510 Process terminated
ERROR_SUCCESS_CONFIG_COMPLETE 1728 MSI config complete
ERROR_SUCCESS_REBOOT_REQUIRED 3010 MSI success, reboot required

Note: These are bitwise flags that can be combined using OR operations.

Sources: direct_conversion.cs:45-61

Win32 API Error Codes

Used in P/Invoke operations:

Code Value Meaning
ERROR_SUCCESS 0 Success
ERROR_NO_MORE_ITEMS 259 Registry enumeration complete

Sources: OfficeScrubC2R-Native.cs:151-152


P/Invoke Function Reference

NativeMethods Class

All P/Invoke declarations are contained in the internal static NativeMethods class.

Kernel32.dll Functions

MoveFileEx
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool MoveFileEx(
    string lpExistingFileName,
    string lpNewFileName,
    int dwFlags);

Purpose: Schedule file deletion on reboot when lpNewFileName is null and dwFlags is MOVEFILE_DELAY_UNTIL_REBOOT.

Sources: OfficeScrubC2R-Native.cs:64-68

SetFileAttributes
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetFileAttributes(
    string lpFileName,
    uint dwFileAttributes);

Purpose: Modify file attributes (used to remove ReadOnly before deletion).

Sources: OfficeScrubC2R-Native.cs:138-140

RemoveDirectory
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool RemoveDirectory(string lpPathName);

Purpose: Alternative directory deletion method (not currently used).

Sources: OfficeScrubC2R-Native.cs:143

Advapi32.dll Functions (Registry)

RegOpenKeyEx
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int RegOpenKeyEx(
    UIntPtr hKey,
    string lpSubKey,
    uint ulOptions,
    int samDesired,
    out UIntPtr phkResult);

Purpose: Open registry key with specific access rights and view flags.

Sources: OfficeScrubC2R-Native.cs:70-76

RegDeleteKeyEx
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern int RegDeleteKeyEx(
    UIntPtr hKey,
    string lpSubKey,
    int samDesired,
    uint Reserved);

Purpose: Delete registry key with specific view flag (KEY_WOW64_64KEY or KEY_WOW64_32KEY).

Sources: OfficeScrubC2R-Native.cs:82-86

RegEnumKeyEx
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern int RegEnumKeyEx(
    UIntPtr hKey,
    uint dwIndex,
    StringBuilder lpName,
    ref uint lpcchName,
    IntPtr lpReserved,
    IntPtr lpClass,
    IntPtr lpcchClass,
    IntPtr lpftLastWriteTime);

Purpose: Enumerate subkeys of a registry key.

Sources: OfficeScrubC2R-Native.cs:94-102

RegEnumValue
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern int RegEnumValue(
    UIntPtr hKey,
    uint dwIndex,
    StringBuilder lpValueName,
    ref uint lpcchValueName,
    IntPtr lpReserved,
    IntPtr lpType,
    IntPtr lpData,
    IntPtr lpcbData);

Purpose: Enumerate values within a registry key.

Sources: OfficeScrubC2R-Native.cs:105-113

RegQueryValueEx
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int RegQueryValueEx(
    UIntPtr hKey,
    string lpValueName,
    IntPtr lpReserved,
    out uint lpType,
    IntPtr lpData,
    ref uint lpcbData);

Purpose: Read registry value data.

Sources: OfficeScrubC2R-Native.cs:116-122

Shell32.dll Functions

ILCreateFromPath
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr ILCreateFromPath(string pszPath);

Purpose: Create item identifier list from file path.

Sources: OfficeScrubC2R-Native.cs:125

ILFree
[DllImport("shell32.dll")]
internal static extern void ILFree(IntPtr pidl);

Purpose: Free item identifier list memory.

Sources: OfficeScrubC2R-Native.cs:128

SHCreateShellItem
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
internal static extern int SHCreateShellItem(
    IntPtr pidlParent,
    IntPtr psfParent,
    IntPtr pidl,
    out IShellItem ppsi);

Purpose: Create shell item from item identifier list.

Sources: OfficeScrubC2R-Native.cs:131-135

COM Interfaces

IShellItem
[ComImport]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IShellItem
{
    void BindToHandler(IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid bhid, 
                       [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IntPtr ppv);
    void GetParent(out IShellItem ppsi);
    void GetDisplayName(uint sigdnName, out IntPtr ppszName);
    void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
    void Compare(IShellItem psi, uint hint, out int piOrder);
}

Purpose: Shell item interface for file system operations.

Sources: OfficeScrubC2R-Native.cs:155-165


Data Structure Reference

HashSet Collections in Orchestrator

The orchestrator uses static HashSet collections for O(1) lookup performance:

private static readonly HashSet<string> ValidSkus = new HashSet<string>
{
    "007E", "008F", "008C", "24E1", "237A", "00DD"
};

private static readonly HashSet<string> SpecialProducts = new HashSet<string>
{
    "{6C1ADE97-24E1-4AE4-AEDD-86D3A209CE60}",
    "{9520DDEB-237A-41DB-AA20-F2EF2360DCEB}",
    "{9AC08E99-230B-47E8-9721-4577B7F124EA}"
};

Performance: These static collections eliminate repeated array traversal in IsInScope() validation logic.

Sources: OfficeScrubC2R-Native.cs:1318-1328

Internal State Collections

FileHelper

private readonly List<string> _pendingDeletes = new List<string>();

Tracks files scheduled for deletion on reboot via PendingFileRenameOperations.

Sources: OfficeScrubC2R-Native.cs:624

ProcessHelper

lock (terminatedPids)
{
    terminatedPids.Add(pid);
}

Thread-safe list updated from parallel tasks during process termination.

Sources: OfficeScrubC2R-Native.cs:796-799


Function Signature Summary Table

GuidHelper Methods

Method Input Output Complexity
GetExpandedGuid 32-char string 38-char GUID or null O(1)
GetCompressedGuid 38-char GUID 32-char string or null O(1)
GetDecodedGuid 20-char Base85 bool + out GUID O(1)

RegistryHelper Methods

Method WOW64 Aware Returns Purpose
KeyExists Yes bool Check key existence
DeleteKey Yes bool Delete key and subkeys
DeleteValue Yes bool Delete named value
EnumerateKeys Yes string[] List subkeys (merged)
EnumerateValues Yes string[] List values (merged)
GetValue Yes object Read value data
SetValue No bool Write value data

FileHelper Methods

Method Schedules on Fail Returns Purpose
DeleteFile Optional bool Delete single file
DeleteDirectory Optional bool Delete directory tree
ScheduleDeleteOnReboot N/A void Schedule file deletion
ScheduleDirectoryDeleteOnReboot N/A void Schedule dir deletion
GetPendingDeletes N/A List Get scheduled items
IsFileLocked N/A bool Check file lock status

ProcessHelper Methods

Method Parallel Returns Purpose
TerminateProcesses Yes List Kill processes by name
GetProcessesUsingPath No List Find processes in path
IsProcessRunning No bool Check if process exists

Sources: OfficeScrubC2R-Native.cs:171-1382


Code Entity to System Mapping

This diagram maps high-level system concepts to specific code entities for easy code navigation:

graph TB
    subgraph "Natural Language Concepts"
        C2R["Click-to-Run Detection"]
        GUID_OPS["GUID Transformation"]
        REG_CLEAN["Registry Cleanup"]
        FILE_CLEAN["File Cleanup"]
        PROC_TERM["Process Termination"]
        MSI_META["MSI Metadata Cleanup"]
    end
    
    subgraph "Code Entities"
        C2R_PATH["OfficeScrubOrchestrator.IsC2RPath()"]
        C2R_CONST["OfficeConstants.C2R_PATTERNS"]
        
        GUID_EXP["GuidHelper.GetExpandedGuid()"]
        GUID_COMP["GuidHelper.GetCompressedGuid()"]
        GUID_DEC["GuidHelper.GetDecodedGuid()"]
        
        REG_DEL["RegistryHelper.DeleteKey()"]
        REG_ENUM["RegistryHelper.EnumerateKeys()"]
        REG_WOW["RegistryHelper.GetWow64Key()"]
        
        FILE_DEL["FileHelper.DeleteDirectory()"]
        FILE_SCHED["FileHelper.ScheduleDeleteOnReboot()"]
        FILE_PEND["RegistryHelper.AddPendingFileRenameOperation()"]
        
        PROC_KILL["ProcessHelper.TerminateProcesses()"]
        PROC_LIST["OfficeConstants.OFFICE_PROCESSES"]
        
        MSI_UPG["WindowsInstallerHelper.CleanupUpgradeCodes()"]
        MSI_PROD["WindowsInstallerHelper.CleanupProducts()"]
        MSI_COMP["WindowsInstallerHelper.CleanupComponents()"]
        MSI_PUB["WindowsInstallerHelper.CleanupPublishedComponents()"]
    end
    
    C2R --> C2R_PATH
    C2R --> C2R_CONST
    
    GUID_OPS --> GUID_EXP
    GUID_OPS --> GUID_COMP
    GUID_OPS --> GUID_DEC
    
    REG_CLEAN --> REG_DEL
    REG_CLEAN --> REG_ENUM
    REG_CLEAN --> REG_WOW
    
    FILE_CLEAN --> FILE_DEL
    FILE_CLEAN --> FILE_SCHED
    FILE_CLEAN --> FILE_PEND
    
    PROC_TERM --> PROC_KILL
    PROC_TERM --> PROC_LIST
    
    MSI_META --> MSI_UPG
    MSI_META --> MSI_PROD
    MSI_META --> MSI_COMP
    MSI_META --> MSI_PUB
Loading

Sources: OfficeScrubC2R-Native.cs:1-1915


Registry Operation Code Flow

This diagram shows the code path for registry operations with WOW64 support:

graph TB
    CALL["Client Code:<br/>regHelper.DeleteKey(HKLM, 'SOFTWARE\X', true)"]
    
    DELETE["RegistryHelper.DeleteKey()"]
    
    CHECK64{"_is64Bit == true?"}
    
    NATIVE_EXISTS["KeyExists(hive, subKey)"]
    NATIVE_DELETE["DeleteKeyInternal(hive, subKey, recursive)"]
    
    WOW_TRANSFORM["GetWow64Key(subKey)<br/>Returns: 'SOFTWARE\Wow6432Node\X'"]
    WOW_EXISTS["KeyExists(hive, wow64Key)"]
    WOW_DELETE["DeleteKeyInternal(hive, wow64Key, recursive)"]
    
    OPEN_NATIVE["GetHiveKey(hive).OpenSubKey(subKey, false)"]
    OPEN_WOW["GetHiveKey(hive).OpenSubKey(wow64Key, false)"]
    
    DEL_NATIVE["GetHiveKey(hive).DeleteSubKeyTree(subKey, false)"]
    DEL_WOW["GetHiveKey(hive).DeleteSubKeyTree(wow64Key, false)"]
    
    RESULT["Return: (native || wow64) result"]
    
    CALL --> DELETE
    DELETE --> CHECK64
    
    CHECK64 -->|"Yes"| NATIVE_EXISTS
    CHECK64 -->|"No"| NATIVE_EXISTS
    
    NATIVE_EXISTS -->|"Exists"| NATIVE_DELETE
    
    NATIVE_DELETE --> OPEN_NATIVE
    OPEN_NATIVE --> DEL_NATIVE
    
    DEL_NATIVE --> CHECK64_POST{"_is64Bit?"}
    
    CHECK64_POST -->|"Yes"| WOW_TRANSFORM
    CHECK64_POST -->|"No"| RESULT
    
    WOW_TRANSFORM --> WOW_EXISTS
    WOW_EXISTS -->|"Exists"| WOW_DELETE
    WOW_EXISTS -->|"Not Exists"| RESULT
    
    WOW_DELETE --> OPEN_WOW
    OPEN_WOW --> DEL_WOW
    DEL_WOW --> RESULT
Loading

Sources: OfficeScrubC2R-Native.cs:349-593


This reference documentation provides comprehensive coverage of all public APIs, constants, data structures, and code entities within the OfficeScrubC2R system. For usage examples and architectural patterns, refer to the related wiki pages listed at the beginning of this document.

Clone this wiki locally