Ir para conteúdo


Manimal

Cadastrado: 06 Jun 2012
Offline Última atividade: Ago 18 2017 06:02
-----

#13329 Autoit v3 Script parou de funcionar

Postado por Manimal em 30 julho 2017 - 09:52

Olá LordyDark.

 

Se vc possui o programa original, verifique o fonte e corrija o mesmo.

 

Se vc não conhece este programa, remova-o da sua inicialização do Windows, que provavelmente deve ser um aplicativo malicioso (malware).




#13243 Enorme coleção de e-books da Microsoft (GRÁTIS)

Postado por Manimal em 17 julho 2017 - 11:20

Pessoal, segue link para um blog de um camarada que oferece um montão de e-books sobre vários assuntos, todos da Microsoft.

 

Tem muita coisa boa, gratuita e extremamente relevante, só que tem que saber inglês.

 

Aliás saber inglês é OBRIGATÓRIO na nossa área. Não tem desculpas para não ter aprendido ainda.

 

Se vc é um daqueles que ainda não sabe inglês use o DUOLINGO para aprender. Alguns minutos por dia não matam ninguém!

 

Vamos ao link: https://blogs.msdn.m...e-2013-sharepo/




#13227 SEND() ta abrindo Corel Draw

Postado por Manimal em 09 julho 2017 - 11:36

Olá Marcos.

 

Ao que vc se confundiu...

 

ClipPut => coloca algo NO clipboard => equivalente ao CTRL-C

 

ClipGet => retira (cola) algo DO clipboard => equivalente ao CTRL-V

 

Assim, no teu programa, vc monta o código HTML inteiro e depois coloca ele todo direto no clipboard com o ClipPut()

 

$HTML = "<head<blablabla</head>"

$HTML &= "<body>segundo blablabla</body>"

ClipPut($HTML) ; a partir daqui todo o seu código HTML estaria no clipboard (pode ser usado o CTRL-V em qualquer lugar, experimenta aí)

 

Desse ponto em diante, vc usa o SEND para o 3o campo do GMail que vc precisa, selecionando o campo e enviando apenas o CTRL-V

SEND("^V")

 

Entendeu?




#13215 Mensagem na tela sem usar GDI

Postado por Manimal em 07 julho 2017 - 01:51

Pode retirar a referência ao $isColorRef neste caso, pois serve para converter o padrão de cores de hexa para RGB e vice-versa

 

O que não é usado aqui neste exemplo pois estamos usando direto a cor em hexa. Se mantivermos sempre este padrão, não haverá necessidade de conversão.

 

Daí a função fica assim:

 

Func _API_SetLayeredWindowAttributes($hwnd, $i_transcolor, $Transparency = 255)
   Local Const $AC_SRC_ALPHA = 1
   Local Const $ULW_ALPHA = 2
   Local Const $LWA_ALPHA = 0x2
   Local Const $LWA_COLORKEY = 0x1
   Local $Ret = DllCall("user32.dll", "int", "SetLayeredWindowAttributes", "hwnd", $hwnd, "long", $i_transcolor, "byte", $Transparency, "long", $LWA_COLORKEY + $LWA_ALPHA)
   Select
      Case @error
         Return SetError(@error,0,0)
      Case $ret[0] = 0
         Return SetError(4,0,0)
      Case Else
         Return 1
   EndSelect
EndFunc   ;==>_API_SetLayeredWindowAttributes
 
Não deve mais dar problema na obfuscação. O que enrosca são os comandos EXECUTE, ASSIGN, CALL e EVAL.
 
Eu os ignoro na obfuscação e em 99% dos casos não dá problema, mas se quiser uma compilação limpa só mudar a função ;)



#13204 FileSelectFolder

Postado por Manimal em 06 julho 2017 - 06:38

O Melba23 (moderador do fórum americano) tem uma função própria que tem várias opções.

 

Inclusive a opção de ter checkboxes para arquivos e pastas.

 

Acho que vale a pena dar uma olhada:

 

https://www.autoitsc...sion-16-feb-17/




#13202 Mensagem na tela sem usar GDI

Postado por Manimal em 06 julho 2017 - 05:25

Experimenta assim.

 

Postei como anexo porque ao usar a tag CODE trava.

 

O Alexandre já tinha reclamado disso faz alguns dias.

Arquivo(s) anexado(s)




#13123 Comparar dois arquivos txts (validar arquivo gerado)

Postado por Manimal em 26 junho 2017 - 02:15

Olá Boogerman.
 
Como você percebeu, existem várias maneiras de validar (ou comparar) dois arquivos, seja de que tipo for.
 
No seu caso como é arquivo TXT, facilita um pouco ao utilizar os comandos básicos de comparação entre strings como StringCompare ou mesmo ==.
 
Acredito que quando falamos em comparação de arquivos, sempre falamos em conteúdo, pois comparar nomes e tipos de arquivo não é comparação, é enrolação ;)
 
Partindo do princípio da comparação do conteúdo, quando trabalhamos com arquivos TXT, temos que ter em mente alguns problemas ou particularidades:
 
  1. letras maiúsculas e minúsculas, acentos e cia
  2. marcador de quebra de linha (padrão Windows, MAC ou Linux)
  3. página de código do arquivo (que é a maior chatice)
 
No primeiro caso, o AutoIt é razoavelmente esperto ao comparar strings, retornando iguais entre maiúsculas e minúsculas.
Porém dependendo do caso, isto pode ser uma boa coisa ou não. No seu é uma péssima idéia, pois vc precisa da comparação exata.
 
Para exemplificar isso, veja os códigos abaixo:
  1.  
  2. $String1 = "palavra"
  3. $String2 = "Palavra"
  4. If $String1 = $String2 Then
  5.    ConsoleWrite("Igual" & @CRLF)
  6. Else
  7.    ConsoleWrite("Diferente" & @CRLF)
  8. EndIf
  9.  
  1.  
  2. $String1 = "palavra"
  3. $String2 = "Palavra"
  4. If $String1 == $String2 Then
  5.    ConsoleWrite("Igual" & @CRLF)
  6. Else
  7.    ConsoleWrite("Diferente" & @CRLF)
  8. EndIf
  9.  
No primeiro o resultado é IGUAL, no segundo o resultado é DIFERENTE.
A diferença entre os dois códigos e os dois resultados é o sinal de == na linha 4, pois ele alterna os modos de comparação de string entre "parecido" e "exato".
 
Usando a função StringCompare, podemos ver que o 3o parâmetro existe justo para verificar este detalhe.
O padrão é ignorar maiúsculas e minúsculas. Para o mesmo efeito do == é necessário passar o 3o parâmetro como 1 (ou $STR_CASESENSE).
Tomar cuidado que o retorno da StringCompare quando as strings são iguais é 0 (zero).
 
Então definimos que a comparação precisa ser exata, conforme seu exemplo do TIL.
 
Assim ao comparar os arquivos, precisamos escolher o método de comparação (claro que tudo é uma opção e necessidade de cada um):
 
  • Importar o conteúdo inteiro como uma variável apenas (FileRead) e comparar Arquivo1 e Arquivo2 (método do Orve):
  1.  
  2. $Conteudo1 = FileRead(@ScriptDir & "\Arquivo1.txt")
  3. $Conteudo2 = FileRead(@ScriptDir & "\Arquivo2.txt")
  4. If $Conteudo1 == $Conteudo2 Then
  5. ou
  6. If StringCompare($Conteudo1, $Conteudo2, $STR_CASESENSE) = 0 Then
  7.  

Pessoalmente não gosto deste método pois come muita memória e é vago ao informar ONDE está o erro (se houver).

Também tem a questão do final de linha pois pode comparar @CRLF com @CR ou com @LF, pois ao importar o conteúdo inteiro inclui as quebras de linha.
 
  • Importar o conteúdo lendo linha a linha (variante do método do Pedro):
  1.  
  2. #include <FileConstants.au3>
  3. #include <StringConstants.au3>
  4.  
  5. Global $Linha1, $Linha2, $Igual = True
  6. Global $Handle1 = FileOpen(@ScriptDir & "\Arquivo1.txt", $FO_READ)
  7. Global $Handle2 = FileOpen(@ScriptDir & "\Arquivo2.txt", $FO_READ)
  8. If @error or $Handle1 <> -1 Then
  9.    While True
  10.       $Linha1 = FileReadLine($Handle1)
  11.       If @error Then
  12.          $Igual = False
  13.          ExitLoop
  14.       EndIf
  15.       $Linha2 = FileReadLine($Handle2)
  16.       If @error Then
  17.          $Igual = False
  18.          ExitLoop
  19.       EndIf
  20.       If $Linha1 == $Linha2 Then ContinueLoop
  21. ;~       If StringCompare($Linha1, $Linha2, $STR_CASESENSE) = 0 Then ContinueLoop
  22.       $Igual = False
  23.       ExitLoop
  24.    WEnd
  25.    FileClose($Handle1)
  26.    FileClose($Handle2)
  27.    If $Igual Then
  28.       ConsoleWrite("Igual" & @CRLF)
  29.    Else
  30.       ConsoleWrite("Diferença está nas linhas:" & @CRLF & "[" & $Linha1 & "]" & @CRLF & "[" & $Linha2 & "]" & @CRLF)
  31.    EndIf
  32. EndIf
  33.  

Escolhendo as linhas 20 ou 21, podemos até alternar entre as comparações.

Apesar do código ser maior, não exige tanta memória e ainda tem a vantagem de apresentar ONDE ocorreu a diferença.
E o comando FileReadLine ignora os diferentes formatos de quebra de linha (o que é uma vantagem neste caso).
 
  • Importar o conteúdo lendo linha a linha (método do Pedro):
Basicamente a mesma idéia anterior, porém usando arrays (questão de gosto).
  1.  
  2. Global $Igual = True
  3. Global $Array1 = FileReadToArray(@ScriptDir & "\Arquivo1.txt")
  4. Global $Array2 = FileReadToArray(@ScriptDir & "\Arquivo2.txt")
  5. If UBound($Array1) <> UBound($Array2) Then
  6.    ConsoleWrite("Tamanhos diferentes" & @CRLF)
  7.    Exit
  8. EndIf
  9. For $Linha = 0 to UBound($Array1)-1
  10.    If not ($Array1[$Linha] == $Array2[$Linha]) Then
  11.       $Igual = False
  12.       ExitLoop
  13.    EndIf
  14. If $Igual Then
  15.    ConsoleWrite("Igual" & @CRLF)
  16. Else
  17.    ConsoleWrite("Diferença está nas linhas:" & @CRLF & "[" & $Array1[$Linha] & "]" & @CRLF & "[" & $Array2[$Linha] & "]" & @CRLF)
  18. EndIf
  19.  

Código um pouco menor, usa mais memória para armazenar o conteúdo dos dois arquivos em arrays.

Pode mostrar onde aconteceu a diferença. Como antes, o comando FileReadToArray ignora as quebras de linha.
Existe outro comando bem parecido que é _FileReadToArray (apenas com o _ antes) que faz a mesma coisa mas com mais algumas opções.
Observe que foi usado um NOT == para manter a comparação exata, pois se usar um <> volta ao padrão "parecido".
Pode usar também a função StringCompare no mesmo lugar.
 
  • Comparação através de HASH (método sugerido por mim e implementado pelo Luigi)
Considerando que não há necessidade de mostrar ONDE estão as diferenças, o método do HASH é o mais rápido e funciona para qualquer tipo de arquivo.
Tanto para TXTs como quaisquer outros tipos de arquivo, mas usa mais memória. Eu gosto de usar para comparar arquivos tipo EXE ou DLL. Aqui usando padrão MD5.
A título de conhecimento, HASH é um método de cálculo sobre o conteúdo de um conjunto de dados (nesse caso o conteúdo do arquivo).
O resultado do estilo de algoritmo utilizado (MD2, MD4, MD5, SHA1, AES e outros) é uma série de caracteres que é ÚNICO para cada arquivo.
Se for modificado qualquer coisa tipo uma vírgula a mais ou a menos, trocar uma letra maiúscula por minúscula, inserir um espaço a mais no final da linha,
não importa o quê gera outro RESULTADO e portanto os arquivos são diferentes. A maioria está acostumado com o padrão CRC32 muito comum em downloads e arquivos ZIP. É a base do processo de criptografia e assinaturas digitais.
  1.  
  2. #include <Crypt.au3>
  3.  
  4. _Crypt_Startup()
  5. Global $Hash1 = _Crypt_HashFile(@ScriptDir & "\Arquivo1.txt", $CALG_MD5)
  6. Global $Hash2 = _Crypt_HashFile(@ScriptDir & "\Arquivo2.txt", $CALG_MD5)
  7. _Crypt_Shutdown()
  8. If $Hash1 == $Hash2 Then
  9.    ConsoleWrite("Igual" & @CRLF)
  10. Else
  11.    ConsoleWrite("Diferente" & @CRLF)
  12. EndIf
  13.  

Achei estranho que vc mencionou que o exemplo do Luigi não funcionou, mas é que tem um erro de ortografia no exemplo dele.

Na linha 17, apesar de ler o 2o arquivo, ele faz o cálculo do 1o, daí sempre vai ser igual o resultado.
 
Finalmente, este são apenas alguns exemplos de comparações entre arquivos.
Tenho certeza que o pessoal do fórum deve ter outros exemplos para compartilhar também.
Não existe um método certo ou errado, existe aquele que faz o serviço que você quer.
Parafraseando aquele programa da Globo: Vc decide! ;)



#13050 Script silencioso c++

Postado por Manimal em 22 maio 2017 - 05:35

Olá Leandro.

 

O que vc chama de script silencioso?

 

E aqui é um fórum de AutoIt, seria mais fácil se vc for num fórum de C++




#13018 Remapear teclas

Postado por Manimal em 11 maio 2017 - 09:13

Olá Belini.

 

Entenda que o ScanCode é permanente, ou seja, não é apenas uma questão de mudar e pronto, fica mudado até nova ordem.

 

É o contrário, a cada boot o SO lê o ScanCode e remapeia as teclas ali contidas, portanto para mudar 2 ou mais teclas, só colocá-las na lista do ScanCode ampliando ou modificando a lista.

 

Usando o mesmo exemplo de antes (P pelo A):
 
00 00 00 00 -> sempre zeros
00 00 00 00 -> sempre zeros
02 00 00 00 -> 2 definições (1 tecla e 1 NULL)
1E 00 18 00 -> troca letra P pela letra A (observe que é primeiro a tecla final depois a inicial)
00 00 00 00 -> sempre zeros (NULL)
 
Agora modificando para incluir mais teclas:
 
00 00 00 00 -> sempre zeros
00 00 00 00 -> sempre zeros
02 00 00 00 -> 5 definições (4 teclas e 1 NULL)
1E 00 18 00 -> troca letra P pela letra A
YY 00 XX 00 -> troca X pela Y
++ 00 11 00 -> troca 1 pelo +
GG 00 00 00 -> desativa o G
00 00 00 00 -> sempre zeros (NULL)
 

Não esqueça de modificar a 3a linha que contém a quantidade de definições no ScanCode inteiro.

 

A parte chata da brincadeira é que para remover uma tecla, por exemplo, tem que remover a linha dela MAS preservar o resto do ScanCode e ajustar a 3a linha.

 

Ok?




#12955 Contar Palavras de um arquivo de texto

Postado por Manimal em 05 maio 2017 - 01:50

Olá Pedro.

 

Entendi agora seu uso dos INI.

 

Teoricamente sobre se haveria uma possível sobrecarga ao ler o INI repetidas vezes, a resposta é não!

 

Se este procedimento deixa o teu programa rápido como vc quer (ou precisa), vai nessa!  :600866:

 

Toda e qualquer função pode ser desenvolvida (ou redesenhada) do zero para satisfazer suas necessidades específicas. As funções que temos hoje, são apenas os blocos básicos com os quais desenvolvemos melhor nossas lógicas.

 

Claro que seria um saco ter que desenvolver uma rotina como StringRight ou FileOpen ou qualquer outra. Mas o princípio é de que TUDO pode ser recriado como função!

 

Se vc não gosta de uma função, recrie-a como vc gosta. Não gosta dos argumentos? Escreva outra com os argumentos que vc precisa!

 

Um belo exemplo seria a função MSgBox Plus que está aqui no fórum.

 

Por consequência, reescrever a INIREAD seria totalmente possível!

 

Na verdade, se vc pegar uma linguagem e montar um subsistema que facilite pra outras pessoas programarem, vc simplesmente estará criando um Framework. Dependendo do seu sucesso neste Framework, ele será mais conhecido (ou utiizado) do que a linguagem original  ;)




#12907 Problema com Logica

Postado por Manimal em 01 maio 2017 - 08:16

Olá Denis de Araújo Ferreira.

 

Na maioria das linguagens ditas "tipadas" esse tipo de comparação que vc está tentando fazer não seria possível.

 

Em linguagens como C, Pascal ou Java seria impossível comparar um número com uma string.

 

Felizmente (ou infelizmente) o AutoIt tem uma liberdade muito grande neste ponto. E por isto mesmo que devemos ter um cuidado extra ao fazermos este tipo de comparações.

 

Quando fazemos um IF, estamos basicamente comparando 2 variáveis do MESMO TIPO, ou seja, ambas numéricas, ambas string ou ambas lógicas. Ao efetuar comparações entre TIPOS DIFERENTES de variáveis, devemos ter em mente como que esta comparação será feita.

 

No AutoIt, ao compararmos TIPOS DISTINTOS, elas serão basicamente convertidas para números e daí feita a comparação. Neste caso todas as variáveis string são avaliadas como 0 (zero), pois não possuem um "valor" específico pois começam com letras, portanto o valor delas é zero!

 

Por isso teu programa deu resultado 5 e não 3 como vc gostaria.

 

Mas é interessante notar que o AutoIt ao converter as variáveis tipo string para números, leva em consideração o conteúdo das mesmas. Assim mesmo strings que contenham números serão convertidas para números, o que pode levar a conclusões e lógicas de programação incorretas. Por exemplo:

  1.  
  2. $variavel = "AutoIt"
  3. If $Variavel = 0 then ... ; isto vai ser VERDADEIRO porque ao converter a string, a primeira letra não tem representação numérica, portanto valor 0 (zero)
  4.  

mas se alterarmos o conteúdo da variável

  1.  
  2. $variavel = "5AutoIt"
  3. If $Variavel = 0 then ... ; isto vai ser FALSO porque ao converter a string, a primeira letra TEM representação numérica, nesse caso 5 (cinco)
Muito cuidado com isto!

 

A partir daqui temos 2 caminhos que vc deve seguir:

  1. Ou converte todas as variáveis para o mesmo tipo usando as funções string() ou number()
  2. Ou modifica seu programa pra refletir o que vc realmente quer

Eu acho que no seu exemplo, se a intenção era verificar se havia conteúdo dentro das variáveis string, então o operador correto a ser usado na comparação seria ==

Porque daí vc força a comparação do tipo (númerica/string) e do conteúdo da variável!

 

Outra possibilidade (e a mais correta no meu entendimento): Ao saber que as variáveis $x1, $x2 e $x3 são string, trate-as como tal da seguinte forma:

  1.  
  2. If $x1 = "" then ...



#12899 Como criar variáveis dinâmicamente

Postado por Manimal em 28 abril 2017 - 06:24

Olá Experito.

 

Para resolver seu problema, use os comandos Assign e Eval

  • Assign para atribuir conteúdos a variáveis dinâmicas
  • Eval para ler o conteúdo das variáveis dinâmicas

 

Modifiquei a linha 20 para a sintaxe correta de criação e as linhas 37 a 40 para a leitura correta das variáveis também.

  1.  
  2. #include <ButtonConstants.au3>
  3. #include <GUIConstantsEx.au3>
  4. #include <MsgBoxConstants.au3>
  5. #include <StaticConstants.au3>
  6. #include <WindowsConstants.au3>
  7.  
  8. FormuDinamico(3)
  9.  
  10. Func FormuDinamico($NumCan)
  11. #Region ### START Koda GUI section ### Form=
  12. $Form1 = GUICreate("Lista de pessoas", 1361, 700, 2, 2)
  13. $Group1 = GUICtrlCreateGroup("Escolhas", 8, 56, 1185, 601)
  14. GUICtrlSetFont(-1, 14, 400, 0, "MS Sans Serif")
  15. $Button1 = GUICtrlCreateButton("Pronto", 312, 608, 129, 41)
  16. $Button2 = GUICtrlCreateButton("Voltar", 704, 608, 129, 41)
  17. Local $esp = 480 / $NumCan
  18.  
  19. For $i = 1 To $NumCan
  20. Assign("Checkbox" & $i, GUICtrlCreateCheckbox("Pessoa " & $i, 104, 60 + $i * $esp, 1009, 33))
  21.  
  22. GUICtrlCreateGroup("", -99, -99, 1, 1)
  23. $Label1 = GUICtrlCreateLabel("Você pode escolher até cinco pessoas.", 8, 8, 1181, 29)
  24. GUICtrlSetFont(-1, 15, 400, 0, "MS Sans Serif")
  25. GUISetState(@SW_SHOW)
  26. #EndRegion ### END Koda GUI section ###
  27.  
  28. While 1
  29. $nMsg = GUIGetMsg()
  30. Switch $nMsg
  31. Case $GUI_EVENT_CLOSE
  32. Case $Button1
  33. ;----------- O meu problema está aqui! Não consigo descobrir qual checkbos foi marcado.
  34.  
  35. For $i = 1 To $NumCan
  36. $saida = GUICtrlRead(Eval("Checkbox" & $i))
  37. If $saida = $GUI_CHECKED Then MsgBox(1, "leu", $i)
  38.  
  39. ;----------- Esperava que os nomes das variáveis fossem Checkbox1, Checkbox2,...
  40.  
  41. EndSwitch
  42. WEnd
  43.  
  44. EndFunc ;==>FormuDinamico
  45.  
  46.  
  47.  

Dessa forma, apenas a CheckBox marcada será sinalizada!




#12888 Remapear teclas

Postado por Manimal em 28 abril 2017 - 11:01

Bom dia.
Desculpe o atraso...
 
Para remapear as teclas em Windows através do REGISTRO, a opção é usar a chave
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout
através do valor
Scancode Map
 
Observações:
  1. Obrigatório reboot para efetivar as mudanças
  2. As mudanças são permanentes até apagar a chave do registro e reboot novamente
  3. As mudanças ocorrem para TODOS os usuários e/ou teclados (lay-outs)
 
Até o Windows XP era possível remapear as teclas "por usuário" usando a chave
HKEY_CURRENT_USER\Keyboard Layout
porém do Windows 7 pra frente não funciona mais
 
A "sintaxe" do Scancode Map é a seguinte:
  • 4 bytes indicando a versão (deixar sempre zeros)
  • 4 bytes indicando os flags (deixar sempre zeros)
  • 4 bytes informando a quantidade de teclas que estão sendo remapeadas (nro de teclas + 1 que é o terminador NULL da string)
  • 4 bytes para cada tecla remapeada sendo:
  •    2 bytes para a tecla desejada (deixar 00 00 para desativar a tecla)
  •    2 bytes da tecla original
  • 4 bytes indicando terminador NULL (deixar sempre zeros)
 
A maneira mais simples de pegar os Scancodes é utilizando o Sharpkeys que mostra os Scancodes
 
Senão os Scancodes podem ser procurados na net mas recomendo (para melhor entendimento):
 
 
Como exemplo usando a sugestão do teu post (trocando o P pelo A)
 
Precisamos saber
00 18 = scancode tecla P
00 1E - scancode tecla A
 
Resultando na string
00 00 00 00 -> sempre zeros
00 00 00 00 -> sempre zeros
02 00 00 00 -> 2 definições (1 tecla e 1 NULL)
1E 00 18 00 -> troca letra P pela letra A (observe que é primeiro a tecla final depois a inicial)
00 00 00 00 -> sempre zeros (NULL)
 
Ficando em AutoIt
  1.  
  2. RegWrite("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout", "Scancode Map", REG_BINARY, "0x00000000000000000200000018001E0000000000")
  3.  
Depois só reiniciar  :lol:



#12844 Pressionar tecla após o resultado do _imageSearch (Violação de Regras do Fórum)

Postado por Manimal em 04 abril 2017 - 10:21

Olá SSuperComboo.

 

Além da excelente dica do Joelson0007 e do vídeo do Alexandre, eu acho que vc está usando a função errada!

 

No seu caso, que quer procurar uma imagem em uma determinada área e não no desktop inteiro, use a função _ImageSearchArea

 

Uma boa fonte de referência é este post aqui: ImageSearch Usage Explanation




#12829 Sons do windows ao digitar em um GUI

Postado por Manimal em 30 março 2017 - 08:20

Boa galera.

 

Parabéns pela solução Pedro.  :600866:

 

Fábio, muito bom seu exemplo, demorei para responder porque enroscou o trabalho aqui e quando fui testar seus exemplos não dava o som. :mad2:

 

Entre achar uma máquina que aparecesse o som que vcs falavam e fazer alguns testes, não tinha mais olhado nada.

 

E hoje, O Pedro aparece com a resposta! Uhu!!!  :like_icon: