dotNet + MXS


#561

+1 for everything Tim said. Spot on!


#562

Great!
Everything is working now, thank you very much.


#563

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?


#564

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)

#565

Depending on how you initialized the .dll, you should be able to do a

gc()

call to clear max’s hold on the file.


#566

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 ?


#567

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.
See http://forums.cgsociety.org/showthread.php?t=997858
and more specifically: http://forums.cgsociety.org/showpost.php?p=6864094&postcount=480


#568

There is no way to unload a .NET assembly without tearing down the entire AppDomain, this is not even a limitation of 3dsmax.


#569

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.


#570

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 :wink: ). 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.

-k.


#571

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


#572

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[1])
	
	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[1])
		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
)


#573

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")

#574

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)
)

#575

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.


#576

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.


#577

Not to mention it has to parse the string and find the correct namespace to even find the class for each call.


#578

help…

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
)

)

createdialog aa


#579

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?


#580

I thought I’d post this here.

If you code your own C# dlls, and are frustrated by the need to restart Max in order to update changes to your C#, I just wrote a little tool for more dynamic dll management, with help from a few around here.

dllManager.ms is posted on my code page