A defer loaded plug-in DLL will not be loaded into memory until required by 3ds Max for the first time. Deferring a plug-in is a useful technique for improving the start-up time and reducing the memory footprint of 3ds Max. This is why 3ds Max uses automatic defer loading system. If a plug-in DLL is deferred, it should not impact the user experience. For example:
Certain plug-in types that are cached (proxied out) by 3ds Max need all their data to be constant to prevent run time issues when defer loaded. 3ds Max will still defer load the plug-in if those values are not constant, but the user may experience unexpected behavior in certain 3ds Max features. One example is the input type of a modifier plugin. If the type of an input object used by a modifier changes at run-time, then the user may not be able to apply the deferred modifier on certain object types. For the correct behavior to re-establish, the modifier plug-in needs to be loaded.
If it is not possible for a plug-in to be defer loaded without impacting the user experience, then it is the responsibility of a plug-in developer to opt out of the automatic defer loading system. This can be done by returning FALSE
from the DLL exported function CanAutoDefer()
as following:
// The plug-in opts out from 3ds Max\'s defer loading mechanism,
// i.e. it\'s always loaded when 3ds Max starts up.
__declspec( dllexport ) ULONG CanAutoDefer()
{
return FALSE;
}
You will also need to add this line to the \.DEF* file. Example:
CanAutoDefer @5
Loading of a plugin however will not be defered, even if CanAutoDefer() function returns true, if the plug-in:
def_struct_primitive
, def_visible_primitive
, def_property
, etc macros. See the documentation of the file define_abstract_functions.h ObjectDataReaderCallback
Although 3ds Max implements some heuristics to detect if the plug-in can be safely deferred, plug-in developers are ultimately responsible for detecting violations of this requirement and explicitly disallow 3ds Max from defer loading the plug-in.
Developers can turn on or off specific plug-in defer loading features using certain flags defined in the file 3dsmax.ini. These features are:
NOTIFY_SYSTEM_STARTUP
notification. See the RegisterNotification()
global function.These flags are introduced in the example below.
[PluginSettings]
; Controls whether plug-ins DLL that do not implement ULONG CanAutoDefer are defer loaded (1) or not (0)
CanAutoDeferDefaultValue=1
; Controls whether plug-in DLLs that expose Action Table (action items) can be defer loaded (1) or not (0)
EnableActionItemProxySystem=1
; Controls whether plug-in DLLs that function publish "core" interfaces can be defer loaded (1) or not (0)
EnableCoreInterfaceProxySystem=1
; Controls whether plug-in DLLs that rely on startup notifications can be defer loaded (1) or not (0)
EnableStartupNotificationReplaySystem=1
The Plug-In Manager feature of 3ds Max shows the user whether a plug-in DLL has been deferred or loaded.
Besides action tables and core interfaces, a plug-in may need to register with 3ds Max other callbacks and objects that affect the user interface such as, but not limited to:
IActionItemOverrideManager::ActivateActionItemOverride()
.IGeometryCheckerManager::RegisterGeometryChecker()
.DragAndDropHandler
.IMenuManager::RegisterMenu()
.IViewportButtonManager::RegisterButton()
.ITrackBarFilterManager:: RegisterFilter()
.RegisterObjectConverter()
, RegisterStaticEditTri()
, RegisterEditTriObjDesc()
and RegisterEditPolyObjDesc()
.At this time 3ds Max's plug-in loading mechanism does not detect these cases and as a result, it will defer load such a plug-in DLL unless it explicitly disallows deferring.
The deferred plug-in DLLs are loaded when a certain user action requires them to be present. Because the sequence of user actions is not always predictable, the order in which deferred plug-in DLLs are loaded by 3ds Max will not be deterministic. In general, Plug-in DLL A has a load order dependency on plug-in DLL B if B needs to be loaded in 3ds Max's address space before A. If plug-in DLL A calls a function exported from plug-in DLL B, a load order dependency will exist between the two plug-in DLLs.
If the plug-in DLL B is defer loaded:
GetProcAddress()
) and call that function.The solution to this problem is to eliminate the load order dependency between the two plug-in DLLs by:
FPStaticInterface
and is created with theFP_CORE
flag). Plug-in DLLs that expose core interfaces are guaranteed to be loaded on demand, when client code acquires the core interface they expose.One example of a plug-in architecture that does not work well with plug-in DLL defer loading is when a 3ds Max plug-in loads a DLL at run-time that extend the plug-in's functionality and the plug-in exposes this functionality in the 3ds Max user interface.
When the plug-in DLL is deferred, extensions in the form of DLLs installed since the last session of 3ds Max may not show up in the user interface, until some user action triggers the loading of the plug-in DLL that depends on these extensions.