ATEasy has many documented methods for accessing externally developed code and software. DLLs, ActiveX objects, and .NET classes can be imported. Command line utilities, VIs, and scripts can be run from within the ATEasy environment.
Should the need arise, ATEasy code can be exported to be used by other development environments. ATEasy projects can be compiled to DLLs which can be linked within other languages. Parameters described in a DLL procedure that are defined as ATEasy basic data types (Short, Long, Word, DWord, etc.) are easily passed and cast as a native type in the calling language.
The article Comparing C/C++, C#, VB and ATEasy Basic Data Types can be used as a reference for setting compatible basic data types. But, ATEasy Internal classes such as ATest, ATask, and ALog can require a bit more work. This article details the process using C++ and C#. | |
IDispatch: Using the methods and properties of an ATEasy object
ATEasy objects and classes are ActiveX/COM objects. The COM IDispatch interface allows the programmer to access an object's property and method list at run-time. ATEasy reserved objects such as Program, System, and Test can be passed out of ATEasy and used using the IDispatch interface. The ATEasy object's members can subsequently be read and altered.
Example 1: Creating The DLL - C++
The DLL we are creating within Visual Studio will contain three exported functions:- ATEasyClassSet() : Set a value to the specified property of the referenced object.
- ATEasyClassGet() : Get the value of the specified property of the referenced object.
- ATEasyClassMethod() : Call a method of the referenced object.
The project created is a Win32 console application that will be compiled to DLL. The project code was created in Microsoft Visual Studio 2005 and entitled IDispatchExample. It is provided at the bottom of this article.The Microsoft knowledge base article (retrieved from web.archive.org) How To Use Visual C++ to Access DocumentProperties with Automation details the automation of Excel operations using the IDispatch interface. We will reuse the helper function Autowrap() included within that article. The Autowrap() function ensures that your request is formatted properly and provides some user notification in case of an error while performing the get, set or call. Each of the following three exported functions will make a call to Autowrap:
ATEasyClassSet(): Setting an object's property
//PURPOSE: Sets the specified value vtParam to the specified property, sProperty on the object pATEasyObject
void WINAPI ATEasyClassSet(IDispatch *pATEasyObject, LPOLESTR sProperty, VARIANT vtParam)
{
AutoWrap(DISPATCH_PROPERTYPUT, NULL, pATEasyObject, sProperty, 1, vtParam);
}
ATEasyClassGet(): Getting an object's property
//PURPOSE: Gets the value of the specified property, sProperty of the specified object pATEasyObject and returns it in the referenced variant pvtParam.
void WINAPI ATEasyClassGet(IDispatch *pATEasyObject, LPOLESTR sProperty, VARIANT *pvtParam)
{
AutoWrap(DISPATCH_PROPERTYGET, pvtParam, pATEasyObject, sProperty, 0);
}
ATEasyClassMethod(): Calling an object's method
C supports calling functions with a variable number of arguments. Autowrap() supports variable arguments because we will be utilizing objects which are undefined within the DLL. The ATEasyClassMethod() function will take 4 variants as parameters and then check to see if each variant has been defined before calling Autowrap() (you can define it with more optional parameter in ATEasy if you use more than 4 arguments). It is assumed that if a variant is undefined within ATEasy, it will be passed to the DLL with the variant type VT_ERROR.
//PURPOSE: Executes the specified object pATEasyObject's method sMethod. This method supports 0 to 4 parameters.
void WINAPI ATEasyClassMethod(IDispatch *pATEasyObject, LPOLESTR sMethod, VARIANT vtParam1, VARIANT vtParam2, VARIANT vtParam3, VARIANT vtParam4)
{
if (vtParam1.vt==VT_ERROR && vtParam1.lVal==VT_ERROR_ARGMISSING)
{ AutoWrap(DISPATCH_METHOD, NULL, pATEasyObject, sMethod, 0);
return;
}
if (vtParam2.vt==VT_ERROR && vtParam2.lVal==VT_ERROR_ARGMISSING)
{ AutoWrap(DISPATCH_METHOD, NULL, pATEasyObject, sMethod, 1, vtParam1);
return;
}
if (vtParam3.vt==VT_ERROR && vtParam3.lVal==VT_ERROR_ARGMISSING)
{ AutoWrap(DISPATCH_METHOD, NULL, pATEasyObject, sMethod, 2, vtParam2, vtParam1);
return;
}
if (vtParam4.vt==VT_ERROR && vtParam4.lVal==VT_ERROR_ARGMISSING)
{ AutoWrap(DISPATCH_METHOD, NULL, pATEasyObject, sMethod, 3, vtParam3, vtParam2, vtParam1);
return;
}
AutoWrap(DISPATCH_METHOD, NULL, pATEasyObject, sMethod, 4, vtParam4, vtParam3, vtParam2, vtParam1);
}
The specific error type with be "ArgMissing" which is defined as 0x80020004. In the header, this can be declared as follows:
#define VT_ERROR_ARGMISSING 0x80020004
Testing the DLL with ATEasy - C++
Now that the DLL has been created, we can create an ATEasy application to test it.
The first step is to define the DLL in ATEasy. The ATEasy Internal Class should be passed as a Val Object. The property or method specifier should be a Val BString and the parameter data should Val or Var Variant, depending on whether you are sending or retrieve data. I started by creating a new library within my program module called IDispatchExample and defining the DLL procedures as such:
Procedure ATEasyClassMethod(pATEasyObject, sMethod, vtParam1, vtParam2, vtParam3, vtParam4): Void
--------------------------------------------------------------------------------
pATEasyObject: Val Object !Specifies the ATEasy Object to access
sMethod: Val BString !Specifies the method to call
vtParam1: [Val] Variant = VarEmpty ! Optional parameter 1
vtParam2: [Val] Variant = VarEmpty ! Optional parameter 2
vtParam3: [Val] Variant = VarEmpty ! Optional parameter 3
vtParam4: [Val] Variant = VarEmpty ! Optional parameter 4
Procedure ATEasyClassGet(pATEasyObject, sProperty, pvtParam): Void
--------------------------------------------------------------------------------
pATEasyObject: Val Object !Specifies the ATEasy Object to access
sProperty: Val BString !Specifies the property to get the value of
pvtParam: Var Variant !The returned value
Procedure ATEasyClassSet(pATEasyObject, sProperty, vtParam): Void
--------------------------------------------------------------------------------
pATEasyObject: Val Object !Specifies the ATEasy Object to access
sProperty: Val BString !Specifies the property to set the value of
vtParam: Val Variant !The value to be set
For the ATEasyClassSet test, the TestResult is intentionally set outside the Min/Max bounds. The ATEasyClassSet procedure is used to set the Min/Max bounds to 40 and 50. We expect this test to PASS if the ATEasyClassSet procedure is working.
Test 1.1 : "Modified Test Properties" ! ATEasyClassSet Test
-------------------------------------------------------------
Type = MinMax
Min = 5
Max = 5
{
TestResult=42
IDispatchExample.ATEasyClassSet(Test, "Max", 50)
IDispatchExample.ATEasyClassSet(Test, "Min", 40)
}
For the ATEasyClassMethod test, the TestResult is set to 42 and the Min/Max bounds have been set to 40 and 50. Within the test Test.Min and Test.Max have been used to set the Min and Max bounds to 5 and 10. The procedure ATEasyClassMethod is used to call the Test Object's Reset method. This should return the Max/Min bounds to 40 and 50 and will cause this test to PASS.
Test 1.2 : "Reset Method Called" ! ATEasyClassMethod Test
-------------------------------------------------------
Type = MinMax
Min = 40
Max = 50
{
TestResult=42
!Manually set the Test properties
Test.Max=5
Test.Min=10
!Call reset method from DLL, returning Test Properties to design-time default
IDispatchExample.ATEasyClassMethod(Test, "Reset")
}
The third test simply demonstrates the use of ATEasyClassMethod when a parameter has been provided. In this implementation, up to four parameters can be included with a method call. If this is working correctly, you should see the message "I am working!" appended to the end of this test.
Test 1.3 : "Log Append Called" !ATEasyClassMethod w/ Param Test
----------------------------------------------------------------
Type = Other
{
IDispatchExample.ATEasyClassMethod(Log, "Append", "\r\n///////////////////\r\n")
IDispatchExample.ATEasyClassMethod(Log, "Append", "// I am working! //\r\n")
IDispatchExample.ATEasyClassMethod(Log, "Append", "///////////////////\r\n")
TestStatus=PASS
}
The fourth and final test retrieves the file location of the Log object natively and also uses ATEasyClassGet to retrieve the Log's FullName property externally. The two values are compared and, if they match, the test will PASS.
Test 1.4 : "Get Log Properties" !ATEasyClassGet Test
----------------------------------------------------
Type = String
String = ""
{
!Retrieve the application's file and path natively
Test.String=Log.FullName
!Retrieve the application's file and path using IDispatch
IDispatchExample.ATEasyClassGet(Log, "FullName", varTest)
TestResult=varTest
}
Example 2: Creating The DLL - C#
The DLL we are creating within Visual Studio will contain three exported functions:- ATEasyTestSetMinMax() : Set the min and max properties of the referenced object.
- ATEasyTaskGetTestCount() : Get the value of the TestsCount property of the referenced object.
- ATEasyLogClear() : Call the Clear() method of the referenced object.
The project created is a Console Application (.NET 3.5 framework) that will be compiled to DLL. The project code was created in Microsoft Visual Studio 2008 and entitled ATEasyNetInterface. Make sure that you set the output of this project to Class Library. Change the default Class Name to Interface. Finally, add references to "C:\Windows\System32\AteRt.dll" and "C:\Windows\System32\AteCtl.dll". The project is provided at the bottom of this article.
ATEasyTestSetMinMax(): Sets a ATEasy test object's min and max properties
//PURPOSE: Sets the specified values iMin and iMax to the specified ATest object pExtObject
public void ATEasyTestSetMinMax(ref Object pExtObject, int iMin, int iMax)
{
AteRtLib.ATest ATEasyObject = (AteRtLib.ATest)pExtObject;
ATEasyObject.Min = iMin;
ATEasyObject.Max = iMax;
}
ATEasyTaskGetTestCount(): Getting an object's property
//PURPOSE: Gets the value of the TestsCount property from the specified ATask object pExtObject and returns it in the reference parameter iTestCount.
public void ATEasyTaskGetTestCount(ref Object pExtObject, ref int iTestCount)
{
AteRtLib.ATask ATEasyObject = (AteRtLib.ATask)pExtObject;
iTestCount = ATEasyObject.TestsCount;
}
ATEasyLogClear(): Clear the log of the specified ALog file
The Clear() method that is being demonstrated does not require any parameters be passed in. When creating a method which requires one or more parameters, they will have to be passed in or hard-coded within this class.
//PURPOSE: Executes the specified ALog object pExtObject's Clear() method.
public void ATEasyLogClear(ref Object pExtObject)
{
AteCtlLib.ALog ATEasyObject = (AteCtlLib.ALog)pExtObject;
ATEasyObject.Clear();
}
Testing the DLL with ATEasy - C#
Now that the DLL has been created, we can create an ATEasy application to test it.
After creating the ATEasy Test Application, insert the .NET assembly that we just created (ATEasyNetInterface.dll) into the Program module. Also, include the mscorlib assembly. Then create these variables:
obNetInterface: ATEasyNetInterface.Interface
vExtObj: Variant
obNetObj: mscorlib.NetObject
lTestCount: Long
For the first test, the Log clear() method is called, which causing the application and program header to be erased from the Test Log.
Test 1.1 : "Call Method"
--------------------------------------------------------------------------------
Id = Call_Method
Type = MinMax
{
!Create instance of .NET class
obNetInterface=new ATEasyNetInterface.Interface()
!Load Test object into variant
vExtObj=Log
!Load Test object variant into mscorlib.NetObject
obNetObj=vExtObj
!Send Test object to .Net DLL along with new properties
obNetInterface.ATEasyLogClear(obNetObj)
}
For the second test, the TestResult is set to 42 and the Min/Max bounds have been set to 0 and 10. The call to ATEasyTestSetMinMax will return the Max/Min bounds to 40 and 50 and will cause this test to PASS.
Test 1.2 : "Set Properties"
--------------------------------------------------------------------------------
Id = Set_Properties
Type = MinMax
Min = 0
Max = 10
{
!Set TestResult outside of the bound of the test so the test will fail if the Min/Max aren't changed
TestResult=42
!Create instance of .NET class
obNetInterface=new ATEasyNetInterface.Interface()
!Load Test object into variant
vExtObj=Test
!Load Test object variant into mscorlib.NetObject
obNetObj=vExtObj
!Send Test object to .Net DLL along with new properties
obNetInterface.ATEasyTestSetMinMax(obNetObj, 40, 45)
}
The third test demonstrates the use of ATEasyTaskGetTestCount to retrieve a property of an ATEasy object.
Test 1.3 : "Get Property"
--------------------------------------------------------------------------------
Id = Get_Property
Type = Precise
Value = 3
{
!Create instance of .NET class
obNetInterface=new ATEasyNetInterface.Interface()
!Load Test object into variant
vExtObj=Task
!Load Test object variant into mscorlib.NetObject
obNetObj=vExtObj
!Send Test object to .Net DLL along with new properties
obNetInterface.ATEasyTaskGetTestCount(obNetObj, lTestCount)
TestResult=lTestCount
}
Applications
- Integration of ATEasy and a scripting language.
- Passing ATEasy objects out to be parsed externally.
Downloads
VS2005 C++ Project
ATEasy Test Workspace for C++ DLL
VS2010 C# Project
ATEasy Test Workspace for C# Assembly