MAXScript plug-ins have the file extension .dlx
. They can extend MAXScript in several ways, including:
Note: There are several sample DLX projects in the 3ds Max sdk howto and samples directories. See the MAXScript Extension Plug-ins topic for a list of these projects. The
howto\intervalarray
andhowto\testdlx projects
are simple examples that illustrate how to add different types of extensions.
Other plug-in types use the Function Publishing method to expose themselves to MAXScript. DLX plug-ins expose functions by extending the Primitive class, and using the def_visible_primitive macro from maxscript\macros\define_instantiation_functions.h
:
// Declare C++ function and register it with MAXScript
#include <maxscript\macros\define_instantiation_functions.h>
def_visible_primitive(IntervalArray, "IntervalArray");
Note: DLX plug-ins cannot be loaded or viewed in the Plug-in Manager. When writing and testing a DLX plug-in, you need to add the path to the compiled plug-in to the 3rd Party Plug-Ins paths (under Customize > Configure User and System Paths), and re-start 3dx Max.
DLX plug-ins must define a DLL entry point that sets the language locale and disables threading when the DLL is loaded. This file also exports the DLL's initialization function, the description, and the version.
MAXScript plug-ins do not generally use ClassDesc
so their .cpp
and .def
files are simpler as they do not export the functions GetClassDesc()
and GetNumClasses()
.
The following is a typical MAXScript plug-in .def
file:
LIBRARY IntervalArray.dlx
EXPORTS
LibDescription @1 PRIVATE
LibInit @2 PRIVATE
LibVersion @3 PRIVATE
SECTIONS
.data READ WRITE
The following is the implementation of the IntervalArray howto sample DllMain.cpp
file (in maxsdk/howto/maxscript/intervalarray/
):
//DLLMain.cpp
#include <maxscript/maxscript.h>
HINSTANCE hInstance;
extern void IntervalArrayInit ();
// ========================================================
// Grab onto this DLL's instance handle
BOOL WINAPI DllMain(HINSTANCE DLLhinst, DWORD fdwReason, LPVOID lpvReserved)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
MaxSDK::Util::UseLanguagePackLocale();
hInstance = DLLhinst;
DisableThreadLibraryCalls(hInstance);
break;
}
return TRUE;
}
__declspec(dllexport) void LibInit()
{
//TODO: Put any code for initializing your plugin here.
//In this case it is IntervalArrayInit(), which will be defined in IntervalArray.cpp,
//However in this example IntervalArrayInit() is empty.
IntervalArrayInit();
}
__declspec(dllexport) const TCHAR* LibDescription()
{
//TODO: Put code in here telling what your plugin does.
return _T("Interval Array Function");
}
__declspec(dllexport) ULONG LibVersion()
{
//Return the version of the Max SDK
return VERSION_3DSMAX;
}
Note: There are several sample DLX projects in the 3ds Max sdk howto and samples directories. See the MAXScript Extension Plug-ins topic for a list of these projects. The
howto\intervalarray
andhowto\testdlx projects
are simple examples that illustrate how to add different types of extensions.
Other plug-in types use the Function Publishing method to expose themselves to MAXScript. DLX plug-ins expose functions by extending the Primitive class, and using the def_visible_primitive macro from maxscript\macros\define_instantiation_functions.h
:
// Declare C++ function and register it with MAXScript
#include <maxscript\macros\define_instantiation_functions.h>
def_visible_primitive(IntervalArray, "IntervalArray");
Note: DLX plug-ins cannot be loaded or viewed in the Plug-in Manager. When writing and testing a DLX plug-in, you need to add the path to the compiled plug-in to the 3rd Party Plug-Ins paths (under Customize > Configure User and System Paths), and re-start 3dx Max.
The DLL entry definition is simpler than for other plug-in types, as MAXScript plug-ins do not generally use ClassDesc
so their .cpp
and .def
files do not export the functions GetClassDesc()
and GetNumClasses()
.
They only need to export:
LibInit()
- all initialization is performed hereLibDescription()
- a short description of the DLLLibVersion()
- returns the supported version of 3ds Max (the SDK version used to build the DLL)The following is a typical MAXScript plug-in .def
file:
LIBRARY IntervalArray.dlx
EXPORTS
LibDescription @1 PRIVATE
LibInit @2 PRIVATE
LibVersion @3 PRIVATE
SECTIONS
.data READ WRITE
DLX plug-ins must define a DLL entry point that sets the language locale and disables threading when the DLL is loaded.
The following is the implementation of the IntervalArray howto sample DllMain.cpp
file (in maxsdk/howto/maxscript/intervalarray/
):
//DLLMain.cpp
#include <maxscript/maxscript.h>
HINSTANCE hInstance;
extern void IntervalArrayInit ();
// ========================================================
// Entry point for this DLL. See https://docs.microsoft.com/en-us/windows/desktop/dlls/dllmain
// Here we set up the user language, store the DLL handle, and disable threading for system calls
// because 3dsmax.exe is not multi-threaded.
BOOL WINAPI DllMain(HINSTANCE DLLhinst, DWORD fdwReason, LPVOID lpvReserved)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
MaxSDK::Util::UseLanguagePackLocale();
hInstance = DLLhinst;
DisableThreadLibraryCalls(hInstance);
break;
}
return TRUE;
}
__declspec(dllexport) void LibInit()
{
// This function is called when the DLL is loaded to do any initialization.
// In this case it is IntervalArrayInit(), which is defined in IntervalArray.cpp,
IntervalArrayInit();
}
__declspec(dllexport) const TCHAR* LibDescription()
{
// Return a short description string here
return _T("Interval Array Function");
}
__declspec(dllexport) ULONG LibVersion()
{
// Returns the version of the Max SDK, used to check compatibility when loaded by Max
return VERSION_3DSMAX;
}
Finally, here is the actual implementation of the IntervalArray type in IntervalArray.cpp:
#include <maxscript/maxscript.h>
#include <maxscript/foundation/numbers.h>
#include <maxscript/foundation/arrays.h>
void IntervalArrayInit()
{
//Todo: Place initialization code here. This gets called when Maxscript goes live
//during max startup.
}
// Declare C++ function and register it with MAXScript
#include <maxscript\macros\define_instantiation_functions.h>
def_visible_primitive(IntervalArray, "IntervalArray");
Value* IntervalArray_cf(Value **arg_list, int count)
{
//--------------------------------------------------------
//Maxscript usage:
//--------------------------------------------------------
// <array> IntervalArray <Start:Number> <End:Number> <steps:Integer>
check_arg_count(IntervalArray, 3, count);
Value* pBegin = arg_list[0];
Value* pEnd = arg_list[1];
Value* pStep = arg_list[2];
//First example of how to type check an argument
if ( ! (is_number(pBegin)))
{
throw RuntimeError(_T("Expected a Number for the first argument, in function IntervalArray"));
}
if ( ! (is_number(pEnd)))
{
throw RuntimeError(_T("Expected a Number for the second argument, in function IntervalArray"));
}
//Second example of how to type check an argument
integer_type_check(pStep, _T("Expected an Integer for the step size" ));
float begin = pBegin->to_float();
float end = pEnd->to_float();
int steps = pStep->to_int();
if (steps <= 0) { throw RuntimeError(_T("Expected a positive Number for Steps, in function IntervalArray"));}
MAXScript_TLS* _tls = (MAXScript_TLS*)TlsGetValue(thread_locals_index);
one_typed_value_local_tls(Array* rArray);
vl.rArray = new Array (steps);
float data = begin;
float increment = ((end-begin)/steps);
for (int i = 0 ; i <= steps ; i++)
{
Value* aTempNumber = Float::heap_intern(data);
vl.rArray->append(aTempNumber);
data += increment;
}
return_value_tls(vl.rArray);
}