Notifications
Clear all

[Closed] Help needed with OLE/COM problem

I am trying to connect to an external Windows application using the OLE/COM interface of MAXScript. I can create the OLE object using createOLEOBject() and I can call some of it’s methods that do not have parameters or that only have string parameters.

But when I try to call a method that wants an array of doubles as argument, I always get an error.

The method in question in the COM interface is declared like this (using COM Inspector to find out):

HRESULT PutFullMatrix(BSTR Name, BSTR Workspace, SAFEARRAY(double) pr, SAFEARRAY(double) pi)

And this is what I tried in MAXScript

x = #(1.0d0)
y = #(1.0d0)
ml.putfullmatrix "c" "base" x y

but this causes an error:

-- Runtime error: OLEObject method call failed: 
Error Message 1: Type mismatch.
Error Message 2: Member not found.
method: putfullmatrix()

Next, I tried

x = SafeArrayWrapper #(1.0, 2.0)
y = SafeArrayWrapper #(1.0, 2.0)
ml.putfullmatrix "c" "base" x y

but that gave me the same error.

Any ideas how to get this working?

Thanks a lot in advance!
– MartinB

9 Replies

I think you are sending over 1-D safearrays and it’s looking for 2-D. I don’t have access to Matlab, so I can’t actually check this out.

I found a snippet of VB.NET code that calls PutFullMatrix at http://www.mathworks.com/access/helpdesk/help/techdoc/ref/putfullmatrix.html

Dim MatLab As Object
Dim XReal(5, 5) As Double
Dim XImag(5, 5) As Double
Dim i, j As Integer

For i = 0 To 4
   For j = 0 To 4
   XReal(i, j)  = Rnd * 6
   XImag(i, j) = 0
   Next j
Next i

Set Matlab = CreateObject("matlab.application")
Call MatLab.PutFullMatrix("M", "base", XReal, XImag)

A maxscript equivalent would be something like:



XReal = #()  
XImag = #()  

for i = 1 to 5 do
(
	append XReal #()
	append XImag #()
	for j = 1 to 5 do (
		append XReal[i] (random 0.0 6)
		append XImag[i] 0
	)
)

wrapXReal = SafeArrayWrapper XReal 
wrapXImag = SafeArrayWrapper XImag

Matlab = createOLEObject ("matlab.application")
MatLab.PutFullMatrix "M"  "base"  wrapXReal  wrapXImag 

Of course the createOLEObject fails for me because I don’t have matlab, but I would be interested to know what, if anything, happens when matlab is present.

Thanks Mike!

Unfortunately, our code also gives me an error. Here’s the output:

SafeArrayWrapper #(#(4.59825, 4.48692, 5.19677, 5.80181, 2.25653), #(5.00639, 4.46697, 5.57105, 2.89624, 1.62776), #(0.265116, 1.66368, 2.97845, 5.77104, 4.8289), #(3.6236, 2.24433, 4.04158, 5.18893, 3.35447), #(0.597254, 5.02519, 5.77154, 5.40901, 2.75437))

SafeArrayWrapper #(#(0, 0, 0, 0, 0), #(0, 0, 0, 0, 0), #(0, 0, 0, 0, 0), #(0, 0, 0, 0, 0), #(0, 0, 0, 0, 0))

<OLEObject:matlab.application>

-- Error occurred in anonymous codeblock; filename: C:\Documents and Settings\user\Desktop\; position: 335; line: 18

-- Runtime error: OLEObject method call failed: 
Error Message 1: Type mismatch.
Error Message 2: Member not found.
method: PutFullMatrix()

– MartinB

Any more ideas?

I really would like to use OLE/COM, but so far I have not been able to pass on any array data through OLE.

Am I looking at a limitation of the OLE interface of 3ds Max, a MAXScript bug or just a user error?

Thanks
– MartinB

Have you verified that you can call the OLE object WITHOUT using max at all?

Use python, or VB, or Excel …whatever it takes to make sure that you can call Get/PutFullMatrix matrices without bringing maxscript into it.

Once you know the problem is with MXS, I’d try sending .NET matrices:

xReal = dotnetobject "System.Double[,]" 5 5
xImag = dotnetobject "System.Double[,]" 5 5

for i = 0 to 4 do
(
	for j = 0 to 4 do (
		xReal.set i j (random 0.0 6)
		xImag.set i j 0
	)
)

Matlab = createOLEObject ("matlab.application")
MatLab.PutFullMatrix "M" "base" xReal xImag 

If that doesn’t work (and to be honest, I doubt it will) I’d explore using the “EngMATLib” library found here:
http://www.codeproject.com/KB/dotnet/matlabeng.aspx

Perhaps through it you can access matlab using .NET and not OLE.

1 Reply
(@martinb)
Joined: 11 months ago

Posts: 0

Thanks once more Mike!

Yes. VB can call PutFullMatrix just fine. The example from http://www.mathworks.com/access/helpdesk/help/techdoc/ref/putfullmatrix.html works right out of the box.

Nope, that doesn’t work at all:

-- Error occurred in anonymous codeblock; filename: C:\Documents and Settings\user\Desktop\OLE\; position: 276; line: 13
-- Runtime error: Unsupported arg type in OLE call: dotNetObject:System.Double[,]

method: PutFullMatrix()

Thanks, I have tested that library before and it works indeed very well (the only limitation I have seen so far is that it seems not to be able to get strings from Matlab other than through evaluation (which seem to get truncated or cause buffer overruns at times).

The reason I would like to avoid the dotNet route is that it creates another dependency (files need to be installed, proper Matlab DLLs need to be copied) and I am not sure how dotNet works when mixing 32bit and 64bit applications?

Cheers!
– MartinB

hm. you could write your own shim assembly to do the parameter conversion and fwd the call to matlab.

Starting to grasp at straws. Did you try safe arrays of .NET doubles?

XReal = #()  
XImag = #()  

for i = 1 to 5 do
(
	append XReal #()
	append XImag #()
	for j = 1 to 5 do (
		append XReal[i] (dotnetobject "System.Double" (random 0.0 6))
		append XImag[i] (dotnetobject "System.Double" 0)
	)
)

wrapXReal = SafeArrayWrapper XReal #(0,0)
wrapXImag = SafeArrayWrapper XImag #(0,0)
Matlab = createOLEObject ("matlab.application")
MatLab.PutFullMatrix "M"  "base" wrapXReal wrapXImag
1 Reply
(@martinb)
Joined: 11 months ago

Posts: 0

Thanks man, but again this errors:

-- Runtime error: Attempt to place unsupported value type into OLE SAFEARRAY: dotNetObject:System.Double

I think I am facing a bug in the SafeArrayWrapper code. I just tried to get ten cell values from Excel through OLE and got only undefined’s. Granted, this is the opposite way (reading data back into 3ds Max), but something is fishy with how arrays get converted through OLE I think.

– MartinB

what is the snippet you are using to read a range?

1 Reply
(@martinb)
Joined: 11 months ago

Posts: 0

Run this code on a machine that has Microsoft Excel installed:

-- create Excel sheet through OLE
x = createOLEObject "Excel.Sheet"
Sheet = x.ActiveSheet
CellA1 = Sheet.Range("A1:A10")
-- set all ten cells to 50.0
CellA1.Value = 50.0
-- now read back the values of those ten cells
q = CellA1.value
-- Variable q contains a SafeArrayWrapper filled with 'undefined' values.

– MartinB