PDA

View Full Version : MaxScript DotNet integration


listener
11-12-2010, 02:07 PM
I have used C# for developing software, since recently started with max projects...

I have a problem if i create custom user control, for a test i just made simple button

--loaded dotNet.loadAssembly my control as dll

then
--Made the dotNetObject control
btn = dotNetObject "DotNetMaxTest.testing"
--Made the form
frm = dotNetObject "MaxCustomControls.MaxForm"
--Allso tried with System.Windows.Forms.Form
--Then Added the button
frm.controls.Add btn
--Made event handler function
function bp =
(
print "Button is pressed"
)
--Linked the event handler
dotNet.addEventHandler btn "click" bp
--Set lifetime so that eventhandler dont go out with trash
dotNet.setLifetimeControl btn #dotnet
--And finally displayed the form
frm.show()

And i get my event handler triggered nicely but just under the button, where actually is gray area when i created custom button control... so when i click on button nothing happens but if i click right next to a button event gets triggered... can anyone please help me a little bit with this. Somenthing got lost in translation because of unawareness of c# that MaxScript exists or somenthing like that....

I hope this was clear enough explanation.

JHN
11-12-2010, 03:09 PM
Looks like you're doing things right, have you tried the same code but with a regular dn button?

-Johan

listener
11-12-2010, 03:23 PM
If you think using somenthing like

btn = dotNetObject "System.Windows.Controls.Button"

I did and if i attach event handler to it it works just fine...

if i understood you correctly.

But the problem is i want to do a custom controll... so i do dotNet.loadAssembly of my custom control dll. And using it like that i get problem from my initial post.

JHN
11-12-2010, 04:01 PM
I understand, why I was asking is that we now know the problem is in the assembly. I have made custom .net tools too and many others here, so my guess is it's in the assembly. Have you overwritten the button handler from the custom control, is it exposed as public etc? Many thing can be the problem.

-Johan

listener
11-12-2010, 04:54 PM
I understaind... I have not changed button control in any way. I used the default one just added it as custom control as a test because im planning to make ui for my max scripts. Basicaly i just draged and droped button as custom control then compiled it as dll and tried to use it in max.

JHN
11-12-2010, 07:23 PM
Then the problem is quite simple. You have assigned the click handler to the base of the control. Not the button of the control. You should have overriden the click handler of the base to bypass it through to the button control in the custom control.have created. Or you create a new eventhandler and patch it though to the button. And a third way is to create the eventhandlers in the dotnet control and use the ManagedServices.dll MaxSDK class to execute maxscript code via the control.

Hope this helps,
-Johan

LoneRobot
11-13-2010, 09:29 PM
I think you are bang on with this Johan. In my controls I always pass the event on a composite control to a new user control level event with a custom eventarg class as I can explicitly control the data that is getting passed to max.

denisT
11-13-2010, 10:38 PM
...In my controls I always pass the event on a composite control to a new user control level event with a custom eventarg class as I can explicitly control the data that is getting passed to max.

it's too long English. Could you break it for not natives please? :)

listener
11-15-2010, 08:43 AM
Could you give a small example for a simple button like im trying to do,

The thing i dont understaind is:

if i call event handler for a button in maxscript.. like this:

function bp =
(
print "Button is pressed"
)

dotNet.addEventHandler btn "click" bp
dotNet.setLifetimeControl btn #dotnet

how does it relates with event handler i made in C# or does it relate at all...


EDIT: I have managed to get it to work with

Managed.Services.MaxscriptSDK.ExecuteMaxscriptCommand();

wich is good, but the problem with eventhandler thats created in maxscript still remains...

JHN
11-15-2010, 09:24 AM
The problem is that when you add a custom control in max, you're assigning every event handler to the base of that control. So in visual studio, you should have overriden the click event handler so that it invokes the button and not the control base, spend some time on the internet to read about custom controls. This is not a max problem it's a problem you have with creating a flawed usercontrol. This same problem you have here, would be the same as if you'd use your custom control in some dotnet application.

-Johan

listener
11-15-2010, 09:52 AM
Thank you JHN, i understood the problem tested it in windows forms application same thing like you sead, off to make custom event handler thx again.

LoneRobot
11-15-2010, 11:25 PM
it's too long English. Could you break it for not natives please? :)

Ha Ha, what's a little missed punctuation between friends? :cool:

Sounds like you are on the right track now, Dejan. If you wanted some more info about inheriting the eventarg class within a user control, I wrote an article about this exact thing a while back, and I promise it has a few shorter sentences than my first offering. :)

http://lonerobot.net/?p=411

listener
11-19-2010, 08:32 AM
Thank you Peter, i figured there are alot of ways to make custom controls... I was thinking about creating most of my project in c# and use

ManagedServices.MaxscriptSDK.ExecuteMaxscriptCommand()

to pass anything i need to maxscript and use execute query... for communication with dotnet...

Is this something that is recommended or its better to do all in maxscript and dotnet just for controls.

LoneRobot
11-19-2010, 11:44 AM
Hi Dejan,

I think that's a good approach. Because my tools generally are set up for a specific task, more that I can hardcode into the class library the better. I use the managedservices.dll methods quite a lot!
It really depends on how complicated the maxscript call is. I have converted maxscript code into 'dotnet friendly' code and registered the function via the usercontrol's new constructor. It's sometimes fiddly to figure out, you just need to insert any variables into the overall string and remember that you'll have to insert a special string character to make a string in a dotnet toMXS transfer. this is because managedservices can only pass a string.

I have a class that I have written that allows me to format code to the listener from the assembly, it helps checking the code going into max is as it should be. Let me know if you can use it and i'll post it when I get home.

There are also a couple of other posts on my blog that talk about managedservices and how you can use them in a max-centric dotnet usercontrol. There's a lot of tips and tricks I've picked up over the last couple of years writing custom controls for max.

JHN
11-19-2010, 04:44 PM
Hey Pete, how would you handle bigger functions like collect all scene materials, the objects they are attached to and their texturemaps. Now I have a maxscript function that collects it nicely for me in manageable structs that mostly use animHandles/IntPtr values (getHandleByAnim).
Now I have in my managed tool a class that mimics the struct, now I'm thinking about passing the struct to dotnet via a method, so that dotnet has representation of my scene materials in managed code and not just strings. I want to use the IntPtr values to communicate. What do you think, does it make sense?
In dotnet I only have some small utility maxscript functions to get data from a specific handle, but the bulk functions I rather leave in maxscript for now, for easier debugging...

There's just so many ways to approach this communication.

Found a nice imageprocessing library btw, free image (http://freeimage.sourceforge.net/sourcecode.html). Reads loads of formats, only 32bits though, afaik.

-Johan

LoneRobot
11-19-2010, 05:18 PM
Hi Johan,

That's a good question, - my initial thoughs are that you are going to have to store an instance of the usercontrol in a global in max -perhaps when the script is run for the first time. Having a dotnet version of a struct is a good approach too, you can construct a class that contains properties for all the value types that you wish to store from max (although with nodes you would be limited to their names, not very robust I know but all I can think of currently) You can then use the script that is registered from your assembly to construct your struct class and feed that back into the usercontrol global variable. You could construct a method to handle this exact case. At the moment im thinking you cant pass anything that isnt a value type like string, boolean, image etc so for something more max-centric you would have to construct a class that stored the elements that make up a particular material. My approach might be a little simplistic, im sure the proper dotnet wizards on here could think of a better way.


Found a nice imageprocessing library btw, free image (http://freeimage.sourceforge.net/sourcecode.html). Reads loads of formats, only 32bits though, afaik.
-Johan

I have used that, it is good although the 64bit limitation stopped me from using it. there is a wrapper called AIL that uses freeimage, and is great to use in a managed environment.

JHN
11-19-2010, 07:44 PM
Hi Johan,

That's a good question, - my initial thoughs are that you are going to have to store an instance of the usercontrol in a global in max -perhaps when the script is run for the first time. Having a dotnet version of a struct is a good approach too, you can construct a class that contains properties for all the value types that you wish to store from max (although with nodes you would be limited to their names, not very robust I know but all I can think of currently)
That's where I was thinking of

handle = getHandleByAnim $
IntPtr = dotnet.ValueToDotNetObject handle (dotNetClass "System.IntPtr")
IntPtr.ToString()


And for arrays

handle = for o in selection collect getHandleByAnim o
IntPtrArr = dotNetObject "System.IntPtr[]" handle.count
for i = 0 to handle.count - 1 do IntPtrArr.Set i (dotNetObject "System.IntPtr" handle[i + 1])

print (IntPtrArr.Get 1)

The IntPtr's can be fed to a custom dotnet class easily and you have a nice reference to your scene with the handles.


I have used that, it is good although the 64bit limitation stopped me from using it. there is a wrapper called AIL that uses freeimage, and is great to use in a managed environment.
What do you use now then? Something you cooked up yourself, cause my first tests with creating thumbnails on the fly didn't go very fast.

-Johan

LoneRobot
11-19-2010, 10:30 PM
Cool, i get it. I hadn't seen the getanimbyhandle/GetHandleByAnim methods before. My question is, that obviously works fine on something like a teapot, but what if the object that you want doesn't have a handle? :) sorry, I couldn't resist it.

I'm assuming that the handle is different each time you open it in a max session, so if you wanted to store something like a rig, you are still stuck with using the name to grab the handle for the node in that session? I will definitely look into this now, it's an interesting approach you've come up with. thanks!

What do you use now then? Something you cooked up yourself, cause my first tests with creating thumbnails on the fly didn't go very fast.

I use GDI+ and Max's built in Image classes in HitchHiker. The dotnet image classes can be cached with a backgroundworker and things like tga and rpf via 3dsmax. There is a cache mode on the latest release, the thumbs are stored locally now, it means it at least has the appearance of being fast after the first run!

JHN
11-19-2010, 10:57 PM
Cool, i get it. I hadn't seen the getanimbyhandle/GetHandleByAnim methods before. My question is, that obviously works fine on something like a teapot, but what if the object that you want doesn't have a handle? :) sorry, I couldn't resist it.

You mean people use something else then teapots in max?!

I'm assuming that the handle is different each time you open it in a max session, so if you wanted to store something like a rig, you are still stuck with using the name to grab the handle for the node in that session? I will definitely look into this now, it's an interesting approach you've come up with. thanks!

The handle should stick over a file, but not over a merge. So it's not so solid for that, CA's should be better suited for that. I'm using it on tools that have to alter the current scene properties. And you can get handles from almost anything, not just nodes. getHandleByAnim scenematerials


I use GDI+ and Max's built in Image classes in HitchHiker. The dotnet image classes can be cached with a backgroundworker and things like tga and rpf via 3dsmax. There is a cache mode on the latest release, the thumbs are stored locally now, it means it at least has the appearance of being fast after the first run!
Alright interesting, but I'm sticking with freeimage for now as the tool I'm building now is not for use in max, and it comes with a proper dotnet wrapper on it's own.

Cheers,
-Johan

LoneRobot
11-19-2010, 11:11 PM
The handle should stick over a file, but not over a merge. So it's not so solid for that, CA's should be better suited for that. I'm using it on tools that have to alter the current scene properties. And you can get handles from almost anything, not just nodes.

I just tried this on a teapot (naturally) with hold/fetch. Each time i fetched and called
GetHandleByAnim $ it returned a different number. So i guess the handle is different each time or am I missing something?

I can still see there would be masses of applications for your approach! thanks again johan.

Alright interesting, but I'm sticking with freeimage for now as the tool I'm building now is not for use in max, and it comes with a proper dotnet wrapper on it's own.

:eek: not for use in max??? consider yeeself BANNISHED! :p

JHN
11-20-2010, 12:18 AM
I just tried this on a teapot (naturally) with hold/fetch. Each time i fetched and called
GetHandleByAnim $ it returned a different number. So i guess the handle is different each time or am I missing something?

You're right indeed, it should only be used on "sessions" it seems, I thought it was a bit more robust, ohwell.


I can still see there would be masses of applications for your approach! thanks again johan.

Wish I could take full credit, but I also read it somewhere on this forum, probably from Bobo or Denis.

:eek: not for use in max??? consider yeeself BANNISHED! :p
Project wrapping tools span more than max (unfortunatly!), lets say you want to semi automatically wrap(archive) a project and generate some nice JPG's and some other statistics along the way. I love this sort of things!

Cheers,
-Johan

LoneRobot
11-20-2010, 10:38 AM
Sounds like I am writing a very similar tool to you at the moment - it's a stand alone .net application that scans through our entire project and generates XML data files according to a set XML schema. Its so the project the can be added to a huge asset database. I'm glad i looked into LINQ a while ago, as it's proving really useful. I couldn't believe it when they told me that previously someone entered the data into excel manually for EVERY project asset and generated the xml from there!

So i guess we are married to max but there are many software mistresses these days.. :)

JHN
11-20-2010, 02:33 PM
Sounds like I am writing a very similar tool to you at the moment - it's a stand alone .net application that scans through our entire project and generates XML data files according to a set XML schema. Its so the project the can be added to a huge asset database. I'm glad i looked into LINQ a while ago, as it's proving really useful. I couldn't believe it when they told me that previously someone entered the data into excel manually for EVERY project asset and generated the xml from there!

That's step two for me to, now we don't have an asset database, just some big elephant brains. The wrapping I'm doing now is for rendered/comped footage.

So i guess we are married to max but there are many software mistresses these days.. :)
Python and Qt are flirting with me too, but I have not given in, yet.

:)

-Johan

denisT
11-20-2010, 03:38 PM
Python and Qt are flirting with me too...


don't flatter yourself. they are doing it for anyone.

JHN
11-20-2010, 07:01 PM
don't flatter yourself. they are doing it for anyone.
:)
I know, I saw a friend of mine doing c++ and Qt, made me jealous, nice UI controls!

-Johan

listener
11-22-2010, 03:32 PM
Thank you Peter if you can post your class im sure it will come handy...

Max and dotnet are communicating quite nicely now... i have developed couple of custom controls and its going fine...
Im using node names to store data in dotnet and when i do anything i do it from dotnet so basically maxscript is just for building skeleton of app and executing what i tell it from dotnet and for now this gives me a lot more flexibility.

Havent tried using pointers but i will look in to it sounds quite interesting JHN.

It would be so nice if they can integrate dotnet even more so we can pass different kind of data, im hoping they are getting to it because it would be much nicer to develop plugins using some of dotnet language suite.

CGTalk Moderation
11-22-2010, 03:32 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.