Execute MaxScript from C# Advice


#1

I’ve worked with 3ds Max for a few years now but am very new to MaxScript and any automation and would be greatful for some advice.

All I’m trying to do is automate opening a max file, assigning an image to a material then rendering it. After looking into to it for quite a while I figured it would be the best solution to create this in C# and execute maxscript using ManagedServices.MaxscriptSDK.ExecuteMaxscriptCommand() (although I’m open to ideas if there’s a better solution) then package it up as an exe and run it standalone.

Heres the code I’ve been trying to get working

using System;
using Autodesk.Max;
using ManagedServices;

namespace ManagedServicesTest
{
    class Program
    {
        static void Main(string[] args)
        {
            ManagedServices.MaxscriptSDK.ExecuteMaxscriptCommand("Render()");
        }
    }
}

I’m hoping it’s just something simple I’ve missed but I keep getting this error AccessViolationException was unhandled (see image below for more detail) any thoughts would be great.


#2

Could be a cut/paste error but it looks like you have a space between ‘a’ and ‘nd’

ManagedServices.MaxscriptSDK.ExecuteMaxscriptComma  nd("Render()");

Hard to tell, the c# call looks ok to me in your image, i guess it could be the Render() call may have failed on the mxs side - it could also be down to the interop between c# and mxs.

I use a slightly different method to run mxs in C#… you may want to try it out and see if it helps.

            
// Your mxs sting of code
string mxsCode = ("$Box001.name");
// an sdk ifpvalue type that will get populated with the result of the mxs code
IFPValue mxsRetVal = Kernel.Global.FPValue.Create();
// run the string... you may want to try catch here...
Kernel.Global.ExecuteMAXScriptScript(mxsCode, true, mxsRetVal);
// here you can retreive the return.. check this class (mxsRetVal.Type will tell you the type of value returned.. here i know its a string (.S))
string ret = mxsRetVal.S;

You can call the same function without the return value stuff too if you dont want to deal with it…

            
// Your mxs sting of code
string mxsCode = ("$Box001.name");
// run the string... you may want to try catch here...
Kernel.Global.ExecuteMAXScriptScript(mxsCode, true, null);

Note : Kernel is just a class i use to access the max .Global and .Instance classes (I ripped off the maxsharp examples). Just replace it with however you are grabbing the global/instance stuff from the Autodesk.Max.dll.

Hope that helps.


#3

Thanks for your response, I believe the space between ‘a’ and ‘nd’ was just a copy and paste error as it’s fine in my code.

I will have to try the code you’ve posted but tbh I don’t completely understand what you mean by the kernel class or grabbing global/instance from Autodesk.Max.dll. As I’ve said I’m new to this so I apologies if this is all basic however I’ve struggled to find much information about this subject.

I think it’s probably best I spend a bit of time looking into MaxSharp and the Autodesk.Max.dll documentation.

Thanks Again


#4

So I just have a single class, in my c# project, that i use as an access point to the two main classes that the autodesk.max.dll provides.

It looks something like this (there can be other methods in there too…)

    public class Kernel
    {
        static public IGlobal Global = Autodesk.Max.GlobalInterface.Instance;
        static public IInterface13 Interface = Kernel.Global.COREInterface13;

    }

This just helps avoid having to keep passing either of these by parameter, or keep initializing them in whichever classes needs them.

Yea, It’s well worth looking into the autodesk.max.dll, and maxsharp, if you are doing max c# stuff.


#5

The ManagedServices.dll has to be loaded by an instance of max before you can use it.
Calling ExecuteMaxscriptCommand from a main method, won’t work.

Calling the method from mxs works, because the .dll is loaded by the max instance:

(dotnetClass "ManagedServices.MaxscriptSDK").ExecuteMaxscriptCommand "render()"

So you have to create you own .dll that reference ManagedServices and load it in max (remember to set Copy local to false)


#6

Ok, still not having any luck using a Kernel class is this definitely possible from an external exe file? :banghead: I must be doing something wrong or missing a step.

However on a brighter note I’ve had success using Ephere’s MaxDotNet and ExecuteMAXScriptScript() as previously suggested. One issue with this solution is there isn’t a release for the newer versions of 3ds max so I’ve been testing it on 2010 (which isn’t ideal).

During set up I had to open max 2010 and allow remoting on a specific port, this was done with a plugin that came with MaxDotNet and allowed me to access it from an external application using:

IManager manager = (IManager)Activator.GetObject( typeof( Autodesk.Max.Remoting.RManager ), "tcp://localhost:9998/Manager" );

Is this a step needed in the Kernel method? or does the Kernel class create the connection to 3ds Max itself?

I’m getting a little confused and realise that I’m probably creating more questions than anything else but any comments on this would be greatly appreciated.


#7

I just played a little bit with dnSpy and was able to modify IL code of managedservices.dll to save incoming string into a file each time function is called.
Can we do anything about it to prevent such strings hijacking? Maybe we can embed our own copy of managedservices.dll to prevent it?
But will it be valid across all max versions, anyone?

%D0%B8%D0%B7%D0%BE%D0%B1%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5


#8

can you explain the essence of the problem again? why can’t you start MAX first and then render all you need in batch?


#9

Maybe I’ve chosen the wrong thread to ressurect :slight_smile: it is pretty old, but somehow related to managedservices.dll
My question is can we somehow prevent mitm attack on c# dlls (since they’re just msil code) when sending plaintext scripts to execute via c# ExecuteMaxscriptCommand?
see my previous post