Como o Itamar falou a melhor forma e renomear para um arquivo temporário, porque não da erro, e podem continuar a usar o sistema.
Ao saírem e entrarem de novo vão usar a nova versão.
Coloque na entrada do sistema para procurar os arquivos temporários e excluir, dando erro ignore.
Para forçar sair do sistema, crie um sinalizador, um arquivo de uso exclusivo, criado no seu terminal
Nas rotinas mais usadas ou ao selecionar uma opção no menu, tente excluir este arquivo, se não conseguir faça a saída do sistema, um exemplo abaixo.
As rotinas abaixo foram tiradas de parte da minha biblioteca, não deu para testar, se for útil é só usar.
Pode ter erro de logica, devido as algumas alterações, e retirada de algumas funções.
LayOut das copias:
arquivo1.exe,arquivo2.exe,arquivo2.exe,...
LayOut arquivos temporarios:
tmp_1.exe,tmp_2.exe,tmp_3.exe,...
O código abaixo não esta funcional é uma parte do meu sistema de atualização, é só para você ter uma ideia de como fazer
EX:
arquivo.new.exe - nova versão, mantem copia da versão atual
arquivo.atu.exe - sobrepor versão atual
Código: Selecionar todos
STATIC nHandle := 0
STATIC FUNCTION AtualizarVersaoNew(sArqNew)
LOCAL sArqExe, sArqTmp1, sArqTmp2, nCopias, aCopia, xx
IF Empty(sArqNew) .or. !File(sArqNew)
RETURN .F.
ENDIF
sArqExe := Lower(PathToFile( sArqNew )) // pega nome arquivo
sArqExe := StrTran(sArqExe, '.new.', '.')
FOR xx := 1 TO 10
IF '(' + NTrim(xx) + ')' $ sArqExe
sArqExe := StrTran(sArqExe, '(' + NTrim(xx) + ')', '')
ENDIF
NEXT
nCopias := Val(IniRead('boot', 'copia versao ' + PathToFile(sArqExe), '10'))
aCopia := { {sArqNew, sArqExe } }
FOR xx := 1 TO nCopias
IF xx = 1
sArqTmp1 := sArqExe
ELSE
sArqTmp1 := StrTran(sArqNew, '.new.', xStr(xx - 1) + '.')
ENDIF
IF File(sArqTmp1)
sArqTmp2 := StrTran(sArqNew, '.new.', xStr(xx) + '.')
IF AScan(aCopia, {|p| FileDate(p[1]) = FileDate(sArqTmp1) .and. FileTime(p[1]) = FileTime(sArqTmp1) }) = 0
AAdd(aCopia, {sArqTmp1, sArqTmp2})
ELSE
EXIT
ENDIF
ELSE
EXIT
ENDIF
NEXT
FOR xx := Len(aCopia) TO 1 STEP -1
IF !BoniFileRenExc( aCopia[xx, 1], aCopia[xx, 2] ) // exclui destino antes de renomear se existir
RETURN .F.
ENDIF
NEXT
RETURN .T.
FUNCTION AtualizarVersaoAtu(sArqAtu)
LOCAL sPath, sArqExe, xx
IF Empty(sArqAtu) .or. !File(sArqAtu)
RETURN .F.
ENDIF
sPath := PathToFile( sArqAtu, .T. ) // pega path do arquivo
sArqExe := Lower(PathToFile( sArqAtu ))
sArqExe := StrTran(sArqExe, '.atu.', '.')
FOR xx := 1 TO 10
IF '(' + NTrim(xx) + ')' $ sArqExe
sArqExe := StrTran(sArqExe, '(' + NTrim(xx) + ')', '')
ENDIF
NEXT
IF File(sArqExe)
IF !BoniFileRenDest(sPath + sArqExe, sPath + 'tmp_' + sArqExe) //renomeia primeiro destino se existir, depois renomeia de orig para dest
RETURN .F.
ENDIF
ENDIF
RETURN BoniFileRen(sArqAtu, sArqExe)
FUNCTION aVersao(sPath, lSinalizador)
LOCAL aVersao, aTmp, xx
DEFA sPath TO PathAtual()
DEFA lSinalizador TO .T.
sPath := TrataPath(sPath)
aVersao := {}
aTmp := Directory(sPath + '*.new.*')
FOR xx := Len(aTmp) TO 1 step - 1
IF Upper(Right(aTmp[xx, 1], 3)) = '.ON'
LOOP
ENDIF
IF Empty(lSinalizador) .or. File(sPath + aTmp[xx, 1] + '.on') // sinalizador, se esta baixado todas dependências
aTmp[xx, 1] := Lower(sPath + aTmp[xx, 1])
aadd(aVersao, aTmp[xx])
ENDIF
NEXT
aTmp := Directory(sPath + '*.atu.*')
FOR xx := Len(aTmp) TO 1 step - 1
IF Upper(Right(aTmp[xx, 1], 3)) = '.ON'
LOOP
ENDIF
IF Empty(lSinalizador) .or. File(sPath + aTmp[xx, 1] + '.on') // sinalizador, se esta baixado todas dependência
aTmp[xx, 1] := Lower(sPath + aTmp[xx, 1])
aadd(aVersao, aTmp[xx])
ENDIF
NEXT
aTmp := Directory(sPath + '*.exe.exe')
FOR xx := Len(aTmp) TO 1 step - 1
IF Empty(lSinalizador) .or. File(sPath + aTmp[xx, 1] + '.on') // sinalizador, se esta baixado todas dependência
aTmp[xx, 1] := Lower(sPath + aTmp[xx, 1])
aadd(aVersao, aTmp[xx])
ENDIF
NEXT
aSort(aVersao,,, {|x, y| (x[3] < y[3]) .or. (x[3] = y[3] .and. x[4] < y[4])} )
RETURN aVersao
Código: Selecionar todos
// na entrada do sistema, nas opções mais usadas, EX: inicio da venda/pedido/cadastros/ao selecionar uma opção do menu principal
PROCEDURE Main()
IF IsBloqueado()
Alerta('sistema em manutenção')
quit
RETURN
ENDIF
FUNCTION Bloqueio()
LOCAL sArq
IF nHandle > 0
RETURN .T.
ENDIF
IF IsBloqueado() // esta bloqueado em outro terminal
RETURN .F.
ENDIF
sArq := 'blq_manu'
nHandle := FCreate( sArq )
IF nHandle > 0
FClose( nHandle )
nHandle := FOpen( sArq, 33 ) //somente escrita e exclusivo
//salvar informação para saber que terminal tem o bloqueio
ENDIF
IF !nHandle > 0
//Alert( 'Nao foi posivel criar sinalizador do sistema ' + cArq )
FErase(cArq)
RETURN .F.
ENDIF
RETURN .T.
// desbloquear
FUNCTION DesBloqueio()
LOCAL sArq
IF nHandle = 0
RETURN .T.
ENDIF
sArq := 'blq_manu'
FClose( nHandle )
FErase(sArq)
RETURN .T.
// se foi bloqueado em outra estação de trabalho
FUNCTION IsBloqueado( sArq)
IF nHandle > 0
RETURN .F.
ENDIF
IF File( sArq )
FErase( sArq )
ENDIF
RETURN File( sArq )
// se bloqueio me pertence
FUNCTION Isblocked( sArq )
RETURN nHandle > 0