<# .SYNOPSIS Harta comuna bin<->memo<->text pentru conversiile VFP (FoxBin2Prg), dot-sourced de vcx2txt.ps1 (Bin2Prg) si txt2vcx.ps1 (Prg2Bin), ca sa nu existe doua copii ale hartii. .DESCRIPTION Defineste $script:VfpFileMap: extensie-binar (lowercase, cu punct) -> @(extensie-memo, extensie-text). Si o functie inversa Get-VfpBinExtensionForTextExtension pentru txt2vcx.ps1 (text -> binar). #> $script:VfpFileMap = @{ '.vcx' = @('.vct', '.vc2'); '.scx' = @('.sct', '.sc2'); '.frx' = @('.frt', '.fr2') '.lbx' = @('.lbt', '.lb2'); '.mnx' = @('.mnt', '.mn2'); '.dbc' = @('.dct', '.dc2') '.pjx' = @('.pjt', '.pj2'); '.dbf' = @('.fpt', '.db2') } function Get-VfpBinExtensionForTextExtension { <# .SYNOPSIS Data o extensie text (.vc2, .sc2, ...), intoarce @(extensie-binar, extensie-memo), sau $null daca nu e cunoscuta. #> param([Parameter(Mandatory)][string]$TextExtension) $t = $TextExtension.ToLower() foreach ($binExt in $script:VfpFileMap.Keys) { if ($script:VfpFileMap[$binExt][1] -eq $t) { return @($binExt, $script:VfpFileMap[$binExt][0]) } } return $null } function Invoke-FoxBin2PrgSafe { <# .SYNOPSIS Ruleaza FoxBin2Prg.EXE cu un watchdog de timp, ca sa nu ramana blocat la infinit. .DESCRIPTION FoxBin2Prg.EXE poate afisa un MessageBox MODAL nativ al motorului VFP (nu al propriului sau error-handler) cand recompilarea textului esueaza (ex. text stricat, ENDPROC lipsa) - vazut concret: "Error 1098, Procedure not closed...". Parametrul cDontShowErrors='1' NU suprima acest dialog (acela controleaza doar raportarea de erori proprie a FoxBin2Prg, nu eroarea nativa de compilare VFP). Fara acest watchdog, un rulaj automat/CI ar ramane agatat la infinit asteptand un om sa apese OK. Orice timeout se trateaza ca ESEC pentru fisierul respectiv. .PARAMETER ExePath Calea catre FoxBin2Prg.EXE. .PARAMETER ExeArgs Lista de argumente pozitionale, in ordinea folosita de FoxBin2Prg (inclusiv string-urile goale intre ele, ca in apelul cu "&"). .PARAMETER TimeoutSeconds Cat asteapta procesul sa termine normal inainte sa-l omoare (implicit 60s - conversiile uzuale dureaza sub o secunda; un timeout mare inseamna aproape sigur un dialog modal blocat). .OUTPUTS PSCustomObject cu TimedOut (bool) si ExitCode (int; -1 daca a fost omorat la timeout). #> param( [Parameter(Mandatory)][string]$ExePath, [Parameter(Mandatory)][AllowEmptyCollection()][AllowEmptyString()][string[]]$ExeArgs, [int]$TimeoutSeconds = 60 ) $psi = New-Object System.Diagnostics.ProcessStartInfo $psi.FileName = $ExePath $psi.Arguments = ($ExeArgs | ForEach-Object { '"' + ($_ -replace '"', '\"') + '"' }) -join ' ' $psi.UseShellExecute = $false $proc = [System.Diagnostics.Process]::Start($psi) $finished = $proc.WaitForExit($TimeoutSeconds * 1000) if (-not $finished) { Write-Warning "Invoke-FoxBin2PrgSafe: TIMEOUT dupa $TimeoutSeconds s (probabil MessageBox modal blocat) - omor procesul (PID $($proc.Id)) si eventualele lui ferestre/copii." try { & taskkill /PID $proc.Id /T /F 2>&1 | Out-Null } catch {} try { if (-not $proc.HasExited) { $proc.Kill() } } catch {} Start-Sleep -Milliseconds 300 return [PSCustomObject]@{ TimedOut = $true; ExitCode = -1 } } return [PSCustomObject]@{ TimedOut = $false; ExitCode = $proc.ExitCode } }