[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
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.
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
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
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