SDK - applyable_class properties issue

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

THREAD CLOSED
 
Thread Tools Search this Thread Display Modes
Old 01 January 2010   #1
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...

Last edited by Pjanssen : 01 January 2010 at 04:41 PM.
 
Old 01 January 2010   #2
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);
} 
 
Old 01 January 2010   #3
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
 
Old 01 January 2010   #4
Originally Posted by Pjanssen: 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.
__________________
 
Old 01 January 2010   #5
Thanks. I've sent you a PM.
 
Old 01 January 2010   #6
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?

 
Old 01 January 2010   #7
Can you post or send me the code ?
__________________
 
Old 01 January 2010   #8
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.
 
Old 01 January 2010   #9
I have it working!

This MAXScript SDK is a nightmare .

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 *--\n"));
    	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).
__________________

Last edited by ypuech : 01 January 2010 at 05:09 PM.
 
Old 01 January 2010   #10
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.
 
Old 01 January 2010   #11
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.....
 
Old 01 January 2010   #12
Originally Posted by Pjanssen: 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


The names are pointing to the proper value now because they were not initialized.

About the count getter/setter and get_property/set_property, Larry Minton (MAXScript developer at Autodesk) explains in the topic "How do I make properties and methods of a class?" of the sparks archive:
Larry Minton
Quote: You can only use the get_XXX and set_XXX forms of getting/setting properties when XXX is defined in biprops.h. You cannot add to this biprops.h file (as you found), as this file defines virtual functions on the Value class. Instead, you need to use the get_property and set_property methods, testing the property name passed in.

In biprops.h, count is defined as a property:
def_property( count )


If you want, I can send you a version with comments where I made the modifications to make it work.
__________________

Last edited by ypuech : 01 January 2010 at 11:00 AM.
 
Old 01 January 2010   #13
Originally Posted by ypuech: The names are pointing to the proper value now because they were not initialized.

So where are they initialized now? Still the only thing that is declaring or doing anything with them is def_name(), or am I missing something?

Quote: About the count getter/setter and get_property/set_property, Larry Minton (MAXScript developer at Autodesk) explains in the topic "How do I make properties and methods of a class?" of the sparks archive:

I must have missed that thread, thanks
 
Old 01 January 2010   #14
Originally Posted by Pjanssen: So where are they initialized now? Still the only thing that is declaring or doing anything with them is def_name(), or am I missing something?

I will send you a commented version of testdlx to show you what I added/modified to make it work.

Originally Posted by Pjanssen: I must have missed that thread, thanks

This thread explains how to make the names work. I just applied what Larry explains.

Edited: Also, mxsagni sample at samples\maxscript\mxsagni helped me a lot too! It uses the namedefs.h file method. In fact it's the code of avg_dlx by Larry Minton.
__________________

Last edited by ypuech : 01 January 2010 at 11:30 AM.
 
Old 01 January 2010   #15
Thanks again Yannick! I've now managed to make my own maxscript class, with custom properties.

I do still find it strangely designed, having to use different includes to have def_name do the right thing in the right place... But I guess it can't be helped, let's just try to avoid it as much as possible.
 
Thread Closed share thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright ©2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 07:17 AM.


Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.