+1 for everything Tim said. Spot on!
Everything is working now, thank you very much.
I’m Just starting out my C# / DotNet exploration.
I found this introductory tutorial on creating C# classes in visual studio and loading them up in MXS. While toying with it, noticed that, once my dotNet assembly is load via max script, I can’t modify and save the visual studio project, because windows thinks the .dll file is “in use” …The only way I could get Max to “let go” was to close it. This makes iteration more difficult.
How can I force max to “let go” of a dotNet Assembly or object?
One trick I always use is to not load the assembly from file. Instead, read the file to memory and load the assembly using the raw bytes:
(dotnetClass "System.Reflection.Assembly").Load ((dotnetClass "System.IO.File").ReadAllBytes filename)
Depending on how you initialized the .dll, you should be able to do a
call to clear max’s hold on the file.
thanks for your response.
I’m using dotNet.LoadAssembly to load my .dll.
foo=dotNet.LoadAssembly @"C:\path o\my est.dll" >>dotNetObject:System.Reflection.RuntimeAssembly foo >>dotNetObject:System.Reflection.RuntimeAssembly foo=undefined >>undefined foo >>undefined gc() >>2170600L
gc() returns the number of bytes free in the MAXScript heap , but doesn’t seem to “let go” of my .dll as far as Visual Studio is concerned. I still get the same error in visual studio:
Error 1 Unable to copy file "obj\Release est.dll" to "bin\Release est.dll". The process cannot access the file 'bin\Release est.dll' because it is being used by another process.
is there no command like dotNet.UnloadAssembly ?
There is not.
I haven’t done any work with them in a while but thought that the garbage collection might release them based on your approach.
I did a bit of searching and found that you need to manually load and unload the dll.
and more specifically: http://forums.cgsociety.org/showpost.php?p=6864094&postcount=480
There is no way to unload a .NET assembly without tearing down the entire AppDomain, this is not even a limitation of 3dsmax.
I looks like useful stuff to know:
how to use C# to define .net custom control,
pass events to MXS
Pass variable from MXS to the .net control…
I’ve been following the examples in that article and trying to get them to work, it would be cool if I could get it working, but I can’t, and am too new to C# to identify exactly how to fix the errors… Their C# code seems flawed, with some vital elements missing.
Does anybody know if a working example / tutorial on this?
I speak not of loading the existing .net stuff into mxs
but a demonstration of coding custom c# objects and controls for use in Max.
Sorry, that I have to interrupt here, but I have a question might preaching to the converted…
Why is dotNet in MaxScript so slow?
Of course for my current purpose it is still faster than Maxscript itself, but I’ve recognized that the more .Net objects I call from MaxScript the longer the execution time is.
For example I created a .Net-List in Maxscript and added Objects to the list (also in Maxscript) it took me around 27 seconds to do that for 100k objects (yes, I’m doing something with points here ). It was still faster than Maxscript only, which took 177 seconds, hurray!
Buuuut, when I moved this list-adding-thing to an assembly in .Net, so that I’ve only had to call an adding function in MaxScript which would add the Max-data types itself to a list that is situated in the dotNet object, it took me only 8 seconds.
The funny thing is, that it also worked, when I’ve exported that data set into a textfile and parsed it in .Net, this took 9 seconds.
So why is it like that, is it because of the Maxscript-.Net-Wrapper or of the nature of .Net being integrated in other scripting languages?
I’d be interested in that because it would dramatically affect (at least my) way of programming with Max and C# in the future.
i’m sure you are doing something wrong. there should be so big difference. do you use dotnetcontrol or .net form control?
what kind of data do pass to the control? maxscript is much slower creates .net objects than .net assembly (which is compiled code). it makes a difference
Please enlight me, Mr. Trofimov
I’ve posted the code, here, yes it will not work, because you’re missing the Dlls but that is the difference between the implemention of the mentioned differently fast methods.
-- Slooooooooowwww... function collectAwGeometryData = ( local snapmesh = (snapshotasMesh selection) local genericType = dotNet.getType "System.Collections.Generic.List`1" local innerType = dotNet.getType "AutoweightClassLib.Vertex" local specificType = genericType.MakeGenericType #(innerType) local awpntlist = (dotNetClass "System.Activator").CreateInstance specificType -- created a dotNet: List<Vertex>() for lvi = 1 to (getNumVerts snapmesh) do ( local pnt = (getVert snapmesh lvi) -- add the dotnet Vertex Object to the created Vertex List in Max Script -- (dotNetObject"System.Windows.Media.Media3D.Vector3D" pnt.X pnt.Y pnt.Z) Having these values as a DotNet Datatype even slows down Maxscript -- with that data type it takes 27 seconds, without it, passing only max-data-types (double, double, double) it takes 21 seconds local awvert = dotNetObject "AutoweightClassLib.Vertex" (lvi-1) (dotNetObject"System.Windows.Media.Media3D.Vector3D" pnt.X pnt.Y pnt.Z) -- add the dotnet Vertex-Object to the dotNet Vertex-List via MaxScript awpntlist.Add awvert ) ) -- Fst... ( function collectAwGeometryData &calcobj = ( local snapmesh = (snapshotasMesh selection) pntamount = (getNumVerts snapmesh) for lvi = 1 to pntamount do ( local pnt = (getVert snapmesh lvi) -- only pass native Max values as parameters to a function that adds a listvalue to the existing list in the calcobj. calcobj.addVertexValueToVertList (lvi-1) pnt.X pnt.Y pnt.Z ) delete snapmesh pntamount ) -- create a simple class instance containing an empty List<Vertex> where we will add points local calculationObj = dotNetObject "AutoweightClassLib.EuclideanDistance" local pntamount = collectAwGeometryData &calculationObj )
i think this part makes everything slow
local awvert = dotNetObject "AutoweightClassLib.Vertex" (lvi-1) (dotNetObject"System.Windows.Media.Media3D.Vector3D" pnt.X pnt.Y pnt.Z) awpntlist.Add awvert
i would move this part to the assembly... so you do everything right.
it might be faster in mxs if do it different way… create the class first, and create objects using this class instead of class name. like:
c = dotnetclass "ListViewItem" for k=1 to 1000 do (dotnetobject c) -- instead of for k=1 to 1000 do (dotnetobject "ListViewItem")
this is what i’m talking about:
( num = 1000 t1 = timestamp() m1 = heapfree c = dotnetclass "ListViewItem" for k=1 to num do (dotnetobject c) format "using class >> time:% memory:% " (timestamp() - t1) (m1 - heapfree) t1 = timestamp() m1 = heapfree for k=1 to num do (dotnetobject "ListViewItem") format "using name >> time:% memory:% " (timestamp() - t1) (m1 - heapfree) )
Ahhhh I see… that’s the strange thing about creating a Class instance at a variable and call the variable instead of the class itself. I’ve never liked that about MaxScript, but I can totally see your point. Thanks Denis.
when you create a dotnet object using name, max doesn’t know if the class was or not already created. and it creates the class instance first and the object next.
Not to mention it has to parse the string and find the correct namespace to even find the class for each call.
rollout aa “l”(
dotNetControl tv “System.Windows.Forms.ListView” pos:[2,2] width:100 height:100
dotNetControl iltv “System.Windows.Forms.ImageList+ImageCollection” pos:[0,0] width:0 height:0
fn fillInTreeView tv iltv theFileName=
ilTv = dotNetObject “System.Windows.Forms.ImageList”
ilTv.imageSize = dotNetObject “System.Drawing.Size” 15 15
theFileName = getfiles (getFilenamePath (getSourceFileName()) + "\aa\*.jpg") img = dotNetClass "System.Drawing.Image" ilTv.images.add (img.fromFile theFileName) tv.images = iltv for c in _files do undo on ( theRoot = tv.Nodes.add() theRoot.image=finditem theFileName c theRoot.text=getfilenamefile c )
on aa open do
fillInTreeView tv ilTv theFileName
probably you copied and pasted this code from somewhere with complete misunderstanding what it’s doing. usually things don’t work this way.
first of all… what do you want to use - TreeView or ListView?