9.7 Plugin Software Development Kit (SDK) | ![]() |
The plugin system is supported only by VEGA for
Windows. A plugin is a DLL that must be placed in the Plugin directory and it's
loaded automatically when VEGA starts. At the present time, the SDK is tested with Mingw
gcc and Borland C/C++ Builder, but it can works with other C compilers. A specific Fortran
SDK will be released as soon as possible.
This DLL must have three exported functions:
VGP_EXTERN VGP_PLUGINFO
* VGP_EXPORT Init(VGP_VEGAINFO
*);
VGP_EXTERN VG_BOOL VGP_EXPORT Free(void);
VGP_EXTERN VG_BOOL VGP_EXPORT Call(VG_UWORD, void *);
All definitions, constants and macros are included in plugin.h header file.
9.7.1 Function description
VGP_EXTERN VGP_PLUGINFO * VGP_EXPORT Init(VGP_VEGAINFO *)
It's the first function that VEGA calls in order to initialize the plugin. It must contain the initialization code for the plugin. VEGA passes the pointer to VGP_VEGAINFO structure in which are present some useful information:
typedef struct { VG_UWORD Version; /* VEGA version */ VG_UWORD Release; /* VEGA release */
VG_ULONG *GlobErr; /* Pointer to global error variable */ char *ErrStr; /* Pointer to error string */
ATOMO **BegAtm; /* Pointer to the pointer of the atom list */ ATOMO **LastAtm; /* Pointer to the pointer to the last atom */ VG_ULONG *TotalAtm; /* Pointer to the number of atoms variable */ VG_SURFACE **BegSrf; /* Pointer to the ponter of the surf. list */ char *Result; /* Pointer to the result string */ void *Custom; /* For custom plugin (don't use it !) */ void *Res1; /* Reserved pointer (don't use it !) */ void *Res2; /* Reserved pointer (don't use it !) */
HDC hDC; /* Device context of the main window */ HGLRC hRC; /* Rendering context of the main window */ HMENU hMenu; /* Handle of the main menu */ HMENU hPopUpMenu; /* Handle of the popup menu */ HWND hWnd; /* Handle of the main window */
char IniFile[MAX_PATH]; /* Plugin .ini file with full path */ char PrgPath[MAX_PATH]; /* Program path \ terminated */ } VGP_VEGAINFO;
Please remember that this structure is read-only and
the reserved pointers are for future use.
The user-defined plugin must return the pointer to the VGP_PLUGINFO structure that VEGA
manage it without writing anything.
typedef struct { VG_UWORD Version; /* Plugin version */ VG_UWORD Release; /* Plugin release */ VG_UWORD VegaVer; /* Minimum VEGA version required */ VG_UWORD VegaRel; /* Minimum VEGA release required */
VG_UWORD Type; /* Plugin type */ char *Name; /* Plugin name */ char *Copyright; /* Copyright message */
VGP_FUNC *FuncList; /* List of the functions */ } VGP_PLUGINFO;
In this structure you can specify the version and the release of the plugin, the minimum required version and release of VEGA (VegaVer and VegaRel), the plugin type (Type), the plugin name (Name), the copyright message (Copyright) and the the function list (FuncList).
The plugin type can be:
Value | Constant name | Description |
0 | VGP_TYPE_GENERIC | Generic plugin |
1 | VGP_TYPE_CALC | Calculation plugin |
2 | VGP_TYPE_CONSOLE | Console plugin |
3 | VGP_TYPE_RENDER | Rendering plugin |
4 | VGP_TYPE_CUSTOM | Custom plugin (for internal use only) |
At the present time, only the VGP_TYPE_GENERIC is available for the user.
The FuncList is a matrix in which is present an entry for each user function that VEGA can call.
typedef struct { char *MenuItem; /* Menu item string */ VG_UWORD MenuPos; /* Menu item to call the plugin function */ HBITMAP MenuBmp; /* 13x13 bitmap handle for menu icon */ VG_BOOL MenuEnabled; /* Set to TRUE to enable from the beginning */ VG_ULONG MenuAct; /* Menu activation */ VG_UWORD Function; /* Function code */ } VGP_FUNC;
MenuItem is the pointer to the string that is showed in the main menu that can be used to activate the specific function. VEGA calls the Call function using Function as argument. Function is the function code associated with the menu item. The reserved function codes are:
Value | Constant name | Description |
0 | VGP_FUNC_NONE | None |
1 | VGP_FUNC_ABOUT | About function (called when you press the About button in the plugin manager). |
2 | VGP_FUNC_CONFIG | Configure function (called when you press the Configure button in the plugin manager). |
3 | VGP_FUNC_HELP | Help function (called when you press the Help button in the plugin manager). |
The user functions must have a function code greater than 100 (e.g. 101, 102, etc) and no limits are present about the number of them.
MenuPos is the code that you can use to set the menu in which the item will be showed. The vertical position is selected by VEGA at the end of the standard menu item. The following tables shows the MenuPos values:
Value | Constant name | Menu name |
0 | VGP_MPOS_NONE | Invisible menu item |
1 | VGP_MPOS_EDIT | Edit |
2 | VGP_MPOS_VIEW | View |
3 | VGP_MPOS_CALC | Calculate |
4 | VGP_MPOS_TOOLS | Tools |
5 | VGP_MPOS_HELP | Help |
6 | VGP_MPOS_POPUP | Popup |
7 | VGP_MPOS_PLUGCFG | Plugin configuration submenu |
MenuBmp is the handle of the 13x13 bitmap
that is showed at the left of the item in the menu. If NULL, no bitmap is showed. A good
idea is to store the bitmap in the resources of the DLL.
Example:
In the .rc file:
MMPIC_USER01 BITMAP "icon_13.bmp" ...
The initialization code can be:
VGP_FUNC FuncList[] = { {"My function", VGP_MPOS_TOOLS, NULL, TRUE , VGP_CM_ALL , VGP_FUNC_USER_01},
/**** Don't delete the last line ****/
{NULL , VGP_MPOS_NONE , NULL, FALSE, VGP_CM_NONE, VGP_FUNC_NONE } };
...
PlugInfo.FuncList[1].MenuBmp = LoadBitmap(GetModuleHandle("MyPlugin.dll"), MAKEINTRESOURCE(MMPIC_USER01)); ...
If MenuEnabled is TRUE (0), the menu item is already enabled when VEGA starts. If it's FALSE (0), the item is disabled. The activation can be changed trough MenuAct variable. The following table shows the activation conditions:
Value | Constant name | Condition |
0 | VGP_CM_NONE | Never |
1 | VGP_CM_NEW | The New command is executed |
2 | VGP_CM_MOLE | The molecule is loaded |
4 | VGP_CM_DEMO | The demo mode is activated |
8 | VGP_CM_CALC | A calculation is performed |
16 | VGP_CM_SURF | A surface is loaded |
32 | VGP_CM_TRJA | The trajectory analysis is atarted |
You can combine more than one condition using the or operator (e.g. VGP_CM_NEW|VGP_CM_MOLE). If you want the item always enable, use the special VGP_CM_ALL constant.
IMPORTANT:
Please remember to end the VGP_FUNC array with a null item, because it's used by
VEGA to detect the last item.
VGP_EXTERN VG_BOOL VGP_EXPORT Free(void)
This function is called by VEGA to release all resources when the program is closing. In this subroutine you can include all code to free the resources that are used by your plugin.
VGP_EXTERN VG_BOOL VGP_EXPORT Call(VG_UWORD, void *)
It's the core of the plugin because this function select the code associated with a specificmenu item. When you select a plugin menu item or press a button in the plugin manager, VEGA calls this subroutine passing the function code and a void pointer that is reserved for future uses. A generic Call function can be:
/**** Generic Call function ****/ VGP_EXTERN VG_BOOL VGP_EXPORT Call(VG_UWORD Func, void *Arg) { switch(Func) { case VGP_FUNC_ABOUT: /* About the plugin */ printf("About\n"); break; case VGP_FUNC_CONFIG: /* Configure the plugin */ printf("Configuration\n"); break; case VGP_FUNC_HELP: /* Show the help */ printf("Help\n"); break; case VGP_FUNC_USER_01: /* Activate the first function */ printf("Function 1 activated\n"); break; /**** If needed, you can insert other cases ****/ } /* End of switch */ return TRUE; }
The Call function should return a value: TRUE (1) if it's executed without errors, FALSE (0) if an error occurs.
9.7.2 How to read/write the atom list
VEGA stores the atom information in a memory list.
Each atom has a its memory space allocated with calloc() function and each atom structure
has the pointer to the next. Thus the list can be scanned only in one direction: from the
first to the last atom. The end signal of the structure is the pointer to next atom
structure that is null. In the VGP_VEGAINFO structure you can find the pointer to the
pointer to the first element in the atom list (**BegAtm), the pointer to the
pointer to the last element (**LastAtm) and the pointer to the total number of
atoms in memory (*TotalAtm).
This is a simple code to read the atom list:
VGP_VEGAINFO *VgInfo; /* Initialized by Init() */
void MyReadAtm(void) { ATOMO *Atm;
for(Atm = *VgInfo -> BegAtm; Atm; Atm = Atm -> Ptr) { /* Print the atom name and the coordinates */ printf("%4.4s %f %f %f\n", Atm -> Name.C, Atm -> x, Atm -> y, Atm -> z); } }
For more information about the ATOMO structure, see the vgtypes.h header file.
9.7.3 How to add atoms in the list
To add an atom at the end of the list, follow these steps:
- Allocate the memory with the size of the ATOMO
structure using calloc() function (or compatible). The memory must be zero-filled.
- Put the data in the structure (atom name, element, coordinates, etc).
- Set the atom number using LastAtm -> Num +1.
- Bind the new atom with the last atom setting LastAtm -> Ptr with the pointer to the
allocated memory.
- Set LastAtm with the pointer to the allocated memory.
The following example allocates an atom and set the default values:
VGP_VEGAINFO *VgInfo; /* Initialized by Init() */
ATOMO *AllocAtm(void) { ATOMO *Atm; if ((Atm = (ATOMO *)calloc(sizeof(ATOMO), 1))) { if (!*VgInfo -> TotalAtm) *VgInfo -> BegAtm = Atm; else *(VgInfo -> LastAtm) -> Ptr = Atm; ++*VgInfo -> TotalAtm; *(VgInfo -> LastAtm) = Atm; /* Bind into the list */ Atm -> ResName.L = *(VG_LONG *)"UNK\0"; /* Unknown residue name */ *Atm -> ResSeq.C = '1'; /* Residue one */ Atm -> ChainID = ' '; /* Default chain */ Atm -> Num = ++*VgInfo -> TotalAtm; /* Sequential atom number */ *Atm -> Elem.C = '?'; /* Unknown element */ *Atm -> Pot.C = '?'; /* Unknown potential */ Atm -> Rad = 1.8; /* Atomic radius */ Atm -> ColorID = VGCOL_WHITE; /* White color (see vgtypes.h) */ Atm -> Active = 1; /* Active */ } return Atm; }
Remember to set the Active flag to 1, otherwise the atom will be invisible.
9.7.4 How to remove an atom in the list.
1. The atom is the first in the list:
- Set BegAtm with the pointer to the next atom.
- Free the memory with free(),
2. The atom isn't the first:
- Find the previous atom.
- Set the its Ptr to the next atom.
- Free the memory.
Remember to decrease TotalAtm of one for each atom removed.
9.7.5 How VEGA can be controlled by a plugin
VEGA can be controlled by a plugin using the standard windows messaging system. You can use this simple subroutine:
VGP_VEGAINFO *VgInfo; /* Initialized by Init() */
/**** Send a VEGA command ****/ VG_ULONG SendVegaCmd(char *Com) { COPYDATASTRUCT Cds; Cds.dwData = 0; Cds.lpData = (void*)Com; Cds.cbData = strlen(Com) + 1; return SendMessage(VgInfo -> hWnd, WM_COPYDATA, NULL, (LPARAM)&Cds); }
The argument is the string of the command to send to VEGA. If the command fails, the function return the global error code, otherwise return 0. If the sent command returns a value, you can read it trough the Result string pointer in VGP_VEGAINFO structure.
9.7.6 Saving/loading the plugin configuration
As convention, the plugin configuration should be loaded and saved in Plugins\Plugins.ini file. To manage this file, use the GetPrivateProfileString() and WritePrivateProfileString() API functions.
9.7.7 The null plugin
This is a simple example of a plugin that performs anything but is useful as skeleton to build your plugin.
/******************************************** **** VEGA Plugin System **** **** Main code **** **** Copyright 2002, Alessandro Pedretti **** ********************************************/ #include "..\plugin.h" /**** Global variables ****/ VGP_VEGAINFO *VgInfo; /**** Description of the functions ****/ /**** All items are optional ****/ VGP_FUNC FuncList[] = { {NULL , VGP_MPOS_NONE , NULL, TRUE , VGP_CM_NONE, VGP_FUNC_ABOUT }, {"Null Config.", VGP_MPOS_PLUGCFG, NULL, TRUE , VGP_CM_ALL , VGP_FUNC_CONFIG }, {"Null Help" , VGP_MPOS_HELP , NULL, TRUE , VGP_CM_ALL , VGP_FUNC_HELP }, {"Start Null" , VGP_MPOS_EDIT , NULL, FALSE, VGP_CM_MOLE, VGP_FUNC_USER_01}, /**** Don't delete the last line ****/ {NULL , VGP_MPOS_NONE , NULL, FALSE, VGP_CM_NONE, VGP_FUNC_NONE } }; /**** Plugin info structure ****/ VGP_PLUGINFO PlugInfo = { 1, /* Plugin version */ 0, /* Plugin release */ 1, /* Minimum VEGA version required */ 4, /* Minimum VEGA release required */ VGP_TYPE_GENERIC, /* Plugin type */ "Null", /* Plugin name */ "Alessandro Pedretti", /* Copyright message */ FuncList /* List of the functions */ }; /**** Plugin initialization ****/ VGP_EXTERN VGP_PLUGINFO * VGP_EXPORT Init(VGP_VEGAINFO *VegaInfo) { VgInfo = VegaInfo; /* Enter here your initialization code */ /* if needed. */ printf("Null: Initialization\n"); return &PlugInfo; } /**** Execute the plugin function ****/ VGP_EXTERN VG_BOOL VGP_EXPORT Call(VG_UWORD Func, void *Arg) { switch(Func) { case VGP_FUNC_ABOUT: /* About the plugin */ printf("Null: About\n"); break; case VGP_FUNC_CONFIG: /* Configure the plugin */ printf("Null: Configuration\n"); break; case VGP_FUNC_HELP: /* Show the help */ printf("Null: Help\n"); break; case VGP_FUNC_USER_01: /* Activate the first function */ printf("Null: Activated\n"); break; } /* End of switch */ return TRUE; } /**** Deallocate the resources ****/ VGP_EXTERN VG_BOOL VGP_EXPORT Free(void) { printf("Null: Release all resources\n"); return TRUE; }
You can find a more complex example in the Dhrystone plugin source code, included in the present SDK.