New Basic Example Plugin

This forum is for programmers who have questions about the source code.
Post Reply
ajhalls
Posts: 36
Joined: Fri Jan 10, 2014 1:41 pm
Location: Utah
Contact:

New Basic Example Plugin

Post by ajhalls » Wed Aug 19, 2020 12:39 pm

The default example plugin is really old, and while it has some great things in there, I had to comment out a ton to get it to compile.

Here is a new basic plugin in a single file that has the following features:
  • Gets current selected patient PatNum into `patient` variable.
  • Executes database queries
  • Converts results into DataTable
  • Basic Logging to a file
As it stands, when you click the button it shows a box that gives you the total number of patients. I added it to the OpenDental Solution, added the references for OpenDental, OpenDentBusiness, and DataConnectionBase. Set the build directory to be the bin\debug directory for the OpenDental project and you should be good.

The only part that annoys me, and surely someone will tell me how to fix it, is that you can't make this plugin a dependency of OpenDental so that it rebuilds every time you click "Start" for debugging, because it creates a circular reference. So I just right click the project and select "Build" before I start the debug session.

Just wanted to give someone a head start.

Code: Select all

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.IO;
using OpenDental;
using OpenDentBusiness;
using MySql.Data.MySqlClient;
using MessageBox = System.Windows.Forms.MessageBox;

///<summary>The namespace for this class must match the dll filename, including capitalization.
///All other classes will typically belong to the same namespace too, but that's not a requirement.</summary>
namespace PluginExample
{
    ///<summary>Required class.  Don't change the name.</summary>
    public class Plugin : PluginBase
    {
        public override void LaunchToolbarButton(long patNum)
        {
            var patient = FormOpenDental.CurPatNum;
            var results = Query("SELECT * FROM patient");
            MessageBox.Show("Total Patients: " + results.Rows.Count);
        }

        public static DataTable Query(string Query)
        {
            DataTable rawData = null;
            var ConnectionString = DataConnectionBase.DataConnection.GetConnectionString();
            using (var mySqlConnection = new MySqlConnection(ConnectionString))
            {
                try
                {
                    mySqlConnection.Open();
                }
                catch (MySqlException ex)
                {
                }
                catch (Exception ex)
                {
                }

                // Setting timeout on mysqlServer
                var timeoutAdjust = new MySqlCommand("set net_write_timeout=400; set net_read_timeout=400;use opendental;", mySqlConnection);
                timeoutAdjust.ExecuteNonQuery();

                using (DbCommand com = new MySqlCommand(Query, mySqlConnection))
                {
                    com.CommandTimeout = 400;
                    IDataReader reader = null;

                    using (reader = com.ExecuteReader())
                    {
                        var dtSchema = reader.GetSchemaTable();
                        rawData = QueryToDataTable(reader, dtSchema);
                    }
                }
                mySqlConnection.Close();
            }

            return rawData;
        }

        public static DataTable QueryToDataTable(IDataReader reader, DataTable dtSchema)
        {
            var listCols = new List<DataColumn>();
            var rawData = new DataTable();
            if (dtSchema != null)
                foreach (DataRow drow in dtSchema.Rows)
                {
                    var columnName = Convert.ToString(drow["ColumnName"]);
                    DataColumn column;
                    if ((Type)drow["DataType"] == typeof(System.Byte[]))
                    {
                        column = new DataColumn(columnName, typeof(String));
                    }
                    else
                    {
                        column = new DataColumn(columnName, (Type)drow["DataType"]);
                    }

                    column.Unique = false;
                    column.AllowDBNull = true;
                    column.AutoIncrement = false;

                    listCols.Add(column);
                    rawData.Columns.Add(column);
                }

            while (reader.Read())
            {
                var dataRow = rawData.NewRow();
                var columnCount = listCols.Count;
                for (var i = 0; i < columnCount; i++)
                {
                    if (reader[i].GetType() == typeof(System.Byte[]))
                    {
                        dataRow[listCols[i]] = BitConverter.ToString((byte[])reader[i]).Replace("-", "");
                    }
                    else
                    {
                        dataRow[listCols[i]] = reader[i];
                    }
                }

                rawData.Rows.Add(dataRow);
            }

            return rawData;
        }

        public static void WriteLine(string str = "", string FileName = @"Plugin.log", bool AccentItem = false)
        {
            if (AccentItem)
            {
                Console.WriteLine("\n");
            }

            Console.WriteLine(DateTime.Now + " [Info] " + str);

            if (AccentItem)
            {
                Console.WriteLine("\n");
            }

            try
            {
                using (var fs = File.Open(@"C:\OpenDental\head\OpenDental\bin\Debug\" + FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite,
                    FileShare.Delete | FileShare.ReadWrite))
                {
                    using (var reader = new StreamReader(fs))
                    using (var writer = new StreamWriter(fs))
                    {
                        //read
                        fs.Position = fs.Length;
                        writer.Write(DateTime.Now + " [Info] " + str + Environment.NewLine);
                        writer.Flush();
                        //write
                    }

                    fs.Close();
                }
            }
            catch (Exception e)
            {
                Trace.WriteLine("WriteLine - Error: " + e.Message);
            }
        }
    }
}
Dr. Alan Halls DMD
alan@reminderdental.com
ReminderDental.com - A new way to save

User avatar
jordansparks
Site Admin
Posts: 5755
Joined: Sun Jun 17, 2007 3:59 pm
Location: Salem, Oregon
Contact:

Re: New Basic Example Plugin

Post by jordansparks » Thu Aug 20, 2020 3:07 pm

No magic bullet, but here are a few ideas:
-There's a difference between build and rebuild
-I use a script in project/properties/build events/post-build. Example:
xcopy "$(TargetDir)Direct2dWrapper.dll" "..\OpenDental\bin\Debug\" /Y
which expands to :
xcopy "E:\Documents\OPEN DENTAL SUBVERSION\head\Direct2dWrapper\bin\Direct2dWrapper.dll" "..\OpenDental\bin\Debug\" /Y
So that doesn't build, but it does copy the dll to where it needs to be.
-It sounds like you already found Solution/Project Dependencies. I've never had a problem with a circular reference, but maybe that's because I'm not building plug-ins.
Jordan Sparks, DMD
http://www.opendental.com

ajhalls
Posts: 36
Joined: Fri Jan 10, 2014 1:41 pm
Location: Utah
Contact:

Re: New Basic Example Plugin

Post by ajhalls » Fri Aug 21, 2020 10:45 am

Thank you for the ideas. The batch file is a good idea, and I could write a command line compile command for the plugin to be part of the OpenDental project's build. Something like:

Code: Select all

"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe" "C:\OpenDentalPlugin\Plugin.sln" /t:Rebuild /p:Configuration=Debug /p:Platform="x86"
If you are open to the idea though, if there was a way through OpenDentBusiness to get the current patient, and access the GotoModule part of the OpenDental namespace, there would be less need to include the OpenDental namespace, which would then make it so developers could make their plugin a dependancy of OpenDental so it would compile automatically when changes were detected.

It isn't the biggest deal either way. From what I hear plugins aren't where you are focusing on right now, which I understand. I am grateful for what we can do.

=============
Update:
I tried the batch file idea as part of the pre-build routine and it doesn't work. As the original error said, it creates a circular reference.

However, I CAN add a command to the plugin's post build to run the OpenDental.exe. You won't get any debug output without external logging, but that is already part of what I posted.
Dr. Alan Halls DMD
alan@reminderdental.com
ReminderDental.com - A new way to save

Post Reply