Função para selecionar arquivos via Windows Explorer utilizando AdvPL

Olá pessoal…

Hoje vou mostrar uma função que desenvolvi para abrir a tela de seleção de arquivos do Windows via AdvPL.

Todos sabemos como a tela padrão do AdvPL para seleção de arquivos (a função cGetFile) não é muito usual, e às vezes acaba confundindo os usuários.

Pensando nisso, criei uma função que você simplesmente passa a máscara desejada para seleção de arquivos, e ele cria a tela para você selecionar.

Testei no Windows 7 e no Windows 10. Abaixo um print da tela.

Janela para escolher o arquivo

Janela para escolher o arquivo

Abaixo o código fonte desenvolvido:

//Bibliotecas
#Include "Protheus.ch"

/*/{Protheus.doc} zChooseFile
Função que abre a tela padrão do Windows Explorer para escolher um arquivo
@author Atilio
@since 03/08/2017
@version undefined
@param cMascara, characters, Máscara para escolha de arquivos (Descrição *.extensão | *.extensão)
@type function
@example Exemplos abaixo:
	//Escolher qualquer arquivo ( *.* ):
	u_zChooseFile()
	
	//Escolher somente arquivos texto ( *.txt )
	u_zChooseFile("Arquivos Texto (*.txt)|*.txt")
	
	//Escolher arquivos texto ou todos (*.txt ou *.*)
	u_zChooseFile("Arquivos Texto (*.txt)|*.txt|Todos Arquivos (*.*)|*.*")
	
	//Escolher imagens png ou jpg (*.png ou *.jpg)
	u_zChooseFile("Arquivos Texto (*.png)|*.png|Arquivos Texto (*.jpg)|*.jpg")
/*/

User Function zChooseFile(cMascara)
	Local cResultado := ""
	Local cComando   := ""
	Local cDir       := GetTempPath()
	Local cNomBat    := "zChooseFile.bat"
	Local cArquivo   := "resultado.txt"
	Local cMac       := ""
	Default cMascara := "Todos Arquivos (*.*)|*.*"
	
	//Se o resultado já existir, exclui
	If File(cDir + cArquivo)
		FErase(cDir + cArquivo)
	EndIf
	
	//Monta o comando para abrir a tela de seleção do windows
	cComando += '@echo off' + CRLF
	cComando += 'setlocal' + CRLF
	cComando += 'set ps_cmd=powershell "Add-Type -AssemblyName System.windows.forms|Out-Null;$f=New-Object System.Windows.Forms.OpenFileDialog;$f.Filter=' + "'"+cMascara+"'" + ';$f.showHelp=$true;$f.ShowDialog()|Out-Null;$f.FileName"' + CRLF
	cComando += '' + CRLF
	cComando += 'for /f "delims=" %%I in (' + "'%ps_cmd%'" + ') do set "filename=%%I"' + CRLF
	cComando += '' + CRLF
	cComando += 'if defined filename (' + CRLF
	cComando += '    echo %filename% > '+cArquivo + CRLF
	cComando += ')' + CRLF
	
	//Gravando em um .bat o comando
	MemoWrite(cDir + cNomBat, cComando)
	
	//Executando o comando através do .bat
	WaitRun(cDir+cNomBat, 2)
	
	//Se existe o arquivo
	If File(cDir + cArquivo)
	
		//Pegando o resultado que o usuário escolheu
		cResultado := MemoRead(cDir + cArquivo)
	EndIf
Return cResultado

Bom pessoal, por hoje é só.
Abraços e até a próxima.

Dan Atilio (Daniel Atilio)
Especialista em Engenharia de Software pela FIB. Entusiasta de soluções Open Source. E blogueiro nas horas vagas.

17 Responses

  1. Sensacional Atílio, utilizando a funcionalidade nativa do Windows. Utilizo PowerShell para scripts de backup, mas nem pensava em mesclar com ADVPL. Parabéns pelo post cara, de verdade! (Só com muita pesquisa mesmo)

  2. Súlivan disse:

    Parabéns pela iniciativas de ótima qualidade.

  3. Felipe Naganava disse:

    Muito legal Atilio.
    Estou tentando colocar um multiselect nisso ai agora kkkk.

    • Dan_Atilio disse:

      Boa tarde Felipe, tudo bem?
      Eu que agradeço jovem.
      Do multiselect, se conseguir algo, mande aqui para gente para mantermos um histórico.
      Um grande abraço.

      • Felipe Naganava disse:

        Nunca tinha mexido com batch, nem powershell kkkkk então não sei se está legal, mas funciona kkkk
        O comando ficou assim:
        cComando += ‘@echo off’ + CRLF
        cComando += ‘setlocal’ + CRLF
        cComando += ‘set ps_cmd=powershell “Add-Type -AssemblyName System.windows.forms|Out-Null;$f=New-Object System.Windows.Forms.OpenFileDialog;$f.Multiselect=$true;$f.Filter=’ + “‘”+cMascara+”‘” + ‘;$f.showHelp=$true;$f.ShowDialog()|Out-Null;$f.FileNames”‘ + CRLF
        cComando += ” + CRLF
        cComando += ‘ {} > ‘+cArquivo + CRLF
        cComando += ‘for /f “delims=” %%I in (‘ + “‘%ps_cmd%'” + ‘) do echo “%%I” >> ‘+cArquivo + CRLF
        cComando += ” + CRLF

        ———————————————————————————————
        Dai só removi as aspas e a quebra de linha

        cResultado := STRTRAN(cResultado,'”‘,”)
        cResultado := STRTRAN(cResultado,’ ‘+chr(13)+chr(10),’|’)

        ——————————————————————————————–
        Depois é só usar a função separa para transformar a string em array
        aAnexos := Separa(cResultado,’|’,.f.)

  4. ciro bizelli disse:

    Fala Dan e Felipe!! Era exatamente isso que eu estava buscando, o multi-select, me ajudou pacas!!

    Dan, faz um post disso! Acho que vai ajudar muita gente! Valeu!

  5. Obrigado por compartilhar. Eu estava com um problema com pastas que contem acentuação, exemplo nota de serviço.
    Resolvi usando cResultado := DecodeUTF8(MemoRead(cDir + cArquivo), “cp1252”)
    Basta utilizar a função DecodeUTF8

  6. Reginaldo Ribeiro disse:

    Obrigado por compartilhar e pelo ótimo trabalhos
    queria deixar uma contribuição para alguém que assim como eu não conseguiu resolver o problema da acentuação só com DecodeUTF8 sitado pelo nosso amigo Wagner de souza.
    no meu caso para funcionar tive que acrescentar no script o comando “chcp 65001′”
    depois disso funcionou perfeitamente.

    cComando += ‘chcp 65001’ + CRLF
    cComando += ‘@echo off’ + CRLF
    cComando += ‘setlocal’ + CRLF
    cComando += ‘set ps_cmd=powershell “Add-Type -AssemblyName System.windows.forms|Out-Null;$f=New-Object System.Windows.Forms.OpenFileDialog;$f.Filter=’ + “‘”+cMascara+”‘” + ‘;$f.showHelp=$true;$f.ShowDialog()|Out-Null;$f.FileName”‘ + CRLF
    cComando += ” + CRLF
    cComando += ‘for /f “delims=” %%I in (‘ + “‘%ps_cmd%'” + ‘) do set “filename=%%I”‘ + CRLF
    cComando += ” + CRLF
    cComando += ‘if defined filename (‘ + CRLF
    cComando += ‘ echo %filename% > ‘+cArquivo + CRLF
    cComando += ‘)’ + CRLF

    //Gravando em um .bat o comando
    MemoWrite(cDir + cNomBat, cComando)

    //Executando o comando através do .bat
    WaitRun(cDir+cNomBat, 2)

    //Se existe o arquivo
    If File(cDir + cArquivo)
    cResultado := MemoRead(cDir + cArquivo)
    cResultado :=Upper(Alltrim(FwCutOff(cResultado)))
    cDecoRes :=DecodeUTF8(cResultado, ‘cp1252’)//MemoRead(cDir + cArquivo)
    If cDecoResNIL
    cResultado:=cDecoRes
    EndIf

    EndIf

  7. Thiago disse:

    teria como fazer um desse, porém, apenas para selecionar uma pasta e retornar a pasta selecionada?

  8. Thiago disse:

    consegui fazer, aos que quiserem..

    @echo off
    setlocal
    set ps_cmd=powershell “Add-Type -AssemblyName System.windows.forms|Out-Null;$folderBrowser=New-Object System.Windows.Forms.FolderBrowserDialog;$folderBrowser.Description = “Selecione uma pasta”;$folderBrowser.ShowDialog();$folderBrowser.SelectedPath”

    for /f “delims=” %%I in (‘%ps_cmd%’) do set “selectedpath=%%I”

    if defined selectedpath (
    echo %selectedpath% > resultado.txt
    )

Deixe uma resposta