Distinguishing between .maxpat and .pat/.mxb/.mxt in my instantiation routine

    Feb 03 2011 | 11:30 pm
    Is there a recommended way for an (UI) object to tell at instantiation time whether it's part of a saved Max 5 .maxpat file that's been opened, or a Max 4 file (be it .pat, .mxb, .mxt, or suffix-free), or if it is just being instantiated because the user has just created a new box while editing?
    The reason I ask is that my object (or any UI object?) uses different saving strategies for Max 4 and Max 5. My Max 5 version obviously doesn't need to support *saving* with the Max 4 strategy, but it does need to support *reading* the Max 4 data (ie, it has to bind itself to a special symbol). And the last message sent in the stream of saved data is a special "unbind yourself from your special symbol" message, just to make sure my object doesn't find itself receiving stray messages from something else after the read is finished.
    I've looked at Patcher attributes to try to distinguish between Max4 and Max5 patchers. The fileversion attribute doesn't help, because by the time my object is instantiated, the imported Max4 patcher is already identified as fileversion 1. (Which maybe makes sense…). My next attempt was with the path attribute and checking against the file suffix. It turns out this is dodgy because an imported Max4 patcher apparently isn't associated with a file (also makes sense, but doesn't help).
    So, how do I tell what file format is being read from?
    Also, in Max 4 we knew that if we were being instantiated from menufunc that the user had just created a brand new instance (ie no stored data coming in). So how do we find out this information on Max 5?
    I've grepped through the docs, and both Googled and used the site search function with no luck. Apols in advance if this is covered somewhere.

    • Feb 03 2011 | 11:37 pm
      PS: It just occurs to me… is there any really compelling reason not to stick with the older saving strategy on Max5? It's tested and works, and the engineer never changes running system.
      That still leaves the last question (user instantiation vs. file read).
    • Feb 04 2011 | 6:40 am
      very clever question!
    • Feb 04 2011 | 11:30 pm
      Do you know about the stdargs method? There's an example in slider from the SDK. Attribute can be stored automatically if the save attr is set, but you can still add things to your dictionary if you need to using the jsave method.
    • Feb 05 2011 | 12:44 pm
      …erm no… there doesn't seem to be much about stdargs in the documentation…
      [ @Tim or whomever is maintaining the SDK docs: it would be _really_ nice to have a complete list of messages understood by the SDK objects. This is probably a moving target, but still, it would be good to have more information here. ]
      Thanks for the pointer to jslider. I _think_ I understand what's going on there with stdargs. Or maybe I will in a while.
      What would be a big help is to see how table and/or coll handle legacy patchers on Max5, but those aren't published anymore.
      I don't have a problem building a jsave method--that is reasonably well documented and the uitextfield project is a simple practical example of how jsave works. My basic issue is that if I'm reading a legacy patcher, my object must bind itself to a symbol (#T) in order to receive messages about stored data. If I'm *not* reading a legacy patcher, it would be cleaner to *not* bind the object to #T.
      I think I'm also going to need stdargs to circumvent the issue in my suspected bug report. But you've seen that thread already…
    • Feb 05 2011 | 3:12 pm
      gensym("#T)->s_thing = (t_object *)x; is all you need to do in the new method.
    • Feb 05 2011 | 8:43 pm
      Yes, I know that.
      I had a working psave method in Max4 (Max3, actually), and bound to #T in my new method. But I did NOT bind from my menufunc method, because I knew that there would be no messages to process.
      Furthermore, when I'm finished reading, I broke the binding. That is, the last line of my psave method was
      binbuf_vinsert(ioBBuf, "ss", gHashTSym, gensym("done"));
      (gHashTSym is a global variable containing gensym("#T"))
      So when I received the "done" message I set
      if (gHashTSym->s_thing == me)  // me is the current object
          gHashTSym->s_thing = NULL;
      (Actually, there were additional tests in the real code.)
      The whole point is I don't want my object to be bound to #T when some stray message gets sent by another object that thinks *it* owns gensym("#T")->s_thing. Can't happen? That's exactly what Luigi was trying to do in < https://cycling74.com/forums/how-to-refer-to-a-coll-from-custom-external >. If someone does that to a coll or table and Max crashes, that other person gets blamed. If someone does that to one of my objects and Max crashes, I get the blame. (cf. second post in thread 31004 %-)
      Which is the point of my original query. On Max4 and earlier you knew whether object instantiation was triggered by a menufunc message or by a new message and could handle the two cases differently. How to differentiate between the different cases on Max5 isn't really documented. I appreciate you effort to clarify this gap here in the forum.
    • Feb 08 2011 | 4:38 pm
      @peter, I'll look into a list of messages understood by the SDK objects for a future version. Good idea.
      Cheers, Tim
    • Jul 31 2012 | 2:57 pm
      I'd like to get back to the original question.
      How can my New Instance routine distinguish whether it is being called from reading a Max 4-style file vs. reading a Max 5-format file?