C# to Maxscript

Written November 8th, 2008
Categories: Articles, Scripting / Programming
4 comments

I figured I’d do a quick tutorial about something a little more difficult, but still very important. I’m going to take you step-by-step through integrating a maxscript document and a C# class library so that you can access the powerful and robust features of the dotnet framework in the rather limited environment that maxscript provides. This lets you do such powerful things as access databases, grab web-deployed content, and more. It is my opinion that dotnet connectivity is the best thing to ever happen to maxscript.

This tutorial is written for C# users. However, the themes here apply to any language that is part of the common language runtime (CLR) framework. If you chose to use C++, VB, etc. you should still be able to compile a class library that can integrate in much the same way.

Step 1: Make a new class library project in Visual Studio.

New Class Library

New class library creation.

So from the startup screen in visual studio, go ahead and go to File > New > Project.

Select a C# class library. I’m going to name mine “Maxscript Sandbox”.

Name Your Library

Name your library.

Step 2: Write a test class.

Now let’s write a test class for our new class library. In this screenshot I’ve written a very simple class that contains a string you pass on creation. Once the object exists, you can access the name, or you can call a function that provides you with a sentence that includes the name. Simple enough!

Rename the class to TestObject, and fill in the code you see below.

public class TestObject
{
    string Name;
    public TestObject(string thisName)
    {
        Name = thisName;
    }

    public string GetLongName()
    {
        return ("You can call me " + Name + "!");
    }
}
Step 2 Code

Insert some placeholder code.

Step 3: Compile.

From the drop-down along the top bar, change the build mode from Debug to Release. This means that the compiler will optimize the code for fast execution rather than for debugging and trying to find out what the problem is. On that note, I think there exists a way to debug the class from your script. However, it’s outside the scope of this tutorial. If you’re burning to debug, make a console app that wraps your class and tests functionality from there.

Finished Code

Change to "Release" compilation.

Now, hit F6 or go to Build > Build Solution.

Build the solution.

Build the solution to a DLL.

Step 4: Call the new object from Maxscript.

I’ve commented a lot of the code in the next image, but it’s actually a lot shorter than it looks. All you have to do is load the new class library you’ve created, instantiate the object, and then do whatever you want with it.

Notice that I’ve moved the .dll file that resulted from building my class library to somewhere shorter. Normally, your class library would compile to a directory within the project folder you selected when you created the project (like C:/…/Maxscript Sandbox/ Maxscript Sandbox/bin/release/Maxscript Sandbox.dll). I’ve moved that file from that incredibly long directory to something more digestable like C:/Temp/Maxscript Sandbox.dll.

Call code from Maxscript.

Call the library from Maxscript.

dotnet.loadAssembly ("C:\Temp\Maxscript Sandbox.dll")
ThisTestObject = dotNetObject "Maxscript_Sandbox.TestObject" "Burt"
print (ThisTestObject.GetLongName())

When you run this program, and the dll is in the right place, you’ll find that it outputs as though the object was a native max object. However it’s actually running in the dotnet framework. You can read more about creating objects and the syntax surrounding the Maxscript/C# connection in the documentation. This tutorial was just meant to clarify some of the logistical issues surrounding getting it working.

The final output

The final output from the script.

Until next time, happy scripting!

Tick-Based UI Updating in MaxScript

Written May 9th, 2008
Categories: Articles, Scripting / Programming
No Comments »

This is going to make all you computer science buffs cringe, but today I learned a really dirty way of managing 3dsMax UI states in a Maxscript rollout or DotNet form. By hooking up a UI refresher to a timer object, you can have your front-end refresh dozens or hundreds of times per second- probably without a performance hit!

Consider the following script:

global hForm, mCheckbox, thisTimer
(
fn whenCheckboxIsPressed a b =
(
if MCRUtils.IsCreating Box
then (Max Select; try((hForm.controls.item(0)).checked = false) catch())
else Macros.run 26615
)

fn updateUI =
(
try
(
hForm.controls.item(0)).checked = MCRUtils.IsCreating Box
) catch()
)

--Create a DotNet Checkbox
mCheckbox = dotNetObject "System.Windows.Forms.Checkbox"
mCheckbox.appearance = (dotnetClass "System.Windows.Forms.Appearance").Button
mCheckbox.text = "Box Button"
mCheckbox.location = dotNetObject "System.Drawing.Point" 0 0

--Create a DotNet Form
global hForm = dotNetObject "System.Windows.Forms.Form"
hForm.topmost = true
hForm.controls.add mCheckbox --add the Button to the Form

thisTimer = dotNetObject "System.Windows.Forms.Timer"
thisTimer.interval = 10

--Add an Event Handler for the click event:
dotNet.addEventHandler mCheckbox "click" whenCheckboxIsPressed
dotNet.addEventHandler thisTimer "tick" updateUI

hForm.show() --show the Form with the Checkbox
thisTimer.start()
)

First, we declare our important Maxscript variables globally so that they can be accessed anywhere. This is a scoping issue; use this technique to taste.

Then we declare the function for when the checkbox is pressed, and accept the sender and event args in a and b respectively. In this function, we dive into the hForm.controls collection and retrieve the control to set it’s “checked” parameter. We set a Try()Catch() block around it because the timer will continue for a short while after the window is closed. Without this expression, you’ll get an error 100 times per second and you’ll have to restart 3dsMax.

The second function is the UI update. In this case, we just set the “checked” parameter equal to a Boolean expression checking to see if the user is engaged in some activity. In this case, we want to know if the user is creating a box. For more of these cases, read the Macroscripts included in 3dsMax and you can derive all sorts of neat “Is the user doing this” type expressions.

The rest is fairly self explanatory. We just create the checkbox, and assign it the visual characteristics we need. We create the DotNet form and assign the checkbox to it, and then create the timer and give it an interval rate of 10 (that is, 1000/10 or 100x per second).

We then link up the two event handlers to functions we declared earlier (button click and update ui), and create the form.

Ta da! The button walks, talks, and acts like a macroscript button, but it’s actually being controlled by DotNet functionality. This means

  1. More robust visual design for UI items,
  2. More robust code options and possibly faster performance, and
  3. When you use my library some day, you’ll be able to get native macroscripts to work alongside your own snazzy code!
Designed by Alejo "Mr. Bluesummers" Grigera"
©2012 MrBluesummers.com