Author | Aaron |
Date | 19 Aug 2011 |
Version 11.08 of theZeolite plugin API for L3DT is a major revision that breaks backward compatibility with previous versions of both L3DT and the plugin API. That is to say, old plugins will not work with the new L3DT, and new plugins will not work with the old L3DT.
This update removes many idiosyncrasies and cuts out about five years of accumulated cruft in Zeolite, which had been backwards compatible until this point. Whilst these changes will make it easier to write new plugins, they will require existing plugins to be modified and recompiled. This tutorial explains how to update a plugin to Zeolite v11.08.
The first thing to note about the new version of Zeolite is that the core files have changed; 'CExtAPI.h', 'CExtAPI.cpp', and 'CExtAPI_defines.h' have been replaced by 'Zeolite.h', 'Zeolite.cpp' and 'Zeolite_defines.h'.
Furthermore, some sets of functions formerly included in the CExtAPI class have been spun out into separate files, including the project functions (in zProj.h/cpp), file helper functions (in zFile.h/cpp), menu functions (in zMenu.h/cpp) and view functions (in zView.h/cpp). If you use these functions, you will need to include these files in your project also.
In previous versions of the API, a set of calculation helper files were included in the 'calc' subdirectory. These have been moved into the 'helper' subdirectory, alongside the other various helper functions.
Additional helper files have been added, including variable type casting (in zVarCast.h/cpp), backup/restore functions (in zBackup.h/cpp), functions for reading/writing L3DT's XML settings files (in zXML.h/cpp), and several others.
The #include statements in the API files have been written with the assumption that you have added to your project's include paths the following directories:
The root directory for your project's source files (specifically, the folder containing 'stdafx.h' in MSVC projects.)
-
In the case of the 'ZeoScript' plugin, the include paths in the project configuration look like this (in MSVC 2008):
|
Include paths for the zeolite-based plugin 'ZeoScript'. |
In previous versions of Zeolite, API functions were accessed through the CExtAPI class and the one and only declared instance thereof, theAPI. In Zeolite v11.08, this class has been removed, and all functions have can be accessed directly. However, to avoid conflicts with functions from other libraries or code, Zeolite API function names have been prepended with 'z'. For example, the CExtAPI::format_GetFormatByExt function is now zformat_GetFormatByExt .
Hence, to update a plugin to Zeolite v11.08, find all instances of 'theAPI.' in your code and and replacing with 'z'. This replacement will account for most of the changes required to use Zeolite v11.08.
The error reporting functions CExtAPI::ReportError (which opens the event log) and CExtAPI::WriteToLog (which does not) have been renamed zeoReportError and zeoWriteToLog . A simple search and replace should be sufficient to change to the new scheme.
In previous versions of Zeolite, it was necessary to include your plugin's exported functions in the EXPORTS list of the module definition file (*.def) so that the functions were exported without name decoration or mangling. This is no longer necessary when using Zeolite v11.08 if functions are exported using the zeoexport keyword.
For example, using older versions of Zeolite you could export the a function called ExampleFunc by declaring it like so:
bool __stdcall ExampleFunc(ZVAR hReturnVar, ZLIST hArgList);
.. and then listing it in the module definition exports table thusly:
EXPORTS
; Explicit exports can go here
ExampleFunc @1
In Zeolite v11.08, the module definition file is no longer needed, and the function may instead be declared as:
zeoexport bool __stdcall ExampleFunc(ZVAR hReturnVar, ZLIST hArgList);
Functions declared with the zeoexport keyword may optionally be listed in the exports table, but it is unnecessary to do so.
In previous versions of Zeolite is was necessary to declare a function called ExtInitPlugin and include this in the exports table. In Zeolite v11.08 the name of this function has changed to zeoInitPlugin and the argument list has also changed:
New | zeoexport bool __stdcall zeoInitPlugin() |
Old | bool __stdcall ExtInitPlugin(FARPROC pFunc, LPVOID hID) |
Note that the function no longer takes any arguments. These were previously required to initialise the plugin API by calling the CExtAPI::InitAPI function from within the ExtInitPlugin function. This is no longer required (or possible), as L3DT now initialises the plugin API directly before calling zeoInitPlugin .
It was also previously necessary to list ExtInitPlugin in the exports table. This is no longer required, as the zeoexport keyword handles the name decoration and exporting of the zeoInitPlugin function.
A plugin's instance of the Zeolite API is initialised after the plugin is loaded into the process but before zeoInitPlugin is called. Hence, users must not call any Zeolite API functions before zeoInitPlugin is called.
In previous versions of Zeolite it was optional to include a function called ExtShutdown , which would be called before the plugin is unloaded, and may be used for cleaning up memory or releasing resources before the library is released from memory. In Zeolite v11.08, this function name has changed to zeoShutdown , and it should now be declared using the zeoexport keyword:
New | zeoexport void __stdcall zeoShutdown(void) |
Old | void __stdcall ExtShutdown(void) |
It was previously necessary to list ExtShutdown in the exports table. This is no longer required, as the zeoexport keyword handles the exporting and name decoration of the zeoShutdown function.
To load an save map files, plugins previously had to export one or more of the ExtSaveMapFile , ExtLoadMapFile , ExtSaveTileFile and ExtLoadTileFile functions, and these functions needed to be included in the plugin's EXPORTS table. For Zeolite v11.08, these functions must be been renamed zeoSaveMapFile , zeoLoadMapFile , zeoSaveTileFile and zeoLoadTileFile , they must be declared with the zeoexport keyword, and they do not need to be included in the EXPORTS table.
The old and new function prototypes are given below:
New | zeoexport bool __stdcall zeoSaveMapFile(ZMAP hMap, LPCSTR lpFileName, ZFORMAT hFormat, ZVAR hProgWnd); |
Old | bool __stdcall ExtSaveMapFile(ZMAP hMap, LPCSTR lpFileName, ZFORMAT hFormat, ZVAR hProgWnd); |
New | zeoexport bool __stdcall zeoLoadMapFile(ZMAP hMap, LPCSTR lpFileName, long MapTypeID, ZFORMAT hFormat, ZVAR hProgWnd); |
Old | bool __stdcall ExtLoadMapFile(ZMAP hMap, LPCSTR lpFileName, long MapTypeID, ZFORMAT hFormat, ZVAR hProgWnd); |
New | zeoexport bool __stdcall zeoSaveTileFile(ZMAP hMap, LPVOID hTile, LPCSTR lpFileName, ZFORMAT hFormat); |
Old | bool __stdcall ExtSaveTileFile(ZMAP hMap, LPVOID hTile, LPCSTR lpFileName, ZFORMAT hFormat); |
New | zeoexport bool __stdcall zeoLoadTileFile(ZMAP hMap, LPVOID hTile, LPCSTR lpFileName, ZFORMAT hFormat); |
Old | bool __stdcall ExtLoadTileFile(ZMAP hMap, LPVOID hTile, LPCSTR lpFileName, ZFORMAT hFormat); |
The CExtAPI::zeofunc_LoadFunc and CExtAPI::zeofunc_LoadFuncEx functions have been replaced by zfunc_Load . The function prototype and usage of zfunc_Load is otherwise identical to the old CExtAPI::zeofunc_LoadFuncEx function.
The function for adding menu items was changed from CExtAPI::menu_InsertItem2 to zmenu_InsertItem , which was moved to the 'zMenu.h/cpp' files, and the function prototypes are given below:
New | long zmenu_InsertItem(const char* lpScript, const char* lpItemText, unsigned long MenuContext, unsigned long Flags) |
Old | long CExtAPI::menu_InsertItem2(const char* lpFnName, const char* lpItemText, unsigned long MenuContext, unsigned long Flags) |
You will note that all the arguments are the same, except for the first (lpScript vs. lpFnName).
In previous versions of Zeolite, menu items could only be added as calls to a single extension function specified by lpFnName. In Zeolite v11.08, menu items now run complete script (specified by lpScript, and in the ZeoScript language), which may call multiple functions. To translate from lpFnName to lpScript, you only need to update the function name to include the full namespace for the function as loaded using zfunc_Load .
In previous versions of Zeolite, the following functions were used to create private variables, create shared variables, and retrieve handles to shared variables:
ZVAR CExtAPI::var_CreateTemp(long VarID) | Creates a private variable. |
ZVAR CExtAPI::var_Create(long VarID, const char* lpVarName) | Creates a shared variable. |
ZVAR CExtAPI::var_GetVar(const char* lpVarName) | Retrieves handle to shared variable. |
In Zeolite v11.08, these functions have been renamed to:
ZVAR zvar_Create(long VarID) | Creates a private variable. |
ZVAR zvar_CreateShared(long VarID, const char* lpVarName) | Creates a shared variable. |
ZVAR zvar_GetSharedVar(const char* lpVarName) | Retrieves handle to shared variable. |
These changes were made to reflect the observation that it is far more common to create private variables than it is to create shared variables. Consequently, this change marks the functions used to handle shared variables explicitly (zvar_CreateShared and zvar_GetSharedVar ), whilst the default function for creating variables is unadorned (zvar_Create ).
The difference between shared and private variables is that shared variables may be accessed by other plugins or by L3DT directly by using the zvar_GetSharedVar function, at any time, and without the knowledge or permission of the plugin that created the variable. In contrast, private variables may only be accessed by the handle returned by zvar_Create , which is given only to the plugin that creates the variable, and may only be used by other plugins if the creator plugin explicitly provides the variable handle to another plugin’s function.
In the very earliest versions of Zeolite, plugins could exchange data only by storing and retrieving shared variables. With the advent of extension functions in Zeolite v1.2, plugins could exchange data using a more controlled and functional mechanism. Consequently, shared variables have largely fallen into disuse.
All the file name helper functions previously included in the CExtAPI class (listed below) have been spun out to the 'zFile.h/cpp' files.
These functions have also been renamed; for instance the function for trimming the directory path from a filename has been renamed from CExtAPI::file_GetFilenameNoDir to zfile_TrimDir . All other file helper functions have been similarly renamed with a name prefixed by zfile_ . Importantly, the order of arguments for these functions have been changed so that the output result string (ZSTR hResult) is now the last argument, rather than the first. This means that a simple search-and-replace operation should not be performed for converting CExtAPI::file_ function calls to zfile_ function calls, because the operation will not change the argument order as required.
The prototypes of some of the more commonly-used file helper functions are listed below:
New | bool zfile_GetExt(const char* lpFileName, ZSTR hResult); |
Old | bool CExtAPI::file_GetExt(ZSTR hStr, const char* lpFileName); |
New | bool zfile_GetDir(const char* lpPathName, ZSTR hResult); |
Old | bool CExtAPI::file_GetDir(ZSTR hStr, const char* lpFileName); |
New | bool zfile_TrimExt(const char* lpFileName, ZSTR hResult); |
Old | bool CExtAPI::file_GetFilenameNoExt(ZSTR hStr, const char* lpFileName); |
New | bool zfile_TrimDir(const char* lpFileName, ZSTR hResult); |
Old | bool CExtAPI::file_GetFilenameNoDir(ZSTR hStr, const char* lpFileName); |
The CzComboSel , CzFileSel and CzSirSel classes are all conceptually similar, in that they all provide a simple user interface to allow users to select:
an item or combination of items from a list (combosel),
a file from a file selection window (filesel), and;
a directory from a directory selection window (dirsel).
However, they were implemented at different times, and their member function names were not entirely consistent. This has been fixed in Zeolite v11.08, as detailed below:
The CExtAPI::filesel_InitFS function was renamed zfilesel_Init , with no changes to arguments or return values.
The CExtAPI::filesel_GetFilename function was renamed zfilesel_GetPathA , the return type was changed to bool , and a ZSTR hReturnStr argument was added.
The function prototypes are given below:
New:
bool zfilesel_Init(ZVAR hFileSel, bool OpenFileFlag, const char* lpFileName, const char* lpFilterStr, const char* lpDefaultExt, const char* lpDefaultDir); |
bool zfilesel_GetPathA(ZVAR hFileSel, ZSTR hReturnStr); |
Old:
bool CExtAPI::filesel_InitFS(ZVAR hFileSel, bool OpenFileFlag, const char* lpFileName, const char* lpFilterStr, const char* lpDefaultExt, const char* lpDefaultDir); |
const char* CExtAPI::filesel_GetFilename(ZVAR hFileSel); |
Corresponding changes were made to the CzFileSel class.
The CExtAPI::dirsel_InitDS function was renamed zdirsel_Init , with no changes to arguments or return values.
The CExtAPI::dirsel_GetDirname function was renamed zdirsel_GetPathA , the return type was changed to bool , and a ZSTR hReturnStr argument was added.
The function prototypes are given below:
New:
bool zdirsel_Init(ZVAR hDirSel, const char* lpStartDir); |
bool zdirsel_GetPathA(ZVAR hDirSel, ZSTR hReturnStr); |
Old:
bool CExtAPI::dirsel_InitDS(ZVAR hDirSel, const char* lpStartDir); |
const char* CExtAPI::dirsel_GetDirname(ZVAR hDirSel); |
Corresponding changes were made to the CzDirSel class.
The function prototypes are given below:
New:
bool zcombosel_Init(ZVAR hComboSel, const char* lpOptionsStr, const char* lpCurSelStr); |
bool zcombosel_GetCurSelA(ZVAR hComboSel, ZSTR hReturnStr); |
bool zcombosel_SetCurSelA(ZVAR hComboSel, const char* lpCurSelStr); |
bool zcombosel_GetOptionsA(ZVAR hComboSel, ZSTR hReturnStr); |
bool zcombosel_SetOptionsA(ZVAR hComboSel, const char* lpOptionsStr); |
Old:
bool CExtAPI::combosel_InitCS(ZVAR hComboSel, const char* lpOptionsStr, const char* lpCurSelStr); |
const char* CExtAPI::combosel_GetCurSel(ZVAR hComboSel); |
bool CExtAPI::combosel_SetCurSel(ZVAR hComboSel, const char* lpCurSelStr); |
const char* CExtAPI::combosel_GetOptions(ZVAR hComboSel); |
bool CExtAPI::combosel_SetOptions(ZVAR hComboSel, const char* lpOptionsStr); |
Furthermore, two new functions were added to allow developers to get and set the current selection by index, rather than by text string. These functions are:
long zcombosel_GetCurSelI(ZVAR hComboSel); |
bool zcombosel_SetCurSelI(ZVAR hComboSel, long CurSelID); |
Corresponding changes were made to the CzComboSel class.
The functions for getting and setting the value of a variable using a text string have been renamed from CExtAPI::var_GetValueA and CExtAPI::var_SetValueA to zvar_GetValueText zvar_SetValueText . This change change is intended to make their purpose more obvious.
A major change in L3DT v11.08 is that the program now takes a more active role in map memory management. Previously, developers could call CExtAPI::map_Init to allocate an in-RAM map, or CExtAPI::map_InitMosaic to allocate a dynamically paged mosaic map. Now, to prevent memory exhaustion in projects with many large maps, L3DT may disregard the caller's preference and split 'large' maps allocated by zmap_Init into virtual mosaic maps, where 'large' is arbitrary, unspecified and subject to change. Virtual mosaic maps, when loaded into L3DT, function exactly like conventional mosaic maps, but are loaded from and saved to single map files, just like in-RAM maps.
You can determine how a map is allocated in memory using the zmap_GetAllocMode function, which returns the following possible values:
Symbol | Value (hex) | Description |
MAPALLOC_INVALID | 0x0 | The map is not allocated. |
MAPALLOC_RAM | 0x00000001 | The map is allocated in a contiguous block of RAM. |
MAPALLOC_MOSAIC | 0x00000002 | The map is allocated as a mosaic, and is saved to disk with a mosaic master file. |
MAPALLOC_MOSAIC_TEMP | 0x00000004 | The map is allocated as a mosaic map that is temporarily stored in the applications temp folder. When saved, the map will be written to a single map file, as with MAPALLOC_RAM maps. |
MAPALLOC_MOSAIC_SYSPAGEFILE | 0x00000010 | Same as MAPALLOC_MOSAIC_TEMP, but the mosaic is backed by the system pagefile. |
MAPALLOC_MOSAIC_MEMMAPFILE | 0x00000020 | Same as MAPALLOC_MOSAIC_TEMP, but the mosaic is backed by a large memory-mapped raw file. |
To force a particular type of memory allocation for a map, use the new zmap_Init2 function, the prototype of which is given below:
bool zmap_Init2(ZMAP hMap, long nx, long ny, long MapTypeID, float HorizScale, bool WrapFlag, unsigned long AllocMode, long TileSize);
This function is comparable to the zmap_Init function, but it also takes an argument AllocMode for the allocation mode (see table above), and an argument TileSize for the virtual mosaic tile size, if MAPALLOC_MOSAIC_TEMP, MAPALLOC_MOSAIC_SYSPAGEFILE or MAPALLOC_MOSAIC_MEMMAPFILE are selected.
Please note that the zmap_GetMosaicFlag function will return true if the map is split into tiles as a mosaic (MAPALLOC_MOSAIC) or virtual mosaic (MAPALLOC_MOSAIC_TEMP, MAPALLOC_MOSAIC_SYSPAGEFILE or MAPALLOC_MOSAIC_MEMMAPFILE), and false if the map is allocated as a single block of memory (MAPALLOC_RAM).
The 64-bit version of L3DT Professional requires plugins to be recompiled for the x64 architecture. No code changes should be required when recompiling a plugin in 64 bit mode, at least as far as using the plugin API is concerned. However, the output plugin file must have an extension of '.x64.zeo'.
Various other functions have been renamed slightly. Often this is due to the fact that the old deprecated functions have been finally removed from Zeolite, which has allowed the replacement functions to be renamed. For instance, the CExtAPI::map_GenMipmaps2 function, which previously replaced the defective CExtAPI::map_GenMipmaps function, has now become zmap_GenMipmaps . Another example is CExtAPI::menu_InsertItemEx , which is now zmenu_InsertItem . In most instances, unless noted elsewhere on this page, the replacement function name should be obvious by looking in the relevant header file (usually 'zeolite.h').
If you plugin uses scripts, it is likely that they will need to be updated also. The names of many script functions have been changed to better match those of the Zeolite API functions. Also, many file format related functions were moved into the 'file' namespace, whilst user interface related functions moved into the 'UI' namespace. To browse through the names of the available functions, I recommend you use the 'function browser' tool in the script editor.
If you find that this tutorial does not cover an important aspect of updating your plugin to Zeolite v11.08, please e-mail aaron@bundysoft.com for assistance.

|