Você abre um fonte AdvPL de 2008 e vê os mesmos AllTrim(), SubStr(), DBSeek() que escreveu ontem. Não é coincidência. Mais de 80% do que se programa em AdvPL gira em torno de cerca de 20 funções. Esse é o conjunto que vale decorar — depois disso, o resto da linguagem aparece quando precisa.
Esse guia não tenta ser exaustivo. É a lista mínima viável: o que você usa todo dia, mesmo sem perceber. Se você está começando agora ou voltou ao Protheus depois de anos no React, é por aqui.
Como escolhi essas 20
Critério simples: funções que aparecem em quase todo .prw que abre uma tela de cadastro, processa uma rotina ou integra com banco. Algumas são da linguagem xBase original (Clipper, Visual Objects). Outras são do framework Microsiga (prefixos FW, MV_, Ap). As duas turmas convivem e se misturam num projeto típico.
Strings — 6 funções
1. AllTrim() — remove espaços nas duas pontas
cNome := AllTrim(cVar) // " joao " → "joao"
cCpf := AllTrim(SA1->A1_CGC) // util pra comparar campos do bancoUse sempre que comparar strings vindas do banco. Campos Character em Protheus vêm preenchidos com espaços até o tamanho declarado.
2. SubStr() — extrai pedaço da string
cAno := SubStr(cData, 1, 4) // "20260105" → "2026"
cMes := SubStr(cData, 5, 2) // "20260105" → "01"Pegadinha: índice começa em 1, não 0. E o terceiro parâmetro é quantidade, não posição final.
3. Upper() / Lower() — converte caixa
cBusca := Upper(AllTrim(cFiltro)) // padroniza pra busca case-insensitive
cEmail := Lower(SA1->A1_EMAIL)Combinação Upper(AllTrim(...)) é o padrão de comparação de strings em Protheus.
4. PadL() / PadR() / StrZero() — preenchimento
StrZero(15, 6) // "000015"
PadL("Joao", 10, " ") // " Joao"
PadR(cCod, 20) // alinha à esquerda, completa com espaçosStrZero() existe especificamente pra zerar à esquerda. Mais legível que PadL(cVal, n, "0").
5. StrTran() — substitui ocorrências
cTexto := StrTran(cTexto, ".", "") // remove pontos
cFone := StrTran(cFone, "-", "") // limpa CPF/CNPJ/telefoneEquivalente ao String.replace de outras linguagens. Substitui todas as ocorrências, não só a primeira.
6. Empty() — string vazia ou só espaços?
If Empty(cCampo)
Help(...,..., "Campo obrigatório")
EndIfNão é só pra string. Empty() também trata data zerada (CTOD(" / / ")), zero numérico, array vazio, e NIL. Vale como validação universal de "tem valor?".
Datas — 3 funções
7. Date() — data atual do sistema
dHoje := Date() // data atual no formato Date
nAno := Year(Date())Retorna a data do servidor, não do cliente. Importante quando o ambiente é multi-fuso.
8. DToS() / SToD() — conversão data ↔ string
cDataStr := DToS(Date()) // 2026-05-06 → "20260506"
dData := SToD("20260506") // "20260506" → 06/05/2026
cDataBR := DToC(Date()) // 2026-05-06 → "06/05/2026"Use DToS pra gravar data em campo Character ou em SQL (formato ISO compactado). Use DToC pra exibir.
9. AddMonth() / AdjustDate() — aritmética de datas
dVencimento := AddMonth(Date(), 3) // hoje + 3 meses
dDiaUtil := AdjustDate(Date(), 5) // hoje + 5 dias úteis (pula fins de semana)AdjustDate respeita feriados se você tiver tabela SX5 com tabela 21 cadastrada. Senão só pula sábado e domingo.
Numéricos — 3 funções
10. Val() / Str() — conversão número ↔ string
nValor := Val("1234.56") // 1234.56
cValor := Str(nValor, 12, 2) // " 1234.56"
cValor := AllTrim(Str(nValor)) // "1234.56"Str() com 1 argumento alinha à direita com 10 chars de largura — quase sempre você quer AllTrim(Str(...)).
11. Round() — arredonda
Round(3.456, 2) // 3.46
Round(3.454, 2) // 3.45
Round(1234.78, -2) // 1200 (arredonda à esquerda)Segundo parâmetro negativo arredonda casas inteiras. Útil pra valores de impostos.
12. Int() / NoRound() — trunca, não arredonda
Int(3.789) // 3 (parte inteira)
NoRound(3.789, 2) // 3.78 (trunca em 2 casas)Diferença importante de Round: NoRound nunca aumenta o valor. Use em rateio fiscal pra evitar arredondamento favorável a um lado.
Arrays — 2 funções
13. aAdd() — adiciona elemento ao final
aLista := {}
aAdd(aLista, "Item 1")
aAdd(aLista, {"Codigo", "Descricao"}) // adiciona um sub-arrayNão confunda com aSize() (redimensiona) — aAdd aumenta o array dinamicamente em 1 posição.
14. aScan() — busca elemento
// Busca simples por igualdade
nPos := aScan(aLista, "Item 1")
// Busca com bloco de código (mais flexível)
nPos := aScan(aLista, {|x| x[1] == "0001" })Retorna a posição (base 1) ou 0 se não encontrar. Versão com bloco é o padrão pra arrays multidimensionais.
Tabelas e Banco — 3 funções
15. DBSeek() — busca por chave de índice
DBSelectArea("SA1")
DBSetOrder(1) // índice por filial+codigo
If DBSeek(xFilial("SA1") + cCod)
// achou
EndIfMais rápido que filtro porque usa o índice. Sempre defina DBSetOrder() antes — a ordem 1 nem sempre é a que você quer.
16. RecLock() / MsUnlock() — lock para escrita
RecLock("SA1", .F.) // .F. = altera registro existente
SA1->A1_OBSERVA := "Atualizado"
MsUnlock()
RecLock("SA1", .T.) // .T. = inclui novo registro
SA1->A1_COD := "999999"
MsUnlock()Sempre chame MsUnlock() depois. Esquecer trava a tabela pra outros usuários até a transação ser fechada.
17. TCQuery() / TCSqlExec() — SQL direto no DBAccess
cQuery := "SELECT A1_COD, A1_NOME FROM " + RetSqlName("SA1") + ;
" WHERE D_E_L_E_T_ = ' '"
cAlias := GetNextAlias()
TCQuery cQuery New Alias (cAlias)
While !(cAlias)->(EOF())
// processa
(cAlias)->(DBSkip())
End
(cAlias)->(DBCloseArea())Use RetSqlName() pra resolver nome físico (com filial) e sempre filtre D_E_L_E_T_ — o Protheus marca delete lógico, não físico.
Framework Microsiga — 3 funções
18. GetMv() — lê parâmetro do sistema
cEmpresa := GetMv("MV_RAZSOC") // string
nLimite := GetMv("MV_LIMICRD", .F., 0) // numérico, default 0
lAtivo := GetMv("MV_USERAU", .F., .F.) // lógicoSegundo parâmetro a .T. retorna o conteúdo bruto (sem cache). Terceiro é o default se o MV_ não existir — nunca confie que um parâmetro está cadastrado.
19. ExistBlock() / ExecBlock() — pontos de entrada
If ExistBlock("MA030VLD")
lOk := ExecBlock("MA030VLD", .F., .F.)
If !lOk
Return .F.
EndIf
EndIfÉ como o sistema permite extensão sem alterar fonte padrão. Sempre cheque com ExistBlock antes — chamar ExecBlock direto num PE inexistente lança erro.
20. ApMsgYesNo() / MsgInfo() / MsgStop() — diálogos
If ApMsgYesNo("Confirma alteração?", "Atenção")
// user clicou Sim
EndIf
MsgInfo("Operação concluída.")
MsgStop("Erro ao salvar registro.", "Erro fatal")Família ApMsg* é a versão ApiAware — funciona em rotina batch, web e desktop. Os antigos MsgYesNo(), Aviso() só funcionavam na interface gráfica.
Qual função usar? Fluxo de decisão
Upper/Lower, PadL/StrZero,
StrTran, Empty] Q1 -->|Data| D1[Date, DToS/SToD,
AddMonth/AdjustDate] Q1 -->|Numero| N1[Val/Str, Round,
Int/NoRound] Q1 -->|Array| A1[aAdd, aScan] Q1 -->|Tabela| T1{Operacao?} T1 -->|Buscar| TB[DBSeek com
DBSetOrder] T1 -->|Gravar| TG[RecLock + MsUnlock] T1 -->|SQL livre| TQ[TCQuery] Q1 -->|Sistema| F1[GetMv, ExistBlock,
ApMsgYesNo]
Tabela resumo
| # | Função | Categoria | O que faz |
|---|---|---|---|
| 1 | AllTrim() | String | Remove espaços início e fim |
| 2 | SubStr() | String | Extrai substring |
| 3 | Upper() / Lower() | String | Converte caixa |
| 4 | PadL() / PadR() / StrZero() | String | Preenche caracteres |
| 5 | StrTran() | String | Substitui ocorrências |
| 6 | Empty() | String/Geral | Vazio? (universal) |
| 7 | Date() | Data | Data atual do servidor |
| 8 | DToS() / SToD() | Data | Conversão data ↔ string |
| 9 | AddMonth() / AdjustDate() | Data | Aritmética de datas |
| 10 | Val() / Str() | Numérico | Conversão número ↔ string |
| 11 | Round() | Numérico | Arredonda |
| 12 | Int() / NoRound() | Numérico | Trunca sem arredondar |
| 13 | aAdd() | Array | Adiciona ao final |
| 14 | aScan() | Array | Busca posição |
| 15 | DBSeek() | Tabela | Busca por chave de índice |
| 16 | RecLock() / MsUnlock() | Tabela | Lock pra gravar |
| 17 | TCQuery() / TCSqlExec() | Banco | SQL direto via DBAccess |
| 18 | GetMv() | Framework | Lê parâmetro MV_ |
| 19 | ExistBlock() / ExecBlock() | Framework | Pontos de entrada |
| 20 | ApMsgYesNo() / MsgInfo() | UI | Diálogos modais |
O caminho daqui
Saber essas 20 não te faz dev sênior — ainda falta dominar tipagem de variáveis (LOCAL vs STATIC), blocos de código, query builders modernos da TLPP, e a parte boa do framework MVC. Mas garante que você não trava na sintaxe quando precisa entregar.
Se quer ir além, a referência oficial está espalhada no TDN. Pra cheat sheet de equivalentes em TLPP, fica de olho — vai ter post.
Comentarios 0