SDK-C# Set transform controller value


#7

It should be pretty straightforward in theory, but in practice it throws system exception and crashes max :slight_smile:
Don’t know if it will work when used from compiled c# dll

code
tea = Teapot isSelected:true

g = (dotNetClass "Autodesk.Max.GlobalInterface").Instance
n = g.coreinterface14.getselnode 0

tm_parent = g.Matrix3.create()
tm_parent.IdentityMatrix()

tm = g.Matrix3.create()
tm.IdentityMatrix()
tm.SetTranslate (g.point3.create 0 0 50)

tm_xf = g.SetXFormPacket.Create tm tm_parent

g.suspendanimate()
n.TMController.SetValue currenttime.ticks tm_xf true (dotNetClass "Autodesk.Max.GetSetMethod").absolute
g.resumeanimate()

#8

It will crash in C# also:

                object setXFormPacket = globalInterface.SetXFormPacket.Create(matrix,globalInterface.Matrix3.Create());
                node.TMController.SetValue(coreInterface.Time, setXFormPacket, true, GetSetMethod.Absolute);

globalInterface.SetXFormPacket.Create has more overloads, maybe we should use it another way.


#9

@Swordslayer may you help us?


#10

“&” in &pckt means we should send the pointer not variable, right? how we can do it in C#?


#11

I tried something like this:

    ISetXFormPacket setXFormPacket2 = globalInterface.SetXFormPacket.Create();
    setXFormPacket2.Aa = globalInterface.AngAxis.Create();
    setXFormPacket2.Command = SetXFormCommand.Set;
    setXFormPacket2.LocalOrigin = true;
    setXFormPacket2.P = globalInterface.Point3.Create();
    setXFormPacket2.Q = globalInterface.Quat.Create();
    setXFormPacket2.TmAxis = globalInterface.Matrix3.Create();
    setXFormPacket2.TmParent = globalInterface.Matrix3.Create();

    IntPtr setXFormPacket = Wrappers.CustomMarshalerSetXFormPacket.GetInstance(string.Empty).MarshalManagedToNative(setXFormPacket2);
    node.TMController.SetValue(time, setXFormPacket, true, GetSetMethod.Absolute);

But again crashing …


#12

“&” in &pckt means we should send the pointer not variable, right?

yes in you are passing the memory address of the object… you could also do it like this

SetXFormPacket*  pckt = new SetXFormPacket(destTM);
tmControl->SetValue(ip->GetTime(), pckt);
delete pckt;

#13

So, We can’t do it in C#?


#14

what about…

object setXFormPacket = globalInterface.SetXFormPacket.Create(matrix,globalInterface.Matrix3.Create());
object* ptr = &setXFormPacket ;
node.TMController.SetValue(coreInterface.Time, ptr, true, GetSetMethod.Absolute);

#15

I got several errors for this:
Compiler Error CS0214: Pointers and fixed size buffers may only be used in an unsafe context
Compiler Error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('object')


#16

declare it as unsafe


#17

“object” type can not be declared as pointer.


#18

could try something like…

  unsafe
    {
        object setXFormPacket = globalInterface.SetXFormPacket.Create(matrix,globalInterface.Matrix3.Create());
        void* ptr = &setXFormPacket ;
        node.TMController.SetValue(coreInterface.Time, ptr, true, GetSetMethod.Absolute);
    }

#19

Not working…

|Error|CS0208|Cannot take the address of, get the size of, or declare a pointer to a managed type 
|Error|CS1503|Argument 2: cannot convert from 'void*' to 'object

which dotnet version do you use? mine is 4.7.2 and “Allow unsafe code” option is enabled.


#20

I’m not using dotnet , just making guesses as I know nothing about c# and max. The only I can think of trying is to create your own c# callable c++ function wrapper to handle it.


#21

it should work, but actually got some errors.


#22

Not sure if this works (or something similar):

        public static unsafe void Test (IMatrix3 matrix, INode node)
        {
            ISetXFormPacket setXFormPacket = globalInterface.SetXFormPacket.Create(matrix, globalInterface.Matrix3.Create());
            void* nativePtr = setXFormPacket.Handle.ToPointer();
            IntPtr* ptr = (IntPtr*)nativePtr;
            node.TMController.SetValue(coreInterface.Time, *ptr, true, GetSetMethod.Absolute);
        }

At least, it compiles. :slight_smile:


Calling C++ function inside C#
#23

INode is not defined, so I used IINode instead.

.Handle is not property of setXFormPacket. so I used .NativePointer instead

Yes, it will be compiled this way, But it will crash the Max again.

private readonly static IGlobal globalInterface = GlobalInterface.Instance;
private readonly static IInterface coreInterface = globalInterface.COREInterface;

public static unsafe void Test(IMatrix3 matrix, IINode node)
{
    int time = coreInterface.Time;
    ISetXFormPacket setXFormPacket = globalInterface.SetXFormPacket.Create(matrix, globalInterface.Matrix3.Create());
    void* nativePtr = setXFormPacket.NativePointer.ToPointer();
    IntPtr* ptr = (IntPtr*)nativePtr;
    node.TMController.SetValue(coreInterface.Time, *ptr, true, GetSetMethod.Absolute);
    globalInterface.COREInterface.RedrawViews(time, RedrawFlags.Normal, null);
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    IINode selNode = coreInterface.GetSelNode(0);
    if (selNode == null) MessageBox.Show("Selection empty.");
    else
    {
        IMatrix3 matrix = globalInterface.Matrix3.Create(true);
        Test(matrix, selNode);
    }
}

#24

Maybe we can use that hack : ManagedServices.MaxscriptSDK.ExecuteStringMaxscriptQuery
any idea how we can send transform controller handler value?


#25

what’s that?
if it is an animatable then simply use getHandleByAnim on mxs side and Animatable.GetAnimByHandle on c# side

Alternatively you can pass maxscript values to c# methods directly, but you’ll have to use some c# argument naming rules for it to work. Check MaxPlusArgNameParsingConstants in …\maxsdk\samples\maxscript\mxsdotNet\utils.h

for example if you want to pass point3 value to the c# method its signature should be like that
… MyMethod( IntPtr point3_pointer )

Class Animatable


#26

I couldn’t find that. where is it?