[Closed] SDK – applyable_class properties issue
I’m trying to learn the max SDK, and as an exercise, I’m adding some functionality to maxscript. I’ve managed to write and compile new static functions without too much problems. Now I’m trying to create an applyable_class. It’ll simply be a container for now, let’s call it KeyValuePair. All it does is store two Value pointers, a key, and a value.
The issue I’m having is that I don’t know how to use the get_property and set_property overrides. In some of the sample code projects I found that def_name() is used, but I can’t get that to work without getting compiler errors:
Error 1 error LNK2001: unresolved external symbol "class Value * n_key" (?n_key@@3PAVValue@@A) KeyValuePair.obj
Error 2 fatal error LNK1120: 1 unresolved externals C:\Program Files\Autodesk\3ds Max 2010\plugins\mxs_extensions.dlx 1
I have literally no idea where this comes from, let alone what I’m supposed to do about it.
Another things is: I don’t know what I’m actually doing here! From the looks of it, def_name just defines a Value* n_##name; and that’s it?
My code so far:
keyvaluepair.h
#ifndef GUARD_keyvaluepair
#define GUARD_keyvaluepair
#include "MAXScrpt.h"
#ifdef ScripterExport
#undef ScripterExport
#endif
#define ScripterExport __declspec( dllexport )
applyable_class (KeyValuePair);
class KeyValuePair : public Value
{
public:
~KeyValuePair();
KeyValuePair(Value* key, Value* value);
Value* _key;
Value* _value;
ValueMetaClass* local_base_class() { return class_tag(KeyValuePair); } // local base class in this class's plug-in
classof_methods(KeyValuePair, Value);
void collect() { delete this; };
void sprin1(CharStream* s);
# define is_keyvaluepair(v) ((DbgVerify(!is_sourcepositionwrapper(v)), (v))->tag == class_tag(KeyValuePair))
Value* get_property(Value** arg_list, int count);
def_property ( key );
def_property ( value );
};
#endif
keyvaluepair.cpp
#include "MAXScrpt.h"
#include "KeyValuePair.h"
#include "defextfn.h"
def_name(key);
#ifdef ScripterExport
#undef ScripterExport
#endif
#define ScripterExport __declspec( dllexport )
visible_class_instance(KeyValuePair, "KeyValuePair");
//===========================================================
// KeyValuePairClass apply
//
Value* KeyValuePairClass::apply(Value** arg_list, int count, CallContext* cc)
{
check_arg_count(KeyValuePair, 2, count);
three_value_locals(key, value, result);
vl.key = arg_list[0];
vl.value = arg_list[1];
vl.result = new KeyValuePair(vl.key, vl.value);
return_value(vl.result);
}
//===========================================================
// KeyValuePair constructor
//
//KeyValuePair::KeyValuePair() { };
KeyValuePair::KeyValuePair(Value* key, Value* value)
{
_key = key;
_value = value;
}
//===========================================================
// KeyValuePair destructor
//
KeyValuePair::~KeyValuePair()
{
}
void KeyValuePair::sprin1(CharStream* s)
{
s->printf(_T("KeyValuePair(%g, %g)"), _key, _value);
}
Value* KeyValuePair::get_property(Value** arg_list, int count)
{
if (arg_list[0] == n_key) return _key;
return Value::get_property(arg_list, count);
}
If a SDK magician could help me out, that would be great. The SDK help files aren’t really much use to me, I can’t find anything in there…
Do you have the public Sparks message archive ? If not I can send you it.
They’re was lot of discussions about extending MAXScript in this webboard. I have searched ‘get_property’ in it and it seems there are answers and solutions for your problem.
Value* KeyValuePair::get_property(Value** arg_list, int count)
{
if (arg_list[0] == n_key) return _key; //where is n_key come from?
return Value::get_property(arg_list, count);
}
As far as I understood it, def_name(key); defines a Value* n_key.
This seems to be the way the samples work as well. Apart from that it doesn’t work at all for me :shrug:
Well, after having read the topics in the Sparks archive kindly provided by Yannick, and having studied the problem for two more days, I’m still completely at a loss of what’s going on!
I have been looking at /howto/maxscript/testdlx but that didn’t clear things up at all. For one, it does not work when loading the plugin (missing LibClassDesc and LibNumberClasses).
I tried copying the code into my own plugin, and made it run. Now the curious thing is, in the List max class defined there, is a property “count”. In the implementation, there’s a function get_count and set_count, which are called when using the property in maxscript. I’ve verified this by setting a breakpoint in it, and it works as you’d expect.
Now, I added my own property in the exact same way, but the get_myprop and set_myprop are never called! When calling them from maxscript, it just runs the get_property and set_property function, which pass it on to the Value class.
Another thing I noticed: n_count is a valid pointer, defined somewhere in core. If I define my property in the same way (def_name(myprop)), I get a null pointer. This also goes for two properties defined by the howto, which as a result do not work.
So, I have two problems:
- Where do the calls to get_count and set_count come from? Why isn’t get_property and set_property called for the count property?
- How do I make my pointers created with the def_name macro valid pointers so I could use them in get_property?
:curious:
Well, in the testdlx I added the following:
dlxClass.h:
// line 45
def_property(count);
def_property(my_prop);
dlxClass.cpp
// line 20
def_name(head);
def_name(tail);
def_name(my_prop);
// and modified the get_property:
Value*
ListValue::get_property(Value** arg_list, int count)
{
Value* prop = arg_list[0];
if (prop == n_my_prop)
return &true_value; // just to see if it works.
else if (prop == n_head)
return head ? head : &undefined;
else if (prop == n_tail)
return head ? (Value*)tail : (Value*)&undefined;
else
return Value::get_property(arg_list, count);
}
I added the two functions to get the DLL to work (LibClassDesc and LibNumberClasses), but left the rest of the code exactly as it was.
I have it working!
This MAXScript SDK is a nightmare :twisted:.
I have successfully found how to initialize well the names defined:
Remove the "def_property(my_prop);" declaration in dlxClass.h
Remove the names declarations in dlxClass.cpp and create a file "namedefs.h" in the project that contains them:
namedefs.h
def_name (head)
def_name (tail)
def_name (myprop)
- tester.cpp
After the common includes:
Replace
tester.cpp
// define the new primitives using macros from SDK
#include "definsfn.h"
def_visible_primitive( my_copy_file, "myCopyFile");
def_visible_primitive( my_file_in, "myFileIn");
By
tester.cpp
#ifdef ScripterExport
#undef ScripterExport
#endif
#define ScripterExport __declspec( dllexport )
// define the new primitives using macros from SDK
#include "definsfn.h"
def_visible_primitive( my_copy_file, "myCopyFile");
def_visible_primitive( my_file_in, "myFileIn");
#include "definsfn.h"
# include "namedefs.h"
tester.cpp
void tester_init()
{
CharStream* out = thread_local(current_stdout);
out->puts(_T("--* Testdlx.dlx 4.00 loaded *--
"));
define_system_global("mySlider", get_slider_time, set_slider_time);
install_rollout_control(Name::intern("foo"), FooControl::create);
#include "defimpfn.h"
# include "namedefs.h"
}
- dlxClass.cpp
After the common includes:
Replace
dlxClass.cpp
#include "lclinsfn.h"
# include "listpro.h"
# include "setpro.h"
By
dlxClass.cpp
#ifdef ScripterExport
#undef ScripterExport
#endif
#define ScripterExport __declspec( dllexport )
#include "lclinsfn.h"
# include "listpro.h"
# include "setpro.h"
#include "defextfn.h"
# include "namedefs.h"
get_property() function should work fine now!
Good luck :). If you want, I can send you the code.
The topic "How do I make properties and methods of a class?" in sparks archive helped me a lot (see Larry Minton's posts, he's the MAXScript developer).
If you could send the code, that would be amazing!
And I’m glad to see that I’m not the only one who finds this part of the SDK utterly confusing.
I’ve got it working now too, thanks Yannick!
However, I really do not understand why it is working. The names defined seem to magically point at the proper value or class now, and that made obviously makes the get_property function work correctly. The count getter and setters are still not going through the get_property function though, for reasons completely beyond my understanding.
It’s quite a mysterious bit of design this maxscript SDK…