This document reviews the structure of 3ds Max plug-ins and the interactions between 3ds Max software, the plug-ins and the user. The goal is to provide a clear image of the architecture of a plug-in in high level terms without getting into plug-in specific details. The audience of this document are C++ developers with no previous experience in writing 3ds Max plug-ins with 3ds Max SDK. It is expected that the reader already is familiar with the basic features of 3ds Max.
A plug-in is the code and data that provides additional features or functionalities to 3ds Max. There are many plug-ins shipped with 3ds Max whose functionality form the majority of the architecture and behavior of the final product. Examples of plug-ins are custom geometric objects, animation controllers, texture maps, materials and so on. We will explain here how a developer can create a plug-in to accomplish his desired task by providing practical lessons on a limited types of plug-ins and their features. You can refer to the topics Overview: Plug-ins and and Plug-in File Extensions in the programmer's guide for a complete review of 3ds Max plug-ins.
How 3ds Max recognizes your plug-ins
Programmers implement plug-ins in dynamic link libraries (DLLs). These DLLs include classes extended from one or more predefined base classes in the Max SDK, and override specific member functions according to their needs. At the start up, 3ds Max attempts to load all DLL files placed from certain 3ds Max installation subfolders (e.g. <3dsMaxInstallFolder>\plugins). A DLL will only be loaded if it exports the required DLL functions mentioned below. These functions tell 3ds Max how many plug-ins are implemented in the DLL file, and return objects that both describe each of those plug-ins, and allow 3ds Max to instantiate from them.
What 3ds Max expects from your plug-in
In order for a DLL file to be loaded by 3ds Max it must implement certain functions. Common to any DLL, there must be a DLL entry point function (named DLLMain()). There are also at least four other functions required by 3ds Max. Three of them return basic information about the plug-in including: (1) the number of plug-in classes in the DLL, (2) the version of the 3ds Max SDK with which the plug-in has been compiled, and (3) a short string that gives the user an idea of what is contained in the DLL (e.g. what the included plug-in does).
The fourth function provides a mechanism with which the actual plug-in can be created (i.e. an object of our plug-in class can be instantiated) in 3ds Max. Once the plug-in is created using this function, 3ds Max will have specialized interfacing to the plug-in based on the plug-in type. This function is explained in more details below in the Class Descriptors section.
Other than these four functions without whom your plug-in cannot be compiled, there are two other DLL functions needed for initializing of your plug-in when it is being loaded for the first time, and un-initializing it when it is being un-loaded. It is strongly recommended to include these two functions in your DLL as well. The names and detailed descriptions of these DLL functions are listed in the topic required DLL functions in the programmer's guide.
Other than the main plug-in class, every plug-in project contains a class knows as the 'class descriptor'. The class descriptor has virtual member functions that provide different information to 3ds Max about the plug-in. This information includes the class ID (explained below), category, and name. The class descriptor is usually derived from ClassDesc2, but can also be derived from ClassDesc.
An important task of the class descriptors is to implement a function (named Create()) that provides 3ds Max a pointer to an instance of our plug-in object. 3ds Max will use this pointer to access the plug-in’s properties and functionality. You can refer to its dedicated page in the programmer's guide for detailed information on the class descriptor.
3ds Max recognizes the plug-ins not by the name but by their IDs. This means that two different plug-ins with the same name can co-exist as long as they have different IDs. On the other hand, if two plug-ins with different or the same name share the same ID, 3ds Max will load only one of them and will give a warning message regarding the conflict. The reason behind this is that different developers might accidentally pick up the same names for their plug-ins, but it is practically impossible for them to pick up the same IDs since the ID consists of two random unsigned 32-bit numbers.
A .DEF file can be included in a DLL project to describe various attributes of the DLL such as the name and the order of the functions exposed in the DLL file. By listing the six mandatory plug-in functions in your .DEF file, you tell 3ds Max that the functions are implemented and are ready to be called. Although There are methods to load the plug-ins without including the .DEF file in the projects, we rather have it in the sample projects accompanying the lessons in this learning path to make them compatible with the plug-ins in the howto and samples sub-folders.
How to make your plug-ins do what you want
Based on their desired task, plug-in can extend from many different base classes. The base class will outline the structure of your plug-in. Unlike a standalone application, your plug-in will not work by following a path from a start to end point in its code. Instead, it implements the member functions that are called by either 3ds Max, other plug-ins, or the plug-in itself at specific times or events. Each plug-in is extended from one or more 3ds Max predefined base class. Each base class (and probably its parents) have a number of virtual methods that your plug-in must to implement in order to become functional. Usually these are pure virtual functions. Additional virtual methods are optional to be implemented depending on what your needs are and can improve the integration of your product with 3ds Max.