Home User Manual Discussion Forum Search

Plug-in Framework

Outside developers are able to maintain their own dll's.  They can publish them, sell them, or keep them private.  Plug-ins are an extension of the Program Links framework, so a button can be placed at the top of any module.

Hooks
In addition to the obvious buttons from Program Links, any number of hooks are allowed. We will add hooks wherever any programmer needs them. We add them quickly and we backport them to the beta version so you can get going right away.  Once we define a hook and what information it will pass, a plug-in can start to make use of it.     We expect there to eventually be hooks in thousands of locations throughout the program.  Almost anything can be done with hooks and plug-ins that can be done by directly altering the main program. 

Database
A plug-in can connect to the database through the framework and does not need to manage database connection info.  If the plug-in makes use of extra database tables, the plug-in dll needs to create and manage those tables.  If a developer is releasing a plug-in for others to use, they will probably want to maintain multiple versions, one for each minor release.

Limitations
- Plug-ins should still not make changes to existing database tables.   Plug-ins will have to use their own tables instead.
- Plug-ins should not extend existing enumerations.  We don't yet have a good idea how to accomplish extending enumerations.  Because they are database related, it might not ever be possible.
- Security permissions should be extensible so that plug-ins can add their own permissions if needed.
- Plug-ins have not been designed and tested to work with our Web Service framework. They will only work with direct connection, and plugins will not load if connected through the web service.  This may change if there is any serious interest in such plug-ins.

Security
Only an administrator can enable a plug-in. This avoids the potential problem of malicious plug-ins being created to hack the database. Because plug-ins will not work with our Web Service, the security will not be acceptable for enterprise situations. The plug-in framework will have to be enhanced later for enterprises.

Example - Simple Installation
This is a very quick way to download the example without needing to have any programming skills.  It only works with version 6.8 which has not been released.

1. Download this file:
https://70.90.133.65:23793/svn/opendental/PluginExample/bin/Debug/PluginExample.dll
and save it in the C:\Program Files\OpenDental\ folder.

2. In the Main Menu, Setup, Program Links, add a new program link and fill it out as shown below

3. Restart Open Dental.

Example - Complex Installation
These instructions are for programmers who are ready to start building their own functionality.

1: Download the PluginExample solution (https://70.90.133.65:23793/svn/opendental/PluginExample/) using Tortoise.  Put the PluginExample folder in a folder next to the head folder, just like it is in our Subversion folder organization.

2: Open the solution (.sln file).  You may get errors about some projects not being found.

3: To fix the errors, remove both the OpenDental project and the OpenDentBusiness project by right clicking on them in the VS Solution explorer.  Then, right click on the solution and add existing projects.  Browse to ...head\OpenDental\OpenDental.csproj, and add it.  Also, browse to ...head\OpenDentBusiness\OpenDentBusiness.csproj, and add it.

4: In Solution explorer, expand the PluginExample project, References folder.  Verify that the references to OpenDental and OpenDentBusiness do not have red exclamations beside them indicating that they would be broken.  If the references are broken, remove them and add back references to those two projects.

5: In Solution explorer, right click on the project, Edit Properties.  Go to the Build Events tab, and edit the post-build event command line.  Carefully fix the absolute path to the batch file that is included with the example.

6: Find the batch file using Windows explorer.  Right click, edit.  Carefully fix the absolute paths contained within it.

7: Try to build.  If no errors, PluginExample.dll will now be found in the debug folder of OpenDental.

8. Set the Open Dental project to be the startup project (right click). 

9. Enable the plugin by adding a Program Link as described above.

Features in the Example
If the example is installed as described above, the following features should be functional:

1. Patient edit window replaced with an alternate.  It's an obvious switch.  The new one has only one field in it, but that field is fully editable.

2. In Account module, hover over the "Family Aging" label at the upper left to see a floating pane with an insurance breakdown in it.  The info in that pane is entirely under the control of the plugin.

3. (newly added) In the Chart module patient info grid, all referrals show instead of just referred from.  Unfortunately, the replaced edit window makes it hard to test this feature.  You may need to turn off the plugin, set up the referrals, then turn the plugin back on to see the effect.

4. A database table will be created and plug-in version managed.

5. Pushing the toolbar button for the plug-in launchs a form.

Hints for Programmers
When using a plug-in, some things are done a little differently

1. To access the private controls on an existing form from outside the form, look through the public Controls property as shown in the posted example.

2. Your new classes will have static methods that get called from the plug in.  One option for implementing the other necessary members of the class that don't get called directly from the plugin is to use the singleton pattern.  As in the example, a static instance of the class is stored within itself.  All the non-static members in the class can then be accessed through that instance. Pay attention to static vs. non-static if you do this.  It's a little trickier than in the main program.

3. More of your methods and variables will probably be public.

4. If managing your own database tables, remember that the plug-in may be turned off and then turned back on a few versions later.  So you can't depend on the same pref that tracks database version.  You will have to store your own database version pref.  If you add rows to the preference table, be sure that they are very very unique.  Make sure to prefix them with a string that would be impossible for us to accidentally duplicate, as we did in the example.

Parameters
(first, read Plug-in Patterns)
The first parameter is always the sending form or class.  Any changes to the sender from within the plug-in code will affect the the original sending form or class.

Subsequent parameters are passed in as objects.   The object types and positions are not checked at compile time, and errors are instead found by testing.  Because they are all passed in as objects, all value types are boxed.  Value types include int, bool, etc.  If the plug-in attempts to alter the value of a value type variable, the new value will not be reflected in the main program.  Reference types include classes, strings, etc.  If the value of a reference type is altered in the plug-in, then it will change the original object in the main program.  The exception to this is if the object is set to new inside the plug-in.

Suggestions may be posted at some point on how to handle value type variables when you wish the changed value to persist after the hook is run.  It will probably involve manually boxing the variable in an object before passing it in.

Dll Naming
If the dll includes a double underscore (__) in its name, then it will be excluded from the file copy routine during an update.  This allows the developer of a plugin to control their own file distribution.

Usually in combination with the above technique, there is also a trigger available that will load a recently distributed dll.  To turn on the trigger, use [VersionMajMin] in the plugin name.  For example, the plugin might be entered as MyPlugin[VersionMajMin].dll.  The bracketed section will be removed when loading the dll.  So it will look for MyPlugin.dll as the dll to load.  However, before it loads, it will look for a similar dll with a version number.  For example, if using version 7.1.13, it would look for MyPlugin7.1.dll.  If that file is found, it would replace MyPlugin.dll with the contents of MyPlugin7.1.dll, and then it would load MyPlugin.dll as normal.  In a typical setting, this copy sequence gets triggered every time Open Dental starts up, ensuring a fresh copy of the dll.   If Open Dental is on a newer version, and the dll is still on an older version with no matching [VersionMajMin], then Open Dental will attempt to load the old dll.

However, using the above two strategies is not necessary for most developers.  There is normally no reason to exclude your dll from the file copy routine during an update.  And you can assign a version number to a dll without changing the name of the file.

Update Sequence
The normal behavior of Open Dental is as follows:
- Any workstation may initiate a version update.
- The Workstation Shutdown window is displayed to the user. When user clicks Continue, a row is inserted into the Signal table telling the Open Dental programs running on the other workstations to shut themselves down.
- preference.UpdateInProgressOnComputerName is set to the name of the computer that initiated the update.  This locks other users out.
- Setup.exe is downloaded and run automatically.
- User manually starts up Open Dental again.
- Sometimes, especially if jumping to a new major or minor version, a database update will automatically run.  Not common for a build update.
- Open Dental will recognize that a new version is installed by comparing with preference.ProgramVersion.
- The entire AtoZ\UpdateFiles folder is deleted.  If it can't delete the folder for some reason, the user will be informed, and Open Dental will exit.
- A fresh UpdateFiles folder is created.
- All files are copied from the current application folder to the UpdateFiles folder except:  FreeDentalConfig.xml, OpenDentalServerConfig.xml, any file that starts with 'openlog', and any file containing a double underscore (__).  Also, folders are not copied.
- Manifest.txt file created in UpdateFiles folder.  Contents are very simple. For example: 7.2.5
- preference.ProgramVersion updated to new version.
- preference.UpdateInProgressOnComputerName set to empty string.  This allows other workstations to connect.
- When another workstation connects, it recognizes that preference.ProgramVersion does not match.
- It checks Manifest.txt to see if the files for the needed version are available.
- If the version in Manifest.txt matches, then UpdateFileCopier.exe is launched and OD closes.
- UpdateFileCopier copies all files from UpdateFiles folder into its own application directory, including OpenDental.exe and UpdateFileCopier.exe.
- OpenDental is automatically launched, and UpdateFileCopier automatically shuts down.
- Because preference.ProgramVersion now matches, OD starts up normally.

 

Open Dental Software 1-971-239-1150