// Executa a captura de dado solicitada pela biblioteca
        private int ShowCorrespondingWindow(PW_GetData[] expectedData, ref FormDisplayQRcode fdqr)
        {
            int                ret   = 0;
            ushort             index = 0;
            FormDisplayMessage fdm;

            foreach (PW_GetData item in expectedData)
            {
                // Caso exista uma mensagem a ser exibida ao usuário antes da captura do dado
                if (item.szMsgPrevia.Length > 0)
                {
                    fdm = new FormDisplayMessage();
                    fdm.ShowDialog(item.szMsgPrevia, 3000);
                    fdm.Dispose();
                }

                ret = 0;
                switch (item.bTipoDeDado)
                {
                case 0:
                    Debug.Print(string.Format("ERRO!!! Item com valor zerado."));
                    return(ret);

                // Caso a automação trabalhe com captura de código de barras, necessário
                // implementar os casos que serão aceitos (digitado, leitor...), bem como
                //  as validações necessárias por tipo de código
                case (int)E_PWDAT.PWDAT_BARCODE:
                    ret = GetTypedDataFromUser(item);
                    return(ret);

                // Menu de opções
                case (int)E_PWDAT.PWDAT_MENU:
                    return(GetMenuFromUser(item));

                // Captura de dado digitado
                case (int)E_PWDAT.PWDAT_TYPED:
                    ret = GetTypedDataFromUser(item);
                    return(ret);

                // Autenticação de permissão de usuário
                case (int)E_PWDAT.PWDAT_USERAUTH:
                    ret = GetTypedDataFromUser(item);
                    return(ret);

                // Captura de dados do cartão
                case (int)E_PWDAT.PWDAT_CARDINF:
                    // Caso só seja aceito o modo de entrada de cartão digitado
                    if (item.ulTipoEntradaCartao == 1)
                    {
                        PW_GetData temp = item;
                        temp.wIdentificador = (ushort)E_PWINFO.PWINFO_CARDFULLPAN;
                        ret = GetTypedDataFromUser(temp);
                    }
                    // Caso seja aceito cartão lido pelo PIN-pad
                    else
                    {
                        ret = Interop.PW_iPPGetCard(index);
                        Debug.Print(string.Format("PW_iPPGetCard={0}", ret.ToString()));
                        if (ret == (int)E_PWRET.PWRET_OK)
                        {
                            ret = LoopPP();
                        }
                    }
                    return(ret);

                // Processamento offline do cartão
                case (int)E_PWDAT.PWDAT_CARDOFF:
                    ret = Interop.PW_iPPGoOnChip(index);
                    Debug.Print(string.Format("PW_iPPGoOnChip={0}", ret.ToString()));
                    if (ret == (int)E_PWRET.PWRET_OK)
                    {
                        ret = LoopPP();
                    }
                    return(ret);

                // Processamento online do cartão
                case (int)E_PWDAT.PWDAT_CARDONL:
                    ret = Interop.PW_iPPFinishChip(index);
                    Debug.Print(string.Format("PW_iPPFinishChip={0}", ret.ToString()));
                    if (ret == (int)E_PWRET.PWRET_OK)
                    {
                        ret = LoopPP();
                    }
                    return(ret);

                // Confirmação de dado no PIN-pad
                case (int)E_PWDAT.PWDAT_PPCONF:
                    ret = Interop.PW_iPPConfirmData(index);
                    Debug.Print(string.Format("PW_iPPConfirmData={0}", ret.ToString()));
                    if (ret == (int)E_PWRET.PWRET_OK)
                    {
                        ret = LoopPP();
                    }
                    return(ret);

                // Confirmação positiva PIN-pad
                case (int)E_PWDAT.PWDAT_PPDATAPOSCNF:
                    ret = Interop.PW_iPPPositiveConfirmation(index);
                    Debug.Print(string.Format("PW_iPPPositiveConfirmation={0}", ret.ToString()));
                    if (ret == (int)E_PWRET.PWRET_OK)
                    {
                        ret = LoopPP();
                    }
                    return(ret);

                // Comando genérico no PIN-pad
                case (int)E_PWDAT.PWDAT_PPGENCMD:
                    ret = Interop.PW_iPPGenericCMD(index);
                    Debug.Print(string.Format("PW_iPPGenericCMD={0}", ret.ToString()));
                    if (ret == (int)E_PWRET.PWRET_OK)
                    {
                        ret = LoopPP();
                    }
                    return(ret);

                // Senha do portador
                case (int)E_PWDAT.PWDAT_PPENCPIN:
                    ret = Interop.PW_iPPGetPIN(index);
                    Debug.Print(string.Format("PW_iPPGetPIN={0}", ret.ToString()));
                    if (ret == (int)E_PWRET.PWRET_OK)
                    {
                        ret = LoopPP();
                    }
                    return(ret);

                // Entrada digitada no PIN-pad
                case (int)E_PWDAT.PWDAT_PPENTRY:
                    ret = Interop.PW_iPPGetData(index);
                    Debug.Print(string.Format("PW_iPPGetData={0}", ret.ToString()));
                    if (ret == (int)E_PWRET.PWRET_OK)
                    {
                        ret = LoopPP();
                    }
                    return(ret);

                // Remoção de cartão do PIN-pad
                case (int)E_PWDAT.PWDAT_PPREMCRD:
                    ret = Interop.PW_iPPRemoveCard();
                    Debug.Print(string.Format("PW_iPPRemoveCard={0}", ret.ToString()));
                    if (ret == (int)E_PWRET.PWRET_OK)
                    {
                        ret = LoopPP();
                    }
                    return(ret);

                // Exibição de mensagem de interface no display da automação
                case (int)E_PWDAT.PWDAT_DSPCHECKOUT:
                    fdm = new FormDisplayMessage();
                    fdm.Start();
                    fdm.ChangeText(item.szPrompt);
                    Thread.Sleep(1000);
                    // Caso o operador tenha apertado a tecla ESC, cancela a operação e aborta o comando do PINpad
                    if (fdm.isAborted())
                    {
                        // Aborta a operação em curso no PIN-pad
                        Interop.PW_iPPAbort();

                        // Atribui o retorno de aoperação cancelada
                        ret = (int)E_PWRET.PWRET_CANCEL;
                    }
                    fdm.Stop();

                    if (ret != (int)E_PWRET.PWRET_OK)
                    {
                        return(ret);
                    }
                    // Sinaliza a exibição da mensagem para a biblioteca
                    ret = Interop.PW_iAddParam(item.wIdentificador, "");
                    return((int)E_PWRET.PWRET_OK);

                // Exibição de QRcode no display da automação
                case (int)E_PWDAT.PWDAT_DSPQRCODE:

                    // Exemplo 2: A string com o QR Code é recebida e um QRcode é gerado utilizando uma biblioteca
                    // de terceiros, para compilar essa opção é necessário descomentar a função AtualizaQRCode na classe FormDisplayQRcode
                    // e instalar a biblioteca  MessagingToolkit.QRCode em seu Visual studio através do gerenciador de pacotes
                    // com o comando "Install-Package MessagingToolkit.QRCode -ProjectName PGWLib"
                    StringBuilder stringQRcode = new StringBuilder(5001);

                    // Tenta obter o valor do QRcode a ser exibido, caso não ache retorna operação cancelada
                    if (Interop.PW_iGetResult((short)E_PWINFO.PWINFO_AUTHPOSQRCODE, stringQRcode, 5001) != (int)E_PWRET.PWRET_OK)
                    {
                        return((int)E_PWRET.PWRET_CANCEL);
                    }

                    // Exibe o QRcode e o prompt
                    fdqr.Start();

                    // Para esse caso em específico o QR code é muito grande para exibir no display "padrão"
                    // Somente para esse exemplo, liga o autoSize da janela
                    fdqr.ChangeText(item.szPrompt, stringQRcode.ToString());

                    // Caso o operador tenha apertado a tecla ESC, cancela a operação e aborta o comando do PINpad
                    if (fdqr.isAborted())
                    {
                        // Aborta a operação em curso no PIN-pad
                        Interop.PW_iPPAbort();

                        fdqr.Stop();

                        // Atribui o retorno de aoperação cancelada
                        return((int)E_PWRET.PWRET_CANCEL);
                    }

                    // Sinaliza a exibição do QRcode para a biblioteca
                    ret = Interop.PW_iAddParam(item.wIdentificador, "");
                    return((int)E_PWRET.PWRET_OK);

                default:
                    break;
                }
                index++;
            }
            return(ret);
        }
        // Executa o loop da transação até que ela seja aprovada ou ocorra algum erro
        private int ExecuteTransaction()
        {
            int ret;
            FormDisplayQRcode fdqr = new FormDisplayQRcode();

            // Loop que só será interrompido em caso da finalização da transação, seja ela por algum
            // tipo de erro ou com o sucesso
            for (; ;)
            {
                // Cria a estrutura necessária para executar a função PW_iExecTransac, caso seja
                // necessário capturar algum dado, essa estrutura terá detalhes de como deverá ser feita
                // essa captura
                PW_GetData[] structParam = new PW_GetData[10];

                // Parâmetro que, na entrada, indica quantos registros possui a estrutura PW_GetData e
                // na saída indica quantos dados precisam ser capturados
                short numDados = 10;

                // Desmarca o desfazimento marcado por segurança, pois a transação irá para
                // controle pela biblioteca
                PendencyDelete();

                // Chama a função que executa um passo da transação
                ret = (int)Interop.PW_iExecTransac(structParam, ref numDados);

                // Marca um desfazimento por segurança, caso a automação seja fechada abruptamente
                // durante qualquer passo abaixo, o desfazimento já estará armazenado em disco para
                // ser executado por PendencyResolve antes da próxima transação
                // Esse desfazimento será desmarcado em duas situações:
                // 1-) O loop foi executado novamente e PW_iExecTransac será chamada
                // 2-) Algum erro ocorreu durante o loop
                // 3-) A transação foi finalizada com sucesso, nesse caso o desfazimento permanecerá
                //     gravado até a execução da resolução de pendência da transação em
                //     "ConfirmUndoNormalTransaction"
                PendencyWrite(E_PWCNF.PWCNF_REV_PWR_AUT);

                // Registra na janela de debug o resultado da execução
                Debug.Print(string.Format("PW_iExecTransac={0}", ret.ToString()));

                // Faz o tratamento correto de acordo com o retorno recebido em PW_iExecTransac
                switch (ret)
                {
                // Caso a biblioteca tenha solicitado a captura de mais dados, chama a função que
                // faz a captura de acordo com as informações contidas em structParam
                case (int)E_PWRET.PWRET_MOREDATA:
                    int ret2 = ShowCorrespondingWindow(structParam, ref fdqr);
                    if (ret2 != (int)E_PWRET.PWRET_OK)
                    {
                        if (ret2 == (int)E_PWRET.PWRET_CANCEL)
                        {
                            // Apaga o status de desfazimento anterior por desligamento abrupto da
                            // automação
                            PendencyDelete();

                            // Escreve o novo desfazimento a ser executado por transação abortada
                            // pela automação durante uma captura de dados
                            PendencyWrite(E_PWCNF.PWCNF_REV_ABORT);
                        }
                        return(ret2);
                    }
                    break;

                // Caso a biblioteca tenha retornado que existe uma transação pendente.
                // Esse retorno só irá acontecer em caso de alguma falha de tratamento da resolução
                // de pendência da transação por parte da automação, ou alguma falha de sistema
                // do Pay&Go WEB, caso um ponto de captura fique com uma transação pendente ele não
                // irá poder realizar novas transações até que essa pendência seja resolvida
                case (int)E_PWRET.PWRET_FROMHOSTPENDTRN:
                    // Desmarca o desfazimento marcado por segurança, pois a transação não foi
                    // finalizada com sucesso
                    PendencyDelete();

                    return(ret);

                // Esse retorno indica que nada deve ser feito e PW_iExecTransac deve ser chamada
                // novamente para prosseguir o fluxo
                case (int)E_PWRET.PWRET_NOTHING:
                    break;

                // Esse retorno indica que a transação foi executada com sucesso
                case (int)E_PWRET.PWRET_OK:
                    // Para de exibir o QRcode, caso exista um sendo exibido
                    fdqr.Stop();
                    return(ret);

                // Qualquer outro código de retorno representa um erro
                default:
                    // Para de exibir o QRcode, caso exista um sendo exibido
                    fdqr.Stop();
                    // Desmarca o desfazimento marcado por segurança, pois a transação não foi
                    // finalizada com sucesso
                    PendencyDelete();

                    return(ret);
                }
            }
        }