lcarakaki 2 Posted December 21, 2020 Report Share Posted December 21, 2020 Bom dia a todos! Estou migrando minha emissão de NFe do AcbrMonitorPlus para AcbrNfeLib, tudo está funcionando perfeitamente com a LIB, o único problema que tenho atualmente é do programa fechar esporadicamente. As vezes fecha logo na primeira emissão de nfe, as vezes fecha na segunda ou terceira NFe. Meu programa é em xHarbour, e optei em carregar a DLL sempre quando vou utiliza-la e em seguida descarrego, mas já tentei carregar ela na abertura do programa e descarregar no fechamento do programa, assim como os métodos NFE_Inicializar e NFE_Finalizar, também tentei trocar DllLoad() por LoadLibrary(), LibLoad() e DllPrepareCall(), e a DllUnLoad() por LibFree() e FreeLibrary(). Tentei utilizar a dll Cdecl e também a StdCall. Já fiz todas as combinações possíveis. Creio que essa ajuda é para xHarbour e não para a lib, pois no log da lib todos os métodos são executados. Agradeço a todos desde já. FUNCTION ACBR_CRIA_ASSINA_VALIDA_ENVIA(xTxt,xChaveNfe) LOCAL nRetMet,cRet,xLocalXml,xXml,lAssinaValidaEnvia:=.T. LOCAL xPara,xCopias,xAssunto,xMensagem LOCAL pDllNfe:=DllLoad("ACBrNFe32.dll") ** Nome do XML e local de onde será salvo xXml:=xChaveNfe+"-nfe.xml" xLocalXml:=pDisco+":\xHB\nfe\"+UPPER(pUnidadeUf)+"\XML\" xPdf:=xChaveNfe+"-nfe.pdf" xLocalPdf:=pDisco+":\xHB\nfe\"+UPPER(pUnidadeUf)+"\PDF\" nRetMet:=DLLCALL(pDllNfe,32,"NFE_Inicializar",pUnidadeUf+"_NFE.INI","") //Retorno 0 cRet:=space(1024) nRetMet:=DLLCALL(pDllNfe,32,"NFE_Consultar",xChaveNfe,.T.,cRet) //Retorno 0 nRetMet:=DLLCALL(pDllNfe,32,"NFE_Finalizar",pUnidadeUf+"_NFE.INI","") //Retorno 0 nRetMet:=DLLCALL(pDllNfe,32,"NFE_Inicializar",pUnidadeUf+"_NFE.INI","") //Retorno 0 if at("Autorizado o uso da NF-e",cRet)>0 lAssinaValidaEnvia:=.F. ** Pega a data correta em que a Nfe foi emitida q:="select concat(year(b09demi),lpad(month(b09demi),2,'0')) as pasta from nfec where chavenfe='"+xChaveNfe+"'" v:=F_GETCON(q) xPastaAno:=v[1,1] xLocalXml:=xLocalXml+xPastaAno+"\" xLocalPdf:=xLocalPdf+xPastaAno+"\" else xLocalXml:=xLocalXml+strZero(year(date_sql()),4)+strZero(month(date_sql()),2)+"\" xLocalPdf:=xLocalPdf+strZero(year(date_sql()),4)+strZero(month(date_sql()),2)+"\" endif if lAssinaValidaEnvia nRetMet:=DLLCALL(pDllNfe,32,"NFE_CarregarINI",xTxt) //Retorno 0 nRetMet:=DLLCALL(pDllNfe,32,"NFE_Assinar") //Retorno 0 nRetMet:=DLLCALL(pDllNfe,32,"NFE_Validar") //Retorno 0 nRetMet:=DLLCALL(pDllNfe,32,"NFE_GravarXml",0,xXml,xLocalXml) //Retorno 0 cRet:=space(1024) nRetMet:=DLLCALL(pDllNfe,32,"NFE_Enviar",0,.T.,.T.,.F.,cRet) //Retorno 0 else ** Se o XML já está autorizado apenas o carrga ** Para poder imprimir e enviar por e-mail nRetMet:=DLLCALL(pDllNfe,32,"NFE_CarregarXML",xLocalXml+xXml,"") //Retorno 0 endif nRetMet:=DLLCALL(pDllNfe,32,"NFE_ImprimirPDF") //Retorno 0 nRetMet:=DLLCALL(pDllNfe,32,"NFE_EnviarEmail",xPara,xLocalXml+xXml,.T.,xAssunto,xCopias,,xMensagem) //Retorno 0 nRetMet:=DLLCALL(pDllNfe,32,"NFE_Finalizar",pUnidadeUf+"_NFE.INI","") //Retorno 0 DllUnload(pDllNfe) RETURN .T. Link to post Share on other sites
Rafael Dias 1,215 Posted December 21, 2020 Report Share Posted December 21, 2020 Eu recomendo em Harbour usar sempre a Cdecl foi o que me deu melhores resultados durante meus testes aqui. Sobre este erro poderia postar um log da lib para eu ver. Rafael Dias Ajude o Projeto ACBr crescer - Assine o SAC Desenvolvedor ACBrLib. Link to post Share on other sites
lcarakaki 2 Posted December 21, 2020 Author Report Share Posted December 21, 2020 @Rafael Dias, eu sempre consulto a chave antes de emitir a nfe, reparei que no log, a consulta da segunda Nfe emitida retorna SetRetorno(-10, Access violation), os métodos de validar, assinar, enviar que são chamados em seguida retorna 0, mas ao finalizar a lib o programa se fecha. Seria a segunda NFE nesta estrutura que dá o erro: nRetMet:=DLLCALL(pDllNfe,32,"NFE_Inicializar",pUnidadeUf+"_NFE.INI","") //Retorno 0 cRet:=space(1024) nRetMet:=DLLCALL(pDllNfe,32,"NFE_Consultar",xChaveNfe,.T.,cRet) //Retorno 0 //Na segunda NFE retorna -10 Access violation nRetMet:=DLLCALL(pDllNfe,32,"NFE_Finalizar",pUnidadeUf+"_NFE.INI","") //Retorno 0 Log: ACBrLibNFE-20201221.log Link to post Share on other sites
Rafael Dias 1,215 Posted December 21, 2020 Report Share Posted December 21, 2020 Sua chamada do NFE_Consultar esta errada, olhe a classe xHarbour que tem no svn lá os métodos estão implementados de forma correta. bufferLen := 1024 cRet := Space(1024) hResult := DllCall(pDllNfe, 32, "NFE_Consultar", hb_StrToUTF8(xChaveNfe), .T., @cRet, @bufferLen) svn.code.sf.net/p/acbr/code/trunk2/Projetos/ACBrLib/Demos/Harbour/NFe/ACBrNFe.prg Rafael Dias Ajude o Projeto ACBr crescer - Assine o SAC Desenvolvedor ACBrLib. Link to post Share on other sites
lcarakaki 2 Posted December 22, 2020 Author Report Share Posted December 22, 2020 @Rafael Dias, estou tentando adaptar o PRG do demo em meu programa para ver se corrigi o erro. Sabe me dizer onde consigo o .ch #include '..\Comum\acbrlib.ch' Link to post Share on other sites
Solution Rafael Dias 1,215 Posted December 22, 2020 Solution Report Share Posted December 22, 2020 Esta tudo no svn p/acbr/code - Revision 21116: /trunk2/Projetos/ACBrLib/Demos/Harbour (sf.net) Rafael Dias Ajude o Projeto ACBr crescer - Assine o SAC Desenvolvedor ACBrLib. Link to post Share on other sites
lcarakaki 2 Posted December 23, 2020 Author Report Share Posted December 23, 2020 @Rafael Dias, adaptei meu programa para usar o PRG do exemplo do SVN, e estou tendo o retorno "-10, Access violation" no método de validar regras de negócio. o Erro é na chamada do método CheckResult, coloquei em vermelho as linhas que o xHarbour destaca ao fechar o programa. METHOD ValidarRegrasdeNegocios() CLASS ACBrNFe local hResult hResult := DllCall(::hHandle, DLL_OSAPI, "NFE_ValidarRegrasdeNegocios") ::CheckResult(hResult) RETURN nil METHOD CheckResult(hResult) CLASS ACBrNFe local buffer, bufferLen, oErr if hResult >= 0 RETURN nil endif bufferLen := STR_LEN buffer := Space(bufferLen) DllCall(::hHandle, DLL_OSAPI, "NFE_UltimoRetorno", @buffer, @bufferLen) if bufferLen > STR_LEN buffer := Space(bufferLen) DllCall(::hHandle, DLL_OSAPI, "NFE_UltimoRetorno", @buffer, @bufferLen) endif oErr := ErrorNew() oErr:Severity := ES_ERROR oErr:Description := hb_UTF8ToStr(buffer) Throw(oErr) RETURN nil Abaixo está o meu PRG modificado. Log ACBR: ACBrLibNFE-20201223.log FUNCTION ACBR_CRIA_ASSINA_VALIDA_ENVIA(xTxt,xChaveNfe) LOCAL cRet,xLocalXml,xXml,lAssinaValidaEnvia:=.T. LOCAL xPara,xCopias,xAssunto,xMensagem ** Nome do XML e local de onde será salvo xXml:=xChaveNfe+"-nfe.xml" xLocalXml:=pDisco+":\xHB\nfe\"+UPPER(pUnidadeUf)+"\XML\" xPdf:=xChaveNfe+"-nfe.pdf" xLocalPdf:=pDisco+":\xHB\nfe\"+UPPER(pUnidadeUf)+"\PDF\" ** Iniciar arquivo de configurações do ACBR nfe:=ACBrNFe():New(pUnidadeUf+"_NFE.INI","") ** Consulta a chave para saber se já é uma NFe Autorizada para uso cRet:=nfe:Consultar(xChaveNfe,.T.) if at("Consumo Indevido",cRet)>0 alert("Consumo Indevido;;Aguarde alguns minutos e tente novamente") nfe:Destroy() RETURN .F. endif if at("Autorizado o uso da NF-e",cRet)>0 lAssinaValidaEnvia:=.F. ** Pega a data correta em que a Nfe foi emitida q:="select concat(year(b09demi),lpad(month(b09demi),2,'0')) as pasta from nfec where chavenfe='"+xChaveNfe+"'" v:=F_GETCON(q) if len(v)==0 alert("Erro ao localizar a chave no Nfec;"+xChaveNfe) nfe:Destroy() RETURN .F. endif xPastaAno:=v[1,1] xLocalXml:=xLocalXml+xPastaAno+"\" xLocalPdf:=xLocalPdf+xPastaAno+"\" ** Verifica se o arquivo XML existe na pasta if ! FILE(xLocalXml+xXml) ** Para garantir cria a pasta do anomes do XML e PDF FT_MKDIR(xLocalXml) FT_MKDIR(xLocalPdf) alert("NFe autorizada, porem arquivo xml nao localizado na pasta:;"+xLocalXml+xXml+";Faca o download pelo site do SEFAZ e coloque na pasta indicada") nfe:Destroy() RETURN .F. endif else xLocalXml:=xLocalXml+strZero(year(date_sql()),4)+strZero(month(date_sql()),2)+"\" xLocalPdf:=xLocalPdf+strZero(year(date_sql()),4)+strZero(month(date_sql()),2)+"\" endif ** Para garantir cria a pasta do anomes do XML e PDF FT_MKDIR(xLocalXml) FT_MKDIR(xLocalPdf) if lAssinaValidaEnvia ** Carrega o arquivo TXT da NFe nfe:CarregarINI(xTxt) ** Valida regras de negócio da NFe cRet:=nfe:ValidarRegrasdeNegocios() cRet:=strTran(cRet,chr(0),"") //Elimina um quadrado "[]" do retrono cRet:=strTran(cRet,chr(32),"") //Elimina um quadrado "[]" do retrono if ! empty(cRet) alert(cRet) nfe:Destroy() RETURN .F. endif ** Assina NFe que está carregada pelo NFE_CarregarINI nfe:Assinar() ** Validar XML assinado na pasta correta nfe:Validar() ** Grava XML assinado na pasta correta nfe:GravarXml(0,xXml,xLocalXml) ** Enviar XML par ao SEFAZ nfe:Enviar(0,.T.,.T.,.F.) else ** Se o XML já está autorizado apenas o carrga ** Para poder imprimir e enviar por e-mail nfe:CarregarXML(xLocalXml+xXml) endif nfe:ImprimirPDF() FileCopy(pDisco+":\xHB\nfe\"+UPPER(pUnidadeUf)+"\PDF\"+xPdf,xLocalPdf+xPdf) mVar:=ACBR_EMAIL(xChaveNfe) xPara:=mVar[1] xCopias:=mVar[2] xAssunto:=mVar[3] xMensagem:=mVar[4] nfe:EnviarEmail(xPara, xLocalXml+xXml,.T.,xAssunto,xMensagem,xCopias) nfe:Destroy() RETURN .T. Link to post Share on other sites
Rafael Dias 1,215 Posted December 23, 2020 Report Share Posted December 23, 2020 Pelo o que vi esta errado a chamada na classe, já mandei uma correção para ela no SVN. E sobre fechar, basta você capturar e tratar o exception que vai parar de fechar. Rafael Dias Ajude o Projeto ACBr crescer - Assine o SAC Desenvolvedor ACBrLib. Link to post Share on other sites
lcarakaki 2 Posted December 23, 2020 Author Report Share Posted December 23, 2020 @Rafael Dias, fiz algumas modificações no prg acbrnfe.prg e funcionou! São elas: Método ValidarRegrasdeNegocios não tinha variável para o retorno. Método EnviarEmail estava com variáveis invertidas na chamada do método do prg e do método da dll Destroy() não era um método e sim uma procedure, mudei para método As correções ficaram assim: METHOD ValidarRegrasdeNegocios() CLASS ACBrNFe local hResult, buffer, bufferLen bufferLen := STR_LEN buffer := Space(bufferLen) hResult := DllCall(::hHandle, DLL_OSAPI, "NFE_ValidarRegrasdeNegocios", @buffer, @bufferLen) ::CheckResult(hResult) RETURN ::ProcessResult(buffer, bufferLen) METHOD EnviarEmail(ePara, eChaveNFe, aEnviaPDF, eAssunto, eCc, eAnexos, eMensagem) CLASS ACBrNFe local hResult hResult := DllCall(::hHandle, DLL_OSAPI, "NFE_EnviarEmail", hb_StrToUTF8(ePara), hb_StrToUTF8(eChaveNFe), aEnviaPDF, eAssunto, hb_StrToUTF8(eCc), hb_StrToUTF8(eAnexos), eMensagem) ::CheckResult(hResult) RETURN nil METHOD Destroy CLASS ACBrNFe DllCall(::hHandle, DLL_OSAPI, "NFE_Finalizar") DllUnload(::hHandle) RETURN nil obrigado pela ajuda! Link to post Share on other sites
Rafael Dias 1,215 Posted December 23, 2020 Report Share Posted December 23, 2020 Obrigado pelas correções, mas mesmo assim vai precisa fazer o tratamento de erros, pois tem retornos que pode lançar exceptions e se não forem tratados vai fechar a aplicação. Rafael Dias Ajude o Projeto ACBr crescer - Assine o SAC Desenvolvedor ACBrLib. Link to post Share on other sites
Rafael Dias 1,215 Posted December 23, 2020 Report Share Posted December 23, 2020 Obrigado por reportar. Fechando. Para novas dúvidas, criar um novo tópico. Rafael Dias Ajude o Projeto ACBr crescer - Assine o SAC Desenvolvedor ACBrLib. Link to post Share on other sites
Recommended Posts