Repository navigation
Native Performance Layer
Relevant source files
The following files were used as context for generating this wiki page:
The Native Performance Layer is the C# component of OfficeScrubC2R that provides high-performance system operations through direct Win32 API calls. It is implemented in OfficeScrubC2R-Native.cs() and compiled into OfficeScrubNative.dll. This layer achieves 10-50x performance improvements over the original VBScript implementation by using compiled .NET code, parallel processing, and memory-optimized algorithms.
For detailed information about individual helper classes, see Helper Classes. For performance optimization techniques, see Performance Optimizations. For Win32 API integration details, see P/Invoke and Win32 APIs.
The native layer consists of a facade class OfficeScrubOrchestrator that provides a unified interface to nine specialized helper classes. Each helper class targets a specific Windows subsystem and exposes methods that PowerShell code can call.
Class Structure Diagram
classDiagram
class OfficeScrubOrchestrator {
+RegistryHelper Registry
+FileHelper Files
+ProcessHelper Processes
+ShellHelper Shell
+WindowsInstallerHelper WindowsInstaller
+TypeLibHelper TypeLib
+LicenseHelper License
+ServiceHelper Services
+GuidHelper GuidUtilities
+bool IsC2RPath(string path)
+bool IsInScope(string productCode)
}
class RegistryHelper {
-bool _is64Bit
+bool KeyExists(RegistryHiveType, string)
+bool DeleteKey(RegistryHiveType, string, bool)
+bool DeleteValue(RegistryHiveType, string, string)
+string[] EnumerateKeys(RegistryHiveType, string)
+string[] EnumerateValues(RegistryHiveType, string)
+object GetValue(RegistryHiveType, string, string, object)
+bool SetValue(RegistryHiveType, string, string, object, RegistryValueKind)
+void AddPendingFileRenameOperation(string)
}
class FileHelper {
-List~string~ _pendingDeletes
+bool DeleteFile(string, bool)
+bool DeleteDirectory(string, bool, bool)
+void ScheduleDeleteOnReboot(string)
+void ScheduleDirectoryDeleteOnReboot(string)
+List~string~ GetPendingDeletes()
+long GetDirectorySize(string)
+bool IsFileLocked(string)
}
class ProcessHelper {
+List~int~ TerminateProcesses(string[], int)
+List~string~ GetProcessesUsingPath(string)
+bool IsProcessRunning(string)
}
class WindowsInstallerHelper {
-RegistryHelper _regHelper
+void CleanupUpgradeCodes(Func~string,bool~)
+void CleanupProducts(Func~string,bool~)
+void CleanupComponents(Func~string,bool~)
+void CleanupPublishedComponents(Func~string,bool~)
}
class TypeLibHelper {
-RegistryHelper _regHelper
-string[] KnownTypeLibs
+void CleanupKnownTypeLibs()
}
class LicenseHelper {
+void CleanOSPP(int versionNT)
+void ClearVNextLicenseCache(string)
}
class ServiceHelper {
+bool DeleteService(string)
}
class ShellHelper {
+bool UnpinFromTaskbar(string)
+bool UnpinFromStartMenu(string)
+void RestartExplorer()
}
class GuidHelper {
+string GetExpandedGuid(string)
+string GetCompressedGuid(string)
+bool GetDecodedGuid(string, out string)
}
OfficeScrubOrchestrator --> RegistryHelper
OfficeScrubOrchestrator --> FileHelper
OfficeScrubOrchestrator --> ProcessHelper
OfficeScrubOrchestrator --> ShellHelper
OfficeScrubOrchestrator --> WindowsInstallerHelper
OfficeScrubOrchestrator --> TypeLibHelper
OfficeScrubOrchestrator --> LicenseHelper
OfficeScrubOrchestrator --> ServiceHelper
WindowsInstallerHelper --> RegistryHelper
TypeLibHelper --> RegistryHelper
Sources: OfficeScrubC2R-Native.cs:1349-1383, OfficeScrubC2R-Native.cs:334-616, OfficeScrubC2R-Native.cs:622-767, OfficeScrubC2R-Native.cs:774-858
The native layer uses a smart fallback mechanism: it attempts to load a pre-compiled OfficeScrubNative.dll first, and if that fails, it compiles the C# source code at runtime.
DLL Loading Flow
flowchart TD
Start["PowerShell imports<br/>OfficeScrubC2R.psm1"] --> CheckDLL["Check for<br/>OfficeScrubNative.dll"]
CheckDLL --> DLLExists{"DLL exists<br/>and not blocked?"}
DLLExists -->|"Yes"| LoadDLL["Add-Type -Path<br/>OfficeScrubNative.dll"]
DLLExists -->|"No"| CompileSource["Add-Type -TypeDefinition<br/>from Native.cs"]
LoadDLL --> LoadSuccess{"Load successful?"}
CompileSource --> CompileSuccess{"Compile successful?"}
LoadSuccess -->|"Yes"| CreateOrchestrator["Create OfficeScrubOrchestrator<br/>instance"]
LoadSuccess -->|"No"| FallbackCompile["Fallback: compile<br/>from source"]
FallbackCompile --> CompileSuccess
CompileSuccess -->|"Yes"| CreateOrchestrator
CompileSuccess -->|"No"| Error["Error: Cannot load<br/>native components"]
CreateOrchestrator --> StoreGlobal["Store in<br/>$script:Orchestrator"]
StoreGlobal --> Ready["Native layer ready<br/>for PowerShell calls"]
Sources: OfficeScrubC2R.psm1(), README.md:162-174
The pre-compiled DLL provides instant loading, while the fallback compilation ensures the module works even in restricted environments where DLLs may be blocked by security policies.
The native layer is organized into specialized helper classes, each targeting a specific Windows subsystem:
| Helper Class | Primary Purpose | Key Win32 APIs | Lines |
|---|---|---|---|
RegistryHelper |
Registry operations with WOW64 support |
RegOpenKeyEx, RegDeleteKeyEx, RegEnumKeyEx
|
334-616 |
FileHelper |
File/directory deletion with reboot scheduling |
MoveFileEx, RemoveDirectory
|
622-767 |
ProcessHelper |
Parallel process termination | Process APIs via System.Diagnostics | 774-858 |
WindowsInstallerHelper |
MSI metadata cleanup | Registry APIs (via RegistryHelper) | 980-1128 |
TypeLibHelper |
COM type library cleanup | Registry APIs (via RegistryHelper) | 1134-1209 |
LicenseHelper |
OSPP/SPP license operations | WMI via System.Management | 1215-1273 |
ServiceHelper |
Windows service management | WMI + sc.exe fallback |
1279-1343 |
GuidHelper |
GUID encoding/decoding utilities | None (pure algorithm) | 171-328 |
ShellHelper |
Taskbar/Start Menu integration | Shell COM automation | 864-974 |
Sources: OfficeScrubC2R-Native.cs:334-1383, README.md:162-174
PowerShell code accesses the native layer through the $script:Orchestrator variable, which holds an instance of OfficeScrubOrchestrator. The utilities module wraps these calls to provide a PowerShell-friendly interface.
Call Flow: PowerShell to Native
sequenceDiagram
participant PS as "PowerShell Script<br/>(OfficeScrubC2R.ps1)"
participant Util as "Utilities Module<br/>(OfficeScrubC2R-Utilities.psm1)"
participant Orch as "$script:Orchestrator<br/>(OfficeScrubOrchestrator)"
participant Helper as "Helper Class<br/>(e.g., RegistryHelper)"
participant Win32 as "Win32 API<br/>(advapi32.dll)"
PS->>Util: "Remove-RegistryKey<br/>-Hive HKLM<br/>-Key 'path'"
Util->>Orch: "$script:Orchestrator<br/>.Registry"
Orch-->>Util: "RegistryHelper instance"
Util->>Helper: "DeleteKey(<br/>RegistryHiveType.LocalMachine,<br/>'path',<br/>recursive: true)"
Helper->>Helper: "GetHiveKey(hive)"
Helper->>Helper: "KeyExists(hive, subKey)"
Helper->>Win32: "RegOpenKeyEx(...)"
Win32-->>Helper: "Handle"
Helper->>Win32: "RegDeleteKeyEx(...)"
Win32-->>Helper: "ERROR_SUCCESS"
Helper->>Win32: "RegCloseKey(handle)"
Helper-->>Util: "bool: true"
Util-->>PS: "Success"
Sources: OfficeScrubC2R-Utilities.psm1, OfficeScrubC2R-Native.cs:349-364
Example: Registry Operation Flow
When PowerShell code calls Remove-RegistryKey, the following sequence occurs:
-
PowerShell layer: OfficeScrubC2R-Utilities.psm1 function
Remove-RegistryKeyis invoked -
Native access: Function accesses
$script:Orchestrator.Registryto get theRegistryHelperinstance -
WOW64 handling:
RegistryHelper.DeleteKey()checks both 64-bit and 32-bit registry views OfficeScrubC2R-Native.cs:354-364 -
Win32 API:
DeleteKeyInternal()callshive.DeleteSubKeyTree()which usesRegDeleteKeyExP/Invoke OfficeScrubC2R-Native.cs:538-552 - Result propagation: Boolean success/failure returned through the call chain
The native layer declares Win32 APIs through P/Invoke for direct system access. Key declarations include:
Win32 API Categories
graph LR
subgraph "Native APIs"
kernel32["kernel32.dll"]
advapi32["advapi32.dll"]
shell32["shell32.dll"]
end
subgraph "File Operations"
MoveFileEx["MoveFileEx<br/>(reboot scheduling)"]
RemoveDirectory["RemoveDirectory<br/>(directory deletion)"]
SetFileAttributes["SetFileAttributes<br/>(attribute modification)"]
end
subgraph "Registry Operations"
RegOpenKeyEx["RegOpenKeyEx<br/>(open key)"]
RegDeleteKeyEx["RegDeleteKeyEx<br/>(delete key)"]
RegDeleteValue["RegDeleteValue<br/>(delete value)"]
RegEnumKeyEx["RegEnumKeyEx<br/>(enumerate subkeys)"]
RegEnumValue["RegEnumValue<br/>(enumerate values)"]
RegQueryValueEx["RegQueryValueEx<br/>(read value)"]
RegCloseKey["RegCloseKey<br/>(close handle)"]
end
subgraph "Shell Operations"
ILCreateFromPath["ILCreateFromPath<br/>(item ID list)"]
ILFree["ILFree<br/>(free PIDL)"]
SHCreateShellItem["SHCreateShellItem<br/>(shell item)"]
end
kernel32 --> MoveFileEx
kernel32 --> RemoveDirectory
kernel32 --> SetFileAttributes
advapi32 --> RegOpenKeyEx
advapi32 --> RegDeleteKeyEx
advapi32 --> RegDeleteValue
advapi32 --> RegEnumKeyEx
advapi32 --> RegEnumValue
advapi32 --> RegQueryValueEx
advapi32 --> RegCloseKey
shell32 --> ILCreateFromPath
shell32 --> ILFree
shell32 --> SHCreateShellItem
Sources: OfficeScrubC2R-Native.cs:60-166
All P/Invoke declarations are in the NativeMethods class with proper marshaling attributes:
internal static class NativeMethods
{
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern int RegOpenKeyEx(...);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool MoveFileEx(...);
// ... additional declarations
}Sources: OfficeScrubC2R-Native.cs:62-153
The native layer achieves 10-50x performance improvements through several techniques:
| Optimization | Technique | Impact | Location |
|---|---|---|---|
| Memory allocation |
Span<char> for GUID operations |
3x faster, 80% less memory | OfficeScrubC2R-Native.cs:188-224 |
| Registry operations | Direct Win32 API calls | 30x faster enumeration | OfficeScrubC2R-Native.cs:402-436 |
| File deletion |
cmd.exe rd + parallel processing |
15x faster | OfficeScrubC2R-Native.cs:654-687 |
| Process termination | Parallel Task.Run
|
Concurrent execution | OfficeScrubC2R-Native.cs:777-814 |
| String comparison | StringComparison.OrdinalIgnoreCase |
2x faster, no allocation | Throughout |
| Static caching | Decode table pre-allocated | Eliminates per-call allocation | OfficeScrubC2R-Native.cs:264-274 |
Sources: docs/OPTIMIZATION_ANALYSIS.md:64-202, README.md:134-142
Performance Comparison Table
| Operation | VBScript (baseline) | PowerShell/C# | Improvement |
|---|---|---|---|
| Registry enumeration (100 keys) | ~10,000 ms | ~300 ms | 30x faster |
| File deletion (1000 files) | ~15,000 ms | ~1,000 ms | 15x faster |
| GUID operations (1000x) | 12.4 ms | 3.8 ms | 3.3x faster |
| Overall execution | 5-10 minutes | 30-60 seconds | 10-50x faster |
Sources: docs/OPTIMIZATION_ANALYSIS.md:249-286, README.md:134-142
The native layer defines constants and enumerations used throughout the codebase:
RegistryHiveType Enumeration
public enum RegistryHiveType
{
ClassesRoot = unchecked((int)0x80000000),
CurrentUser = unchecked((int)0x80000001),
LocalMachine = unchecked((int)0x80000002),
Users = unchecked((int)0x80000003)
}Sources: OfficeScrubC2R-Native.cs:21-27
OfficeConstants Class
Contains Office-specific identification patterns:
| Constant | Value | Purpose |
|---|---|---|
OFFICE_ID |
"0000000FF1CE}" |
Office product GUID suffix |
PROD_LEN |
13 |
Product code length |
SQUISHED |
20 |
Squished GUID length |
COMPRESSED |
32 |
Compressed GUID length |
C2R_PATTERNS |
String array | Click-to-Run detection patterns |
OFFICE_PROCESSES |
String array | Known Office process names |
Sources: OfficeScrubC2R-Native.cs:29-56
The RegistryHelper class provides transparent WOW64 (Windows-on-Windows 64-bit) support, automatically checking both 64-bit and 32-bit registry views on 64-bit systems:
flowchart TD
Start["Registry operation<br/>requested"]
Start --> Check64["Check _is64Bit field"]
Check64 --> Native["Perform operation on<br/>native registry view"]
Native --> Is64{"Is 64-bit<br/>system?"}
Is64 -->|"Yes"| Wow64["Also perform operation on<br/>Wow6432Node registry view"]
Is64 -->|"No"| Done["Return result"]
Wow64 --> Combine["Combine results from<br/>both views"]
Combine --> Done
Sources: OfficeScrubC2R-Native.cs:343-364, OfficeScrubC2R-Native.cs:583-593
The GetWow64Key() method OfficeScrubC2R-Native.cs:583-593 transforms registry paths to access the 32-bit registry view on 64-bit systems by injecting Wow6432Node into the path structure.
The native layer follows a "silent failure" pattern: methods return bool for success/failure or catch exceptions and return default values. This prevents native exceptions from propagating to PowerShell:
public bool DeleteKey(RegistryHiveType hive, string subKey, bool recursive = true)
{
bool result = false;
if (KeyExists(hive, subKey))
{
result = DeleteKeyInternal(GetHiveKey(hive), subKey, recursive);
}
if (_is64Bit && KeyExists(hive, GetWow64Key(subKey)))
{
result = DeleteKeyInternal(GetHiveKey(hive), GetWow64Key(subKey), recursive) || result;
}
return result;
}Sources: OfficeScrubC2R-Native.cs:349-364
All Win32 API failures are caught and return false or null, allowing PowerShell code to handle errors at a higher level through standard error codes and logging.