Difference between revisions of "COM Integration"
(Created page with "''This page describes a proposed feature that does not yet exist in Analytica or ADE (as of release 4.4). We make it available to encourage you and other users to review it and ...") |
|||
Line 34: | Line 34: | ||
* 64-bit objects can only be used when you are running Windows 64-bit. | * 64-bit objects can only be used when you are running Windows 64-bit. | ||
* When neither «force64bit» nor «force32bit» are specified, it defaults to the same bitness as the calling process when both are available. | * When neither «force64bit» nor «force32bit» are specified, it defaults to the same bitness as the calling process when both are available. | ||
+ | |||
+ | == Other considerations == | ||
+ | |||
+ | === Security === | ||
+ | |||
+ | TBD. The user should be given control over whether COM objects are allowed to run, so that if you receive a model from someone else, it can't inflict arbitrary damage. Also, there should be restrictions on the ACP server as to what objects are allowed to run, and who can configure this. | ||
+ | |||
+ | === Run As Impersonation === | ||
+ | |||
+ | TBD. It is possible to run out-of-process COM objects under a different identity. This can be configured in DCOMCNFG, but some parameters would need to be added to make controllable by the model. Need to design... | ||
+ | |||
+ | === Error Handling === | ||
+ | |||
+ | TBD. Obviously, failure to instantiate an object can result in an error that terminates computation. Should we allow a soft-failure variation, so you could "test" whether it is going to succeed and do/try something else if it doesn't? | ||
+ | |||
+ | = CallCOMMethod(«object»,methodName'',param1,param2,param3,...,resultIndex:I,J,...'') = | ||
+ | |||
+ | This calls a method (or property) of a COM object that has already been instantiated using [[CreateCOMObject]] (or [[SpreadsheetOpen]]). The return value is the value returned by the method. | ||
+ | |||
+ | Methods can only be invoked for «object»s that implement the <code>IDispatch</code> interface. | ||
+ | |||
+ | Example | ||
+ | <pre> | ||
+ | var ade := CreateCOMObject("ADE4.CAEngine"); | ||
+ | CallCOMMethod(ade,"SendCommand","news"); | ||
+ | CallCOMMethod(ade,"OutputBuffer") | ||
+ | </pre> | ||
+ | |||
+ | In the above example, the <code>SendCommand</code> method is invoked with the parameter "news". Its return value is ignored. Then the <code>OutputBuffer</code> property is accessed, and its value is returned. | ||
+ | |||
+ | == Array-valued results == | ||
+ | |||
+ | When a method returns an array (known as a SafeArray in COM lingo), the dimensions of that array need to be mapped to Analytica indexes. If you do not specify the «resultIndex» parameter, the function creates local indexes with the names <code>.dim1</code>, <code>.dim2</code>, etc. Alternatively, you can specify the indexes to use for the result via the «resultIndex» parameter. If your result index does not match the length of the corresponding dimension of the array that is returned, the array is truncated (when your index is too short) or result is padded with [[Null]]s (if your index is too long). If you specify too many indexes (i.e., you provide 3 indexes but the result is only 2-D), the extra indexes are ignored. If you don't specify enough indexes, then local indexes are created as before. | ||
+ | |||
+ | == Array-valued parameters == | ||
+ | |||
+ | When you pass Analytica arrays as parameters, the call is iterated (invoked multiple times) for each atomic combination of parameters, and the results from each call are collected. Also, if the «object» parameter is array valued (an array of objects), the call is iterated, calling the method for each object. Hence, array-abstraction extends to COM method calls. | ||
+ | |||
+ | When a method expects an array-valued parameter, you must package it using the <code>ToForeignArray</code> function, which specifies which indexes are consumed along with the order of the indexes for 2-D or greater arrays. Any indexes that are not included within the <code>ToForeignArray</code> call are iterated over. | ||
+ | |||
+ | Example | ||
+ | :<code>CallCOMObject( mathObj, "PrincipleEigenVector", ToForeignArray(A,I,J), resultIndex: I )</code> | ||
+ | |||
+ | == Pass-by Value = | ||
+ | |||
+ | All parameters are passed-by-value. The option to pass-by-reference is not available. This limits the methods that can be called to those without pass-by-reference parameters (a.k.a., "out" parameters). | ||
+ | |||
+ | == Data Types == | ||
+ | |||
+ | Parameters are passed as COM VARIANTs. COM Objects themselves can be passed as parameters and result values can return COM objects. Hence, it is possible to have methods that return a new COM object, and then that object can be used as the first parameter in a call to CallCOMObject. | ||
+ | |||
+ | == The Invoke Method operator == | ||
+ | |||
+ | A new <code>-></code> operator provides a syntactic convenience for CallCOMObject. The use of the operator looks like this: | ||
+ | |||
+ | :<code>obj->method(param1,param2,..)</code> | ||
+ | |||
+ | == Names parameters == | ||
+ | |||
+ | TBD: The COM Automation specification has a concept of named parameters. I've not yet worked this into the spec. | ||
+ | |||
+ | == Set Properties == | ||
+ | |||
+ | TBD: When an object has a get/set property, what change or special consideration is necessary to handle that? Research. |
Revision as of 19:43, 5 December 2012
This page describes a proposed feature that does not yet exist in Analytica or ADE (as of release 4.4). We make it available to encourage you and other users to review it and to make comments before we implement the feature(s).
Requires Analytica Enterprise, Optimizer or ADE.
The Microsoft Component Object Model (COM) provides a framework for interprocess communication within the Windows operating system. The features described here allow your model to call other applications that expose a COM automation interface (known as the IDispatch
interface). You can write your own COM servers in C++, C#, VB, and a host of other languages, and then call them, or you can use existing interfaces to call applications from other vendors.
The features here allow your Analytica model to call other applications. This is different from having other applications call your Analytica model. The latter is what ADE provides.
CreateCOMObject(name,server,inProcess,outOfProcess,force64bit,force32bit,flags)
The first step when using COM is to instantiate a COM object, which is done using the function 'CreateCOMObject (note: You can also obtain an Excel::_Workbook object using SpreadsheetOpen, which can be used as a COM object). Only the first parameter is required, and it is rare that you would need to worry about the remaining parameters.
Parameters:
- «name» : The textual name of the COM class being instantiated. This can be a name such as "WScript.Shell" or "ADE4.CAEngine", or it can be a clsid such as "clsid:72C24DD5-D70A-438B-8A42-98424B88AFB8".
- «server»: (optional text) The name of the computer where the object will run. Allows remote invocation, or can be "localhost".
- «inProcess»: (optional boolean) Specifies whether in-process invocation is allowed.
- «outOfProcess»: (optional boolean) Specifies whether out-process invocation is allowed.
- «force64bit»: (optional boolean) Specifies that the 64-bit version of the server should be used, even if you are running Analytica 32-bit.
- «force64bit»: (optional boolean) Specifies that the 64-bit version of the server should be used.
- «flags»: (optional integer bitfield). Additional esoteric flags (see the CLSCTX enumeration in Microsoft documentation).
- TBD: Parameters for account to run under.
In most cases, the instantiated object runs on the same machine as the Analytica calling process, however, remote invocation is possible, known as DCOM. When the «server» parameter is not specified, the target computer is determined by the DCOMCNFG settings for that component. By running the DCOMCNFG program, or entering "DCOM Config" in the Microsoft Component Services, you can configure specific COM components to run on specific remote servers. The «server» parameter overrides that setting. The COM component will usually need to be installed on both machines.
The programs that implement COM objects can either run in-process or out-of-process and can be 32-bit or 64-bit programs. Some COM servers provide both in-process and out-of-process versions and some provide both 32-bit and 64-bit versions. If you don't specify any of the optional flags («inProcess», «outOfProcess», «force64bit» or «force32bit»), it will allow any possible combination that it finds to run. You can use these flags to force a specific type to run. For example:
CreateComObject("MyObject", outOfProcess:true, force64bit:true )
would force the creation of a MyObject
in an out-of-process 64-bit server, whereas without the flags it might have created an in-process 32-bit instance. Some COM servers provide only one type. For example, ABODB classes can only be used in-process.
Not all combinations of flags are valid. Here are some basic constraints:
- Any remote invocation (on a different machine) is automatically out-of-process.
- Any in-process invocation must have the same bitness (32-bit or 64-bit) as the Analytica or ADE program you are using. (Out-of-process bitness can differ).
- 64-bit objects can only be used when you are running Windows 64-bit.
- When neither «force64bit» nor «force32bit» are specified, it defaults to the same bitness as the calling process when both are available.
Other considerations
Security
TBD. The user should be given control over whether COM objects are allowed to run, so that if you receive a model from someone else, it can't inflict arbitrary damage. Also, there should be restrictions on the ACP server as to what objects are allowed to run, and who can configure this.
Run As Impersonation
TBD. It is possible to run out-of-process COM objects under a different identity. This can be configured in DCOMCNFG, but some parameters would need to be added to make controllable by the model. Need to design...
Error Handling
TBD. Obviously, failure to instantiate an object can result in an error that terminates computation. Should we allow a soft-failure variation, so you could "test" whether it is going to succeed and do/try something else if it doesn't?
CallCOMMethod(«object»,methodName,param1,param2,param3,...,resultIndex:I,J,...)
This calls a method (or property) of a COM object that has already been instantiated using CreateCOMObject (or SpreadsheetOpen). The return value is the value returned by the method.
Methods can only be invoked for «object»s that implement the IDispatch
interface.
Example
var ade := CreateCOMObject("ADE4.CAEngine"); CallCOMMethod(ade,"SendCommand","news"); CallCOMMethod(ade,"OutputBuffer")
In the above example, the SendCommand
method is invoked with the parameter "news". Its return value is ignored. Then the OutputBuffer
property is accessed, and its value is returned.
Array-valued results
When a method returns an array (known as a SafeArray in COM lingo), the dimensions of that array need to be mapped to Analytica indexes. If you do not specify the «resultIndex» parameter, the function creates local indexes with the names .dim1
, .dim2
, etc. Alternatively, you can specify the indexes to use for the result via the «resultIndex» parameter. If your result index does not match the length of the corresponding dimension of the array that is returned, the array is truncated (when your index is too short) or result is padded with Nulls (if your index is too long). If you specify too many indexes (i.e., you provide 3 indexes but the result is only 2-D), the extra indexes are ignored. If you don't specify enough indexes, then local indexes are created as before.
Array-valued parameters
When you pass Analytica arrays as parameters, the call is iterated (invoked multiple times) for each atomic combination of parameters, and the results from each call are collected. Also, if the «object» parameter is array valued (an array of objects), the call is iterated, calling the method for each object. Hence, array-abstraction extends to COM method calls.
When a method expects an array-valued parameter, you must package it using the ToForeignArray
function, which specifies which indexes are consumed along with the order of the indexes for 2-D or greater arrays. Any indexes that are not included within the ToForeignArray
call are iterated over.
Example
CallCOMObject( mathObj, "PrincipleEigenVector", ToForeignArray(A,I,J), resultIndex: I )
= Pass-by Value
All parameters are passed-by-value. The option to pass-by-reference is not available. This limits the methods that can be called to those without pass-by-reference parameters (a.k.a., "out" parameters).
Data Types
Parameters are passed as COM VARIANTs. COM Objects themselves can be passed as parameters and result values can return COM objects. Hence, it is possible to have methods that return a new COM object, and then that object can be used as the first parameter in a call to CallCOMObject.
The Invoke Method operator
A new ->
operator provides a syntactic convenience for CallCOMObject. The use of the operator looks like this:
obj->method(param1,param2,..)
Names parameters
TBD: The COM Automation specification has a concept of named parameters. I've not yet worked this into the spec.
Set Properties
TBD: When an object has a get/set property, what change or special consideration is necessary to handle that? Research.
Enable comment auto-refresher