Late Binding is a mechanism to invoke methods from objects at the runtime of a program. We know this calling method mainly from the Component Object Method (COM) environment. Based on my approach to using the Win32 API I made an extension so that late binding can also be realized with the VisualBasic dotNET programming language.
Here the code of the Invoke Code activity. It is almost the same as the Win32 API usage, but here the language (C#, VB dotNET or JScript) can be selected.
//-UiPath Begin---------------------------------------------------------
CompilerResults CompResult;
//-Setting of the compiler version--------------------------------------
Dictionary<string, string> providerOptions = new Dictionary<string, string> {
{"CompilerVersion", "v4.0"}
};
//-Setting of the language----------------------------------------------
CodeDomProvider CodeProvider = null;
switch(Language.ToUpper()) {
case "CS":
CodeProvider = new CSharpCodeProvider(providerOptions);
break;
case "VB":
CodeProvider = new VBCodeProvider(providerOptions);
break;
case "JS":
CodeProvider = new JScriptCodeProvider();
break;
default:
ErrorMessage = "Language unknown";
Console.WriteLine("Error: " + ErrorMessage);
return;
}
//-Setting of the compiler parameters-----------------------------------
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.GenerateInMemory = true;
compilerParams.GenerateExecutable = false;
compilerParams.IncludeDebugInformation = true;
compilerParams.WarningLevel = 3;
string[] assemblies = Assemblies.Split(new char[] { ',' } );
foreach(string Assembly in assemblies) {
compilerParams.ReferencedAssemblies.Add(Assembly);
}
//-Checking the code----------------------------------------------------
if(System.String.IsNullOrEmpty(Code.Trim())) {
ErrorMessage = "Code missed";
return;
}
//-Compiling of the code------------------------------------------------
CompResult = CodeProvider.CompileAssemblyFromSource(compilerParams, Code);
//-Checking if compiling code exists------------------------------------
if(CompResult == null) {
ErrorMessage = "Compiling code missed";
return;
}
StringCollection CompOutput = CompResult.Output;
if(CompResult.Errors.Count != 0) {
ErrorMessage = "Compilation failed" + Environment.NewLine;
foreach(string CompOutputLine in CompOutput) {
if(!string.IsNullOrEmpty(CompOutputLine)) {
if(!CompOutputLine.Contains("This compiler is provided as part of the Microsoft (R) .NET Framework") &&
!CompOutputLine.Contains("Copyright (C) Microsoft Corporation. All rights reserved.")) {
ErrorMessage += CompOutputLine + Environment.NewLine;
}
}
}
return;
}
//-Read constructor parameters and add it to a list---------------------
object[] ConstructorParams = null;
if(!System.String.IsNullOrEmpty(ConstructorParameters)) {
string[] partsConstructorParams = ConstructorParameters.Split(new char[] { ',' });
ConstructorParams = new List<string>(partsConstructorParams).ToArray();
}
//-Read method parameters and add it to a list--------------------------
object[] MethodParams = null;
if(!System.String.IsNullOrEmpty(MethodParameters)) {
string[] partsMethodParams = MethodParameters.Split(new char[] { ',' });
MethodParams = new List<string>(partsMethodParams).ToArray();
}
//-Checking the instance------------------------------------------------
if(System.String.IsNullOrEmpty(Instance.Trim())) {
ErrorMessage = "Instance missed";
return;
}
//-Create instance and invoke method------------------------------------
try {
object oInstance = CompResult.CompiledAssembly.CreateInstance(
Instance,
false,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance,
null, // use default binder
ConstructorParams,
null, // use CultureInfo from current thread,
null
);
if(!System.String.IsNullOrEmpty(Method)) {
MethodInfo MethInfo = oInstance.GetType().GetMethod(Method);
object oResult = MethInfo.Invoke(oInstance, MethodParams);
if(oResult != null) {
Result = oResult.ToString();
}
}
} catch (System.Exception ex) {
ErrorMessage = ex.Message + Environment.NewLine + ex.StackTrace;
}
//-UiPath End-----------------------------------------------------------
Here a tiny example to use late binding.
Here the invoked code. In this example I use the MSScriptControl to execute a VBScript code, only to show a message box.
@"
Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.VisualBasic
Class Test
Sub Main()
Dim VBS As Object
VBS = CreateObject(""MSScriptControl.ScriptControl"")
VBS.Language = ""VBScript""
VBS.AllowUI = True
VBS.ExecuteStatement(""MsgBox """"Hello World via Late Binding in UiPath from VBScript!"""", VBOkOnly, """"ExecuteStatement"""""")
End Sub
End Class
"
And it works as expected.
On this way late binding can be used in the context of UiPath, without additional packages.
Here my example project:
LateBinding.zip (34.5 KB)
And also it is possible to use JScript.
@"
import System.Windows.Forms;
class Test {
function Main() {
MessageBox.Show(""Hello World with native dotNET"", ""JScript"");
}
}
"
Addendum 11.09.2022: The approach presented here is deprecated, because it can’t work in the Windows compatibility mode. It is suggested to use the late binding approach with dotNET 5 and 6.