Passing Arrays to a .NET COM object from Visual FoxPro
Assume you have a method in a .NET COM object that looks like this:
[ClassInterface(ClassInterfaceType.AutoDual)]
[ProgId("DotNetCom.DotNetComPublisher")]
public class DotNetComPublisher
public string PassArray(object[] Objects )
{
string Output = "";
foreach(object Customer in Objects)
{
// *** Must access array by using Reflection
Output += ComUtils.GetProperty(Customer,"Name") + " " +
ComUtils.GetProperty(Customer,"Name") + "\r\n";
}
return Output;
}
}
And you want to pass an object like this:
loAddr = CREATEOBJECT("EMPTY")
ADDPROPERTY(loAddr,"Name","Rick Strahl")
ADDPROPERTY(loAddr,"Company","West Wind")
ADDPROPERTY(loAddr,"Date",DATETIME())
loAddr2 = CREATEOBJECT("EMPTY")
ADDPROPERTY(loAddr2,"Name","Rick Strahl")
ADDPROPERTY(loAddr2,"Company","West Wind")
ADDPROPERTY(loAddr2,"Date",DATETIME())
DIMENSION loAddrArray[2]
loAddrArray[1] = loAddr
loAddrArray[2] = loAddr2
To .NET. Your first try likely looks like this:
LOCAL loNet as DotNetCom.DotNetComPublisher
loNet = CREATEOBJECT('DotNetCom.DotNetComPublisher')
? loNet.PassArray(@loAddrArray)
which will fail with Invalid Parameter type.
The key to make this work is to use the COMARRAY() function in VFP to mark the array as 0 based and passed by reference:
LOCAL loNet as DotNetCom.DotNetComPublisher
loNet = CREATEOBJECT('DotNetCom.DotNetComPublisher')
COMARRAY(loNet,10)
? loNet.PassArray(@loAddrArray)
And this works correctly passing the objects to .NET.
To return arrays works as well. Take the following .NET method:
public Customer[] ReturnArray(int Count)
{
Customer[] Customers = new Customer[Count];
for (int x=0; x < Count; x++)
{
Customers[x] = new Customer();
Customers[x].Company = "West Wind " + DateTime.Now.ToString();
Customers[x].oAddress.StreetAddress = DateTime.Now.ToString();
}
return Customers;
}
Which you can retrieve like this in FoxPro:
LOCAL loNet as DotNetCom.DotNetComPublisher
loNet = CREATEOBJECT('DotNetCom.DotNetComPublisher')
loArray =loNet.ReturnArray(3)
lnCount = ALEN(loArray,1)
FOR x=1 TO lnCount
loCust = loArray[x]
? loCust.Company
? loCust.oAddress.StreetAddress
ENDFOR
RETURN
Note that you are not getting the Array object that .NET is returning. There’s no Length property for example, but rather VFP marshals this .NET array to a standard array. Actually .NET returns this array to COM as a COM compatible SafeArray and VFP picks that up and exposes the array as a VFP array object. You won't need to use COMARRAY() on the returned array.
A final option that I like to use in many situations is to not pass arrays as parameter or return types directly, but rather pass objects that contain arrays. The advantage is that you get more control over the data and you have a chance to potentially call COMARRAY() with other marshalling options.
Other Posts you might also like
- Adding minimal OWIN Identity Authentication to an Existing ASP.NET MVC Application
- Resolving Paths To Server Relative Paths in .NET Code
- Map Physical Paths with an HttpContext.MapPath() Extension Method in ASP.NET
- Back to Basics: Rewriting a URL in ASP.NET Core
- Getting the Client IP Address in ASP.NET Core
The Voices of Reason
# re: Passing Arrays to a .NET COM object from Visual FoxPro
http://west-wind.com/weblog/posts/6728.aspx
Arrays are always passed by reference from .NET, but VFP converts the arrays to VFP arrays and it's very difficult to update these arrays and send them back especially if you change the item count of the array.
# re: Passing Arrays to a .NET COM object from Visual FoxPro
Thank you very much for your article.
I wont to make more precise one point:
we cannot return an array to Foxpro if even an element of the array has a Long(Int64) type of data.
<Microsoft.VisualBasic.ComClass(), ProgId("UDFDotNET.FoxPro")> _ Public Class FoxPro ' it returns the array to FoxPro Public Function ReturnArrayObject(ByVal Count As Integer) As Object(,) Dim ReturnedArray(,) As Object ReDim ReturnedArray(Count - 1, 1) For x As Integer = 0 To Count - 1 ReturnedArray(x, 0) = (x + 1) ReturnedArray(x, 1) = CStr(-(x + 1)) Next x Return ReturnedArray End Function ' it returns the array to FoxPro Public Function ReturnArrayString(ByVal Count As Integer) As String(,) Dim ReturnedArray(,) As String ReDim ReturnedArray(Count - 1, 1) For x As Integer = 0 To Count - 1 ReturnedArray(x, 0) = (x + 1).ToString ReturnedArray(x, 1) = -(x + 1).ToString Next x Return ReturnedArray End Function ' it returns the array to FoxPro Public Function ReturnArrayInteger(ByVal Count As Integer) As Integer(,) Dim ReturnedArray(,) As Integer ReDim ReturnedArray(Count - 1, 1) For x As Integer = 0 To Count - 1 ReturnedArray(x, 0) = x + 1 ReturnedArray(x, 1) = -(x + 1) Next x Return ReturnedArray End Function ' The call to the function in Foxro results in the error message, "Function argument value, type, or count is invalid (Error 11)". Public Function ReturnArrayLong(ByVal Count As Integer) As Long() Dim ReturnedArray() As Long ReDim ReturnedArray(Count - 1) For x As Integer = 0 To Count - 1 ReturnedArray(x) = (x + 1) Next x Return ReturnedArray End Function End Class 'FoxPro
loNet = Createobject("UDFDotNET.FoxPro") loArray = loNet.ReturnArrayInteger(3) display memory like loarray loArray = loNet.ReturnArrayString(3) display memory like loarray loArray = loNet.ReturnArrayObject(3) display memory like loarray loArray = loNet.ReturnArrayLong(3) && error !
# re: Passing Arrays to a .NET COM object from Visual FoxPro