activities
latest
false
Importante :
A tradução automática foi aplicada parcialmente neste conteúdo.
UiPath logo, featuring letters U and I in white
Atividades do UIAutomation
Last updated 28 de out de 2024

Inject .NET Code

UiPath.Core.Activities.InjectDotNetCode

Description

Injeta código .NET no thread principal da interface gráfica do aplicativo de destino. Destinado ao uso com aplicativos .NET UI que não expõem tecnologias de automação tradicionais ou não podem ser direcionados corretamente por meios tradicionais.

Propriedades

Comum
  • ContinuarComErro — especifica se a automação deve continuar mesmo quando a atividade gera um erro. Este campo só aceita valores booleanos (True, False). O valor padrão é False. Como resultado, se o campo estiver em branco e um erro for lançado, a execução do projeto será interrompida. Se o valor for definido como True, a execução do projeto prosseguirá mesmo com erros.

    Observação: se essa atividade estiver incluída na atividade Try Catch e o valor da propriedade ContinuarComErro for True, nenhum erro será capturado quando o projeto for executado.
  • NomeDeExibição - o nome de exibição da atividade.
Entrada
  • Montagem - O caminho completo para a montagem de compilação .NET que você deseja injetar.Este campo é compatível apenas com strings e variáveis String.
  • Nome do Método - o nome do método que você deseja executar. Somente métodos estáticos públicos são suportados.

    Observação: Um tipo não pode conter vários métodos com o mesmo nome. Se for esse o caso, um erro é exibido em runtime.
  • Target.ClippingRegion - Define o retângulo de recorte, em pixels, relativo ao UiElement, nas seguintes direções: esquerda, superior, direita, inferior. Ele suporta números positivos e negativos.
  • Target.Element - Use a variável UiElement retornada por outra atividade. Esta propriedade não pode ser usada junto com a propriedade Selector. Este campo suporta apenas variáveis UiElement.
  • Target.Selector - Propriedade de texto usada para localizar um determinado elemento da interface do usuário quando a atividade é executada. Na verdade, é um fragmento XML especificando atributos do elemento GUI que você está procurando e de alguns de seus pais.
  • Target.TimeoutMS - Especifica a quantidade de tempo (em milissegundos) para aguardar a execução da atividade antes que o erro SelectorNotFoundException seja lançado. O valor padrão é 30000 milissegundos (30 segundos).
  • Target.WaitForReady - Antes de executar as ações, aguarde o destino ficar pronto. As seguintes opções estão disponíveis:

    • Nenhum — não espera por nada, exceto o elemento de interface gráfica do alvo existir antes de executar a ação. Por exemplo, você pode usar essa opção se quiser recuperar apenas o texto de uma página web ou clicar em um botão específico, sem precisar esperar todos os elementos da interface gráfica carregarem. Observe que isso pode ter consequências indesejadas se o botão depender de elementos ainda não carregados, como scripts.
    • Interativo/completo - espera que todos os elementos da interface do usuário no aplicativo de destino existam antes de executar a ação.

      Para avaliar se um aplicativo está no estado Interativo ou Concluído, as seguintes tags são verificadas:

    • Aplicativos de área de trabalho — uma mensagem wm_null é enviada para verificar a existência das tags,<wnd> ,<ctrl> ,<java> ou. <uia>Se existirem, a atividade é executada.
    • Aplicativos web:
    1. Internet Explorer - A tag <webctrl> é usada para verificar se o estado Pronto do documento HTML está definido como Concluído. Além disso, o estado Ocupado deve ser definido como “Falso”.
    2. Outros - A tag <webctrl> é usada para verificar se o estado Pronto do documento HTML está Concluído.
    • Aplicativos SAP — primeiro a presença da tag <wnd> é verificada e, depois disso, uma API específica do SAP é usada para detectar se a sessão está ocupada ou não.
  • TipoDeNome - O nome da classe pública que contém o método de execução. Este campo é compatível apenas com strings e variáveis String.
Diversos
  • Privado - Se selecionado, os valores de variáveis e argumentos não são mais registrados no nível Verbose.
Saída
  • Resultado - O resultado do método invocado, armazenado em um variável Object.Este campo é compatível apenas com variáveis Object.

Injetando código em AppDomains não padrão

A atividade Inject .NET Code injeta código apenas no AppDomain padrão.

Alguns aplicativos são estruturados de tal maneira que os elementos que você pode precisar acessar ou manipular não estejam localizados dentro do AppDomain padrão. Portanto, injetar código no AppDomain padrão não é suficiente. Portanto, se os elementos da interface gráfica que você deseja indicar estiverem localizados em outro AppDomain, eles não estarão disponíveis para o código injetado.

Para corrigir isso, você deve modificar o processo de injeção para direcionar o AppDomain preciso que contém os elementos da interface gráfica. Mais exatamente, você precisa injetar código da função que é executada no AppDomain padrão em todos os AppDomains não padrão ou no AppDomain não padrão específico que contém os elementos da interface gráfica que você deseja indicar.

Criar um executor cruzado do AppDomain

Para executar código em AppDomains não padrão, você precisa criar uma classe derivada de MarshalByRefObject, contendo a função que deseja executar em AppDomains não padrão:
public class CrossAppDomainRunner : MarshalByRefObject
{
    public void Execute(IntPtr controlHandle)
    {
        // Implementation of the method that will be executed in the target AppDomain
        Trace.WriteLine("Sunt in " + AppDomain.CurrentDomain.FriendlyName);

        Control foundControl = null;
        try
        {
            foundControl = Control.FromHandle(controlHandle);
        }
        catch (Exception controlException)
        {
            int lastWin32Error = Marshal.GetLastWin32Error();
            Trace.WriteLine($"+++++ An exception occurred while getting the control from handle {controlHandle}. The message is: {controlException.Message}, Win32 Error: {lastWin32Error}");
            
        }
        if (foundControl != null)
        {
            Trace.WriteLine($"+++++ Found control {foundControl.Name} from handle {controlHandle}");
            
        }
        else
        {
            int lastWin32Error = Marshal.GetLastWin32Error();
            Trace.WriteLine($"+++++ Control NOT found based on handle {controlHandle}, Win32 Error: {lastWin32Error}");
            
        }
    }
}public class CrossAppDomainRunner : MarshalByRefObject
{
    public void Execute(IntPtr controlHandle)
    {
        // Implementation of the method that will be executed in the target AppDomain
        Trace.WriteLine("Sunt in " + AppDomain.CurrentDomain.FriendlyName);

        Control foundControl = null;
        try
        {
            foundControl = Control.FromHandle(controlHandle);
        }
        catch (Exception controlException)
        {
            int lastWin32Error = Marshal.GetLastWin32Error();
            Trace.WriteLine($"+++++ An exception occurred while getting the control from handle {controlHandle}. The message is: {controlException.Message}, Win32 Error: {lastWin32Error}");
            
        }
        if (foundControl != null)
        {
            Trace.WriteLine($"+++++ Found control {foundControl.Name} from handle {controlHandle}");
            
        }
        else
        {
            int lastWin32Error = Marshal.GetLastWin32Error();
            Trace.WriteLine($"+++++ Control NOT found based on handle {controlHandle}, Win32 Error: {lastWin32Error}");
            
        }
    }
}
Basicamente, você tem uma função Execute que recebe um parâmetro IntPtr . Esse parâmetro contém o valor do controle que você está tentando encontrar. Neste exemplo, você precisa passar apenas um parâmetro IntPtr , mas, em sua situação específica, você pode adicionar quantos parâmetros desejar.

Como enumerar e injetar código em AppDomains não padrão

Para enumerar os outros AppDomains, você precisa de um ponteiro para a interface ICorRuntimeHost de mscoree. Para fazê-lo, você precisa declarar essa interface:
using System;
                using System.Collections.Generic;
                using System.Diagnostics;
                using System.Reflection;
                using System.Runtime.InteropServices;
                
                namespace mscoree
                {
                [CompilerGenerated]
                [Guid("CB2F6722-AB3A-11D2-9C40-00C04FA30A3E")]
                [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
                [TypeIdentifier]
                [ComImport]
                [CLSCompliant(false)]
                public interface ICorRuntimeHost
                {
                void _VtblGap1_11();
                
                void EnumDomains(out IntPtr enumHandle);
                
                void NextDomain([In] IntPtr enumHandle, [MarshalAs(UnmanagedType.IUnknown)] out object appDomain);
                
                void CloseEnum([In] IntPtr enumHandle);
                }
                }using System;
                using System.Collections.Generic;
                using System.Diagnostics;
                using System.Reflection;
                using System.Runtime.InteropServices;
                
                namespace mscoree
                {
                [CompilerGenerated]
                [Guid("CB2F6722-AB3A-11D2-9C40-00C04FA30A3E")]
                [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
                [TypeIdentifier]
                [ComImport]
                [CLSCompliant(false)]
                public interface ICorRuntimeHost
                {
                void _VtblGap1_11();
                
                void EnumDomains(out IntPtr enumHandle);
                
                void NextDomain([In] IntPtr enumHandle, [MarshalAs(UnmanagedType.IUnknown)] out object appDomain);
                
                void CloseEnum([In] IntPtr enumHandle);
                }
                } 

É preciso declarar uma classe que contenha métodos nativos para inicializar o Modelo de Objeto do Componente (COM):

public static class NativeMethods
                {
                
                [DllImport("ole32.dll")]
                public static extern int CoInitializeEx(IntPtr pvReserved, COINIT dwCoInit);
                
                public enum COINIT : uint
                {
                /// Initializes the thread for multi-threaded object concurrency.
                COINIT_MULTITHREADED = 0x0,
                /// Initializes the thread for apartment-threaded object concurrency. 
                COINIT_APARTMENTTHREADED = 0x2,
                // ...
                }
                }public static class NativeMethods { [DllImport("ole32.dll")] public static extern int CoInitializeEx(IntPtr pvReserved, COINIT dwCoInit); public enum COINIT : uint { /// Inicializa a thread para a concorrência de objetos com várias threads.
                COINIT_MULTITHRADEED = 0x0, /// Inicializa a thread para simultaneidade de objetos dentro de threads de compartimento. 
                COINIT_APpartmentthreaded = 0x2, // ... } }   
Você precisa de um método para obter um objeto ICorRunttimeHost :
public static ICorRuntimeHost GetCorRuntimeHost()
                {
                return (ICorRuntimeHost)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E")));
                }public static ICorRuntimeHost GetCorRuntimeHost()
                {
                return (ICorRuntimeHost)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E")));
                }
Agora, você tem tudo pronto para enumerar os outros AppDomains e executar código neles. A função GetControlData é executada pela atividade Inject .NET Code no AppDomain padrão:
public static void GetControlData(Int64 controlHandle, out string response)
                {
                //initialising COM
                NativeMethods.CoInitializeEx(IntPtr.Zero, NativeMethods.COINIT.COINIT_MULTITHREADED);
                
                mscoree.ICorRuntimeHost host = null;
                try
                {
                host = (ICorRuntimeHost)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E")));
                }
                catch (COMException comEx)
                {
                Trace.WriteLine($"COMException: {comEx.Message}, HRESULT: {comEx.ErrorCode}");
                }
                catch (Exception ex)
                {
                // Handle other exceptions
                Trace.WriteLine($"Exception: {ex.Message}");
                }
                
                
                
                IntPtr enumHandle = IntPtr.Zero;
                
                try
                {
                //now that we have ICorRuntimeHost object we can use it to enumerate the other domains
                host.EnumDomains(out enumHandle);
                object domain = null;
                host.NextDomain(enumHandle, out domain);
                while (domain != null)
                {
                //for each appdomain obtained
                AppDomain appDomain = (AppDomain)domain;
                //appDomain.BaseDirectory; - you might want to copy your dll 
                //in the appDomain.BaseDirectory cause otherwise it might not find 
                //the assembly 
                
                ObjectHandle handle = appDomain.CreateInstance(
                typeof(CrossAppDomainRunner).Assembly.FullName,
                typeof(CrossAppDomainRunner).FullName);
                
                // Unwrap to get the actual object
                
                var runnerProxy = handle.Unwrap();
                
                // Use reflection to call the Execute method
                MethodInfo executeMethod = runnerProxy.GetType().GetMethod("Execute", new Type[] { typeof(IntPtr) });
                //pass parameters as new object[]
                executeMethod.Invoke(runnerProxy, new object[] { new IntPtr(controlHandle) });
                
                //go to next appdomain
                host.NextDomain(enumHandle, out domain);
                if (domain == null)
                break;
                
                }
                }
                finally
                {
                if (host != null)
                {
                if (enumHandle != IntPtr.Zero)
                {
                host.CloseEnum(enumHandle);
                }
                
                Marshal.ReleaseComObject(host);
                }
                
                }
                response = string.Empty;
                }public static void GetControlData(Int64 controlHandle, out string response)
                {
                //initialising COM
                NativeMethods.CoInitializeEx(IntPtr.Zero, NativeMethods.COINIT.COINIT_MULTITHREADED);
                
                mscoree.ICorRuntimeHost host = null;
                try
                {
                host = (ICorRuntimeHost)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E")));
                }
                catch (COMException comEx)
                {
                Trace.WriteLine($"COMException: {comEx.Message}, HRESULT: {comEx.ErrorCode}");
                }
                catch (Exception ex)
                {
                // Handle other exceptions
                Trace.WriteLine($"Exception: {ex.Message}");
                }
                
                
                
                IntPtr enumHandle = IntPtr.Zero;
                
                try
                {
                //now that we have ICorRuntimeHost object we can use it to enumerate the other domains
                host.EnumDomains(out enumHandle);
                object domain = null;
                host.NextDomain(enumHandle, out domain);
                while (domain != null)
                {
                //for each appdomain obtained
                AppDomain appDomain = (AppDomain)domain;
                //appDomain.BaseDirectory; - you might want to copy your dll 
                //in the appDomain.BaseDirectory cause otherwise it might not find 
                //the assembly 
                
                ObjectHandle handle = appDomain.CreateInstance(
                typeof(CrossAppDomainRunner).Assembly.FullName,
                typeof(CrossAppDomainRunner).FullName);
                
                // Unwrap to get the actual object
                
                var runnerProxy = handle.Unwrap();
                
                // Use reflection to call the Execute method
                MethodInfo executeMethod = runnerProxy.GetType().GetMethod("Execute", new Type[] { typeof(IntPtr) });
                //pass parameters as new object[]
                executeMethod.Invoke(runnerProxy, new object[] { new IntPtr(controlHandle) });
                
                //go to next appdomain
                host.NextDomain(enumHandle, out domain);
                if (domain == null)
                break;
                
                }
                }
                finally
                {
                if (host != null)
                {
                if (enumHandle != IntPtr.Zero)
                {
                host.CloseEnum(enumHandle);
                }
                
                Marshal.ReleaseComObject(host);
                }
                
                }
                response = string.Empty;
                }

O exemplo acima injeta o código em todos os AppDomains. Após descobrir o DomínioDoAplicativo onde os elementos de interface gráfica que deseja indicar estão localizados, você pode enumerar todos os DomíniosAplicativos, mas injetar código apenas no DomínioDoAplicativo necessário.

Esta página foi útil?

Obtenha a ajuda que você precisa
Aprendendo RPA - Cursos de automação
Fórum da comunidade da Uipath
Uipath Logo White
Confiança e segurança
© 2005-2024 UiPath. Todos os direitos reservados.