RegisterNotification not working with remoting ?

 
 
 
Posted by:Snoelk
Data created:21 October 2010

i tried to register notification events via remoting. i always get weird errors. TargetInvokationError cant load assembly TestMaxApp here is the code. maybe i did something terribly wrong. 

namespace TestMaxApp
{
    public class Program
    {
        public GlobalDelegates.Delegate4 systemShutdownHandler;

        [STAThread]
        public static void Main()
        {
            IManager m_manager = (IManager)Activator.GetObject(typeof(RManager), "tcp://localhost:9998/Manager");

            GlobalDelegates.Delegate4 systemShutdownHandler = new GlobalDelegates.Delegate4(Global_SystemShutdown);

            m_manager.Global.RegisterNotification(systemShutdownHandler, null, SystemNotificationCode.SystemShutdown);

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1(m_manager));
        }

        private static void Global_SystemShutdown(IntPtr obj, IntPtr info)
        {
            MessageBox.Show("Max Shuts down");
        }
    }
}


Mario Röske
Technical Artist
Piranha-Bytes

Can you see the inner exception of TargetInvocationError? It should give a more descriptive message.

I am away from office at the moment so I can't check this out, however, the code looks OK from the first glance. Does the error happen when loading that assembly?

Marsel Khadiyev (Software Developer, EPHERE Inc.)

this happens after loading the assembly.

...

IManager m_manager = (IManager)Activator.GetObject(typeof(RManager), "tcp://localhost:9998/Manager");

GlobalDelegates.Delegate4 systemShutdownHandler = new GlobalDelegates.Delegate4(Global_SystemShutdown);

m_manager.Global.RegisterNotification(systemShutdownHandler, null, SystemNotificationCode.SystemShutdown);  <----- this line crashes with the exception

...

now the innerException itself. have to translate. the messages are in german ^^

[System.IO.FileNotFoundException]

  • {"The File or Assembly \"TestMaxApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\" or the dependency for it couldnt be found. The system cant find the file.":"TestMaxApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"}

Data

  • {System.Collections.ListDictionaryInternal}

FileName

  • TestMaxApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

HelpLink

  • null

InnerException

  • null

Message

  • The File or Assembly \"TestMaxApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\" or the dependency for it couldnt be found. The system cant find the file.

Source

  • mscorelib

StackTrace

  • at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
  • at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection, Boolean suppressSecurityChecks)
  • at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
  • at System.Reflection.Assembly.Load(String assemblyString)
  • at System.Runtime.Serialization.FormatterServices.LoadAssemblyFromString(String assemblyName)
  • at System.Reflection.MemberInfoSerializationHolder..ctor(SerializationInfo info, StreamingContext context)

TargetSite

  • null

 

i tried the Registration with a dll too, just to be sure and then its working like a charme.

currently thinking in making a workaround with ole automatisation. but that feels like a dirty hack *g*

 

regards


Mario Röske
Technical Artist
Piranha-Bytes

[UPDATE]

now i dont get it. after days i made a new testrun to add something new and now it works.

i have no idea why now. i think i installed open office or something that instlled something that i didnt got before.

the code is the same now and its still working.

 


Mario Röske
Technical Artist
Piranha-Bytes

Right, it looks like it couldn't resolve your assembly before but now it can. Not really sure why that would be happening, the assembly should've been resolved if you referenced it, but glad it works now nevertheless :)

Marsel Khadiyev (Software Developer, EPHERE Inc.)

to early, after restart my comp its happening again arf


Mario Röske
Technical Artist
Piranha-Bytes

maybe this exception tells you more

 

Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
    Server stack trace:
       at System.RuntimeMethodHandle._SerializationInvoke(IRuntimeMethodInfo method, Object target, SignatureStruct& declaringTypeSig, SerializationInfo info, StreamingContext context)
       at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
       at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
       at System.Runtime.Serialization.ObjectManager.DoFixups()
       at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Remoting.Channels.CoreChannel.DeserializeBinaryRequestMessage(String objectUri, Stream inputStream, Boolean bStrictBinding, TypeFilterLevel securityLevel)
       at System.Runtime.Remoting.Channels.BinaryServerFormatterSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg, ITransportHeaders& responseHeaders, Stream& responseStream)
    Exception rethrown at [0]:
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       at Autodesk.Max.IGlobal.RegisterNotification(Delegate3 proc, Object param, SystemNotificationCode code)
       at TestMaxApp.TestMaxApp.Main() in C:\Documents and Settings\Visual Studio 2005\Projects\TestMaxApp\TestMaxApp\TestMaxApp.cs:line 25
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.TypeLoadException
       Message=Could not load type 'TestMaxApp.TestMaxApp' from assembly 'TestMaxApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
       Source=mscorlib
       TypeName=TestMaxApp.TestMaxApp
       StackTrace:
            at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type)
            at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
            at System.Reflection.MemberInfoSerializationHolder..ctor(SerializationInfo info, StreamingContext context)
       InnerException:


Mario Röske
Technical Artist
Piranha-Bytes

Where is the .exe file that you're running located? Is it on the same computer as 3dsmax? It seems that you need to either register it in the GAC of the computer running 3dsmax or put it into 3dsmax's root directory (so it can resolve it).

Marsel Khadiyev (Software Developer, EPHERE Inc.)

the exe thats generated is on the same computer than 3dsmax.

but when i start as debug its not in the same root.

do i have to autogenerate it inside the main root of max to get it running ?


Mario Röske
Technical Artist
Piranha-Bytes

ok i think thats it

moved the exe files to the main path of 3ds max. now it seems to work.

why there rest of it works without placing the exe to the max app path ?


Mario Röske
Technical Artist
Piranha-Bytes

From my understanding Max needs to resolve your assembly if you are using a delegate from it. Your delegate is a part of your custom class and thus Max (on the other end) needs to be able to resolve that class.

Marsel Khadiyev (Software Developer, EPHERE Inc.)

is it possible to delegate the event notifications via remoting to my forms ?

right now everytime i want to call a event inside my form everything crashes.

if i try to register those events inside the form and not in the main() i get an instant crash when its start to register the notification. without an exception. it seems the event from max cant alter anything inside the remoting application.


Mario Röske
Technical Artist
Piranha-Bytes

So the application from which you invoke remoting into 3dsmax crashes? What type of changes are you trying to make? It is possible that remoting is invoking your callbacks on a thread different from your main Forms thread. .NET forms require you to perform most operations on the same thread used for creating the form, so you might need to use Invoke(...) method to ensure that you execute your code on the same thread.

Marsel Khadiyev (Software Developer, EPHERE Inc.)

thats what im doing

heres some code

namespace TestMaxApp
{
    /// <summary>
    /// Hauptklasse der TestMaxApp
    /// </summary>
    public class TestMaxApp
    {
            public static IManager m_Manager;
            public static TestMaxAppGui MyForm;
            public static GlobalDelegates.Delegate3 selectionSetChanged;

        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        public static void Main()
        {
            m_Manager = (IManager)Activator.GetObject(typeof(RManager), "tcp://localhost:9998/Manager");

            GlobalDelegates.Delegate3 selectionSetChanged = new GlobalDelegates.Delegate3(OnMaxMessage);
            m_Manager.Global.RegisterNotification(selectionSetChanged, null, SystemNotificationCode.SelectionsetChanged);


            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            MyForm = new TestMaxAppGui(m_Manager);

            Application.Run(MyForm);
        }

        private static void OnMaxMessage( IntPtr Obj, IntPtr Info )
        {
             MyForm.Invoke(MyForm.maxDelagete);
        }
    }
}


now the snippet from the form

public partial class TestMaxAppGui : Form
    {
        /// <summary>
        /// stores the Max Global Interface
        /// </summary>

        public delegate void OnMaxDelegate();

        public IGlobal MaxGlobal;
        public IManager m_Manager;
        public OnMaxDelegate maxDelagete;

        public TestMaxAppGui(IManager a_Manager)
        {
            InitializeComponent();

            try
            {
                maxDelagete = new OnMaxDelegate(this.OnMax);

                this.m_Manager = a_Manager;
                this.MaxGlobal = m_Manager.Global;
                EnableGui(true);
            }
            catch (System.Net.Sockets.SocketException _Exception)
            {
                EnableGui(false);

                if (_Exception.ErrorCode.Equals(10061))
                {

                    MessageBox.Show("No Connect to Max could be established!!");
                }
            }
            catch (Exception _SysException)
            {
                EnableGui(false);
            }
        }

       // This delegate enables asynchronous calls from other threads
        public void OnMax()
        {
            MessageBox.Show("Juhuuuu");
        }

}

im trying to invoke the callback from max to my form. it seems, that the callback from max runs inside the thread of max itself. so its a complete other process and thread. if i try to acces now my main application from there it gives me a crash. some friend that has looked into it means that i have to make interprocess communication between max and my application. or i dont get it right.


Mario Röske
Technical Artist
Piranha-Bytes