Private/NativeHelper.ps1
|
# --------------------------------------------------------------------------- # Native helper - CWD reading via PEB, window control via user32 # --------------------------------------------------------------------------- function Initialize-NativeHelper { if ($script:NativeHelperLoaded) { return } $csPath = Join-Path (Join-Path $PSScriptRoot 'lib') 'ProcessHelper.cs' if (Test-Path $csPath) { try { $csCode = [System.IO.File]::ReadAllText($csPath) Add-Type -TypeDefinition $csCode -ErrorAction Stop $script:NativeHelperLoaded = $true } catch { # Type may already be loaded in this session if ([Type]::GetType('TTProcessHelper') -or ('TTProcessHelper' -as [type])) { $script:NativeHelperLoaded = $true } } } } function Get-ProcessCwd { <# Read the current working directory of a process via its PEB. #> param([int]$ProcessId) Initialize-NativeHelper if (-not $script:NativeHelperLoaded) { return $null } try { [TTProcessHelper]::GetWorkingDirectory($ProcessId) } catch { $null } } function Get-TTWindowHandle { <# Resolve the visible window handle for a shell process (handles WT hosting). #> param([int]$Pid) $proc = Get-Process -Id $Pid -ErrorAction SilentlyContinue if (-not $proc) { return [IntPtr]::Zero } # If the process itself has a window, use it if ($proc.MainWindowHandle -ne [IntPtr]::Zero) { return $proc.MainWindowHandle } # Walk up to parent - for WT-hosted shells, the WT process has the window try { $cimProc = Get-CimInstance Win32_Process -Filter "ProcessId=$Pid" -ErrorAction Stop if ($cimProc.ParentProcessId) { $parent = Get-Process -Id $cimProc.ParentProcessId -ErrorAction SilentlyContinue if ($parent -and $parent.ProcessName -eq 'WindowsTerminal' -and $parent.MainWindowHandle -ne [IntPtr]::Zero) { return $parent.MainWindowHandle } # One more level up (shell -> OpenConsole -> WT) if ($parent) { $grandparentCim = Get-CimInstance Win32_Process -Filter "ProcessId=$($parent.Id)" -ErrorAction SilentlyContinue if ($grandparentCim.ParentProcessId) { $gp = Get-Process -Id $grandparentCim.ParentProcessId -ErrorAction SilentlyContinue if ($gp -and $gp.ProcessName -eq 'WindowsTerminal' -and $gp.MainWindowHandle -ne [IntPtr]::Zero) { return $gp.MainWindowHandle } } } } } catch { } return [IntPtr]::Zero } # --------------------------------------------------------------------------- # Thin mockable wrappers for native Win32 calls # --------------------------------------------------------------------------- function Invoke-TTShowWindow { <# .SYNOPSIS Wrapper for [TTProcessHelper]::ShowWindow. .PARAMETER Handle Window handle. .PARAMETER CmdShow Show command (SW_HIDE=0, SW_SHOW=5, SW_MINIMIZE=6, SW_RESTORE=9). #> [CmdletBinding()] param( [IntPtr]$Handle, [int]$CmdShow ) if (-not $script:NativeHelperLoaded) { return $null } try { [TTProcessHelper]::ShowWindow($Handle, $CmdShow) } catch { $null } } function Invoke-TTSetForegroundWindow { <# .SYNOPSIS Wrapper for [TTProcessHelper]::SetForegroundWindow. .PARAMETER Handle Window handle. #> [CmdletBinding()] param( [IntPtr]$Handle ) if (-not $script:NativeHelperLoaded) { return $null } try { [TTProcessHelper]::SetForegroundWindow($Handle) } catch { $null } } function Test-TTWindowVisible { <# .SYNOPSIS Wrapper for [TTProcessHelper]::IsWindowVisible. .PARAMETER Handle Window handle. #> [CmdletBinding()] param( [IntPtr]$Handle ) if (-not $script:NativeHelperLoaded) { return $false } try { [TTProcessHelper]::IsWindowVisible($Handle) } catch { $false } } |