アクティビティ
最新
バナーの背景画像
UI Automation のアクティビティ
最終更新日 2024年4月26日

.NET コードを挿入

UiPath.Core.Activities.InjectDotNetCode

説明

対象のアプリケーションのメイン UI スレッドに .NET コードを挿入します。従来の自動化テクノロジを公開していない、または従来の手段では正しくターゲットにできない、.NET UI アプリケーションでの使用を目的としています。

プロパティ

共通
  • エラー発生時に実行を継続 - アクティビティが例外をスローした場合でも、ワークフローを継続するかどうかを指定します。このフィールドでは Boolean 値 (True、False) のみサポートされています。既定値は False です。その結果、フィールドが空白で例外がスローされると、プロジェクトの実行が停止します。値を True に設定すると、プロジェクトの実行はエラーに関係なく継続されます。

    注: このアクティビティが [トライ キャッチ] に含まれていて、[エラー発生時に実行を継続] プロパティの値が True の場合、プロジェクトが実行されたときにエラーは発生しません。
  • 表示名 - アクティビティの表示名です。
入力
  • アセンブリ - 挿入するコンパイル済みの .NET アセンブリへのフル パスです。このフィールドは、文字列と String 型変数のみをサポートします。
  • メソッド名 - 実行するメソッドの名前です。パブリック静的メソッドのみがサポートされます。

    注: 型に同じ名前の複数のメソッドを含めることはできません。この場合、実行時にエラーがスローされます。
  • Target.ClippingRegion - UiElement を基準とし、左、上、右、下の方向で、クリッピング四角形 (ピクセル単位) を定義します。正と負の両方の値をサポートしています。
  • Target.Element - 別のアクティビティから返される UiElement 変数を使用します。このプロパティを Selector プロパティと一緒に使用することはできません。このフィールドでは UiElement 変数のみサポートされています。
  • Target.Selector - アクティビティの実行時に特定の UI 要素の検索に使用する Text プロパティです。実際には、検索しようとする GUI 要素とそのいくつかの親要素の属性を指定する XML フラグメントです。
  • Target.TimeoutMS - アクティビティの実行が完了するまで待機する時間をミリ秒で指定します。指定した時間が経過しても実行が完了しない場合には、SelectorNotFoundException 例外をスローします。既定値は 30000 ミリ秒 (30 秒) です。
  • Target.WaitForReady - アクションを実行する前に、ターゲットが準備完了になるまで待ちます。次のオプションを使用できます。

    • NONE - ターゲット要素以外の要素の読み込みを待たずに、アクションを実行します。たとえば、UI 要素がすべて読み込まれるまで待つことなく、Web ページからテキストを取得したり、特定のボタンをクリックしたりする場合に、このオプションを使用できます。ボタンがまだ読み込まれていない要素 (スクリプトなど) に依存している場合、これは望ましくない結果を招く可能性があります。
    • Interactive/Complete - 実際に操作を実行する前に、対象アプリのすべての UI 要素が存在するようになるまで待ちます。

      アプリケーションが対話または完了のどちらのステートにあるか調べるには、以下のタグを検証します。

    • Desktop applications - <wnd> タグ、<ctrl> タグ、<java> タグ、または <uia> タグの存在を確認するために wm_null メッセージが送信されます。存在する場合、アクティビティが実行されます。
    • Web アプリケーション:
    1. Internet Explorer - <webctrl> タグは、HTML ドキュメントの Ready ステートが Complete に設定されているかどうかを確認するために使用されます。また、Busy ステートは「False」に設定されている必要があります。
    2. Others - <webctrl> タグは、HTML ドキュメントの Ready ステートが Complete であるかどうかを確認するために使用されます。
    • SAP applications - 最初に <wnd> タグを確認した後、SAP 固有の API を使用して、セッションがビジーかどうかを検出します。
  • 型名 - 実行メソッドを含むパブリック クラスの名前です。このフィールドは、文字列と String 型変数のみをサポートします。
その他
  • プライベート - オンにした場合、変数および引数の値が Verbose レベルでログに出力されなくなります。
出力
  • 結果 - 呼び出されたメソッドの結果。Object 変数に格納されます。このフィールドでは Object 変数のみがサポートされています。

既定以外のアプリケーション ドメインにコードを挿入する

[.NET コードを挿入] アクティビティは、既定のアプリケーション ドメインにのみコードを挿入します。

一部のアプリケーションは、ユーザーがアクセスや操作を行うために必要な要素を既定のアプリケーション ドメイン内に配置しない構造になっているため、既定のアプリケーション ドメインにコードを挿入するのでは不十分です。そのため、指定する UI 要素が別のアプリケーション ドメインにある場合、挿入したコードでその要素を利用することはできません。

これを修正するには、挿入プロセスを変更し、その UI 要素が含まれる正確なアプリケーション ドメインを対象にする必要があります。より正確に言うと、既定のアプリケーション ドメインで実行される関数から、既定以外のすべてのアプリケーション ドメイン、または指定する UI 要素が含まれる既定以外の特定のアプリケーション ドメインにコードを挿入する必要があります。

アプリケーション ドメイン間の実行機能を作成する

既定以外のアプリケーション ドメインでコードを実行するには、MarshalByRefObject から派生させたクラスを構築し、既定以外のアプリケーション ドメインで実行する関数を含める必要があります。
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}");
            
        }
    }
}
基本的には、IntPtr パラメーターを受け取る Execute 関数があります。このパラメーターに、検索しようとしているコントロールの値が格納されます。この例では、渡す必要があるのは IntPtr パラメーターだけですが、特定の状況では必要な数だけパラメーターを追加できます。

既定以外のアプリケーション ドメインを列挙してコードを挿入する

他のアプリケーション ドメインを列挙するには、mscoree から ICorRuntimeHost インターフェイスを指すポインターが必要です。このためには、次のようにそのインターフェイスを宣言する必要があります。
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);
                }
                } 

ネイティブ メソッドを含むクラスを宣言して、コンポーネント オブジェクト モデル (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
                {
                /// Initializes the thread for multi-threaded object concurrency.
                COINIT_MULTITHREADED = 0x0,
                /// Initializes the thread for apartment-threaded object concurrency. 
                COINIT_APARTMENTTHREADED = 0x2,
                // ...
                }
                }   
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")));
                }
これで、他のアプリケーション ドメインを列挙してそこでコードを実行する準備ができました。関数 GetControlData は、既定のアプリケーション ドメイン内の [.NET コードを挿入] アクティビティによって実行されます。
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;
                }

上の例では、すべてのアプリケーション ドメインにコードが挿入されます。指定する UI 要素が配置されているアプリケーション ドメインが見つかったら、すべてのアプリケーション ドメインを列挙できますが、コードは必要なアプリケーション ドメインにのみ挿入します。

Was this page helpful?

サポートを受ける
RPA について学ぶ - オートメーション コース
UiPath コミュニティ フォーラム
UiPath ロゴ (白)
信頼とセキュリティ
© 2005-2024 UiPath. All rights reserved.