using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Win32.SafeHandles;

namespace WorkIndicator.Delcom
{
    internal sealed partial class HID
    {
        private const String ModuleName = "Hid";

        internal HidpCaps Capabilities;
        internal HiddAttributes DeviceAttributes;

        internal abstract class ReportIn
        {
            internal abstract void Read(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, ref Boolean myDeviceDetected, ref Byte[] readBuffer, ref Boolean success);
        }

        internal class InFeatureReport : ReportIn
        {
            internal override void Read(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, ref Boolean myDeviceDetected, ref Byte[] inFeatureReportBuffer, ref Boolean success)
            {
                try
                {
                    success = HidD_GetFeature(hidHandle, inFeatureReportBuffer, inFeatureReportBuffer.Length);

                    Debug.Print("HidD_GetFeature success = " + success);
                }
                catch (Exception ex)
                {
                    DisplayException(ModuleName, ex);
                    throw;
                }
            }
        }

        internal class InputReportViaControlTransfer : ReportIn
        {
            internal override void Read(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, ref Boolean myDeviceDetected, ref Byte[] inputReportBuffer, ref Boolean success)
            {
                try
                {
                    success = HidD_GetInputReport(hidHandle, inputReportBuffer, inputReportBuffer.Length + 1);

                    Debug.Print("HidD_GetInputReport success = " + success);
                }
                catch (Exception ex)
                {
                    DisplayException(ModuleName, ex);
                    throw;
                }
            }
        }

        ///  <summary>
        ///  For reading Input reports.
        ///  </summary>

        internal class InputReportViaInterruptTransfer : ReportIn
        {
            internal void CancelTransfer(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, IntPtr eventObject)
            {
                try
                {
                    //  ***
                    //  API function: CancelIo

                    //  Purpose: Cancels a call to ReadFile

                    //  Accepts: the device handle.

                    //  Returns: True on success, False on failure.
                    //  ***

                    FileIODeclarations.CancelIo(readHandle);

                    Debug.WriteLine("************ReadFile error*************");
                    //String functionName = "CancelIo";
                    //Debug.WriteLine(MyDebugging.ResultOfAPICall(functionName));
                    Debug.WriteLine("");

                    //  The failure may have been because the device was removed,
                    //  so close any open handles and
                    //  set myDeviceDetected=False to cause the application to
                    //  look for the device on the next attempt.

                    if ((!(hidHandle.IsInvalid)))
                    {
                        hidHandle.Close();
                    }

                    if ((!(readHandle.IsInvalid)))
                    {
                        readHandle.Close();
                    }

                    if ((!(writeHandle.IsInvalid)))
                    {
                        writeHandle.Close();
                    }
                }
                catch (Exception ex)
                {
                    DisplayException(ModuleName, ex);
                    throw;
                }
            }

            ///  <summary>
            ///  Creates an event object for the overlapped structure used with ReadFile. 
            ///  </summary>
            ///  
            ///  <param name="hidOverlapped"> the overlapped structure </param>
            ///  <param name="eventObject"> the event object </param>

            internal void PrepareForOverlappedTransfer(ref NativeOverlapped hidOverlapped, ref IntPtr eventObject)
            {
                try
                {
                    //  ***
                    //  API function: CreateEvent

                    //  Purpose: Creates an event object for the overlapped structure used with ReadFile.

                    //  Accepts:
                    //  A security attributes structure or IntPtr.Zero.
                    //  Manual Reset = False (The system automatically resets the state to nonsignaled 
                    //  after a waiting thread has been released.)
                    //  Initial state = False (not signaled)
                    //  An event object name (optional)

                    //  Returns: a handle to the event object
                    //  ***

                    eventObject = FileIODeclarations.CreateEvent(IntPtr.Zero, false, false, "");

                    //  Set the members of the overlapped structure.

                    hidOverlapped.OffsetLow = 0;
                    hidOverlapped.OffsetHigh = 0;
                    hidOverlapped.EventHandle = eventObject;
                }
                catch (Exception ex)
                {
                    DisplayException(ModuleName, ex);
                    throw;
                }
            }

            ///  <summary>
            ///  reads an Input report from the device using interrupt transfers.
            ///  </summary>
            ///  
            ///  <param name="hidHandle"> the handle for learning about the device and exchanging Feature reports. </param>
            ///  <param name="readHandle"> the handle for reading Input reports from the device. </param>
            ///  <param name="writeHandle"> the handle for writing Output reports to the device. </param>
            ///  <param name="myDeviceDetected"> tells whether the device is currently attached. </param>
            ///  <param name="inputReportBuffer"> contains the requested report. </param>
            ///  <param name="success"> read success </param>

            internal override void Read(SafeFileHandle hidHandle, SafeFileHandle readHandle, SafeFileHandle writeHandle, ref Boolean myDeviceDetected, ref Byte[] inputReportBuffer, ref Boolean success)
            {
                IntPtr eventObject = IntPtr.Zero;
                NativeOverlapped hidOverlapped = new NativeOverlapped();
                Int32 numberOfBytesRead = 0;

                try
                {
                    //  Set up the overlapped structure for ReadFile.

                    PrepareForOverlappedTransfer(ref hidOverlapped, ref eventObject);

                    // Allocate memory for the input buffer and overlapped structure. 

                    IntPtr nonManagedBuffer = Marshal.AllocHGlobal(inputReportBuffer.Length);
                    IntPtr nonManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(hidOverlapped));
                    Marshal.StructureToPtr(hidOverlapped, nonManagedOverlapped, false);

                    //  ***
                    //  API function: ReadFile
                    //  Purpose: Attempts to read an Input report from the device.

                    //  Accepts:
                    //  A device handle returned by CreateFile
                    //  (for overlapped I/O, CreateFile must have been called with FILE_FLAG_OVERLAPPED),
                    //  A pointer to a buffer for storing the report.
                    //  The Input report length in bytes returned by HidP_GetCaps,
                    //  A pointer to a variable that will hold the number of bytes read. 
                    //  An overlapped structure whose hEvent member is set to an event object.

                    //  Returns: the report in ReadBuffer.

                    //  The overlapped call returns immediately, even if the data hasn't been received yet.

                    //  To read multiple reports with one ReadFile, increase the size of ReadBuffer
                    //  and use NumberOfBytesRead to determine how many reports were returned.
                    //  Use a larger buffer if the application can't keep up with reading each report
                    //  individually. 
                    //  ***                    

                    success = FileIODeclarations.ReadFile(readHandle, nonManagedBuffer, inputReportBuffer.Length, ref numberOfBytesRead, nonManagedOverlapped);

                    if (!success)
                    {
                        Debug.WriteLine("waiting for ReadFile");

                        //  API function: WaitForSingleObject

                        //  Purpose: waits for at least one report or a timeout.
                        //  Used with overlapped ReadFile.

                        //  Accepts:
                        //  An event object created with CreateEvent
                        //  A timeout value in milliseconds.

                        //  Returns: A result code.

                        Int32 result = FileIODeclarations.WaitForSingleObject(eventObject, 3000);

                        //  Find out if ReadFile completed or timeout.

                        switch (result)
                        {
                            case FileIODeclarations.WaitObject0:

                                //  ReadFile has completed

                                success = true;
                                Debug.WriteLine("ReadFile completed successfully.");

                                // Get the number of bytes read.

                                //  API function: GetOverlappedResult

                                //  Purpose: gets the result of an overlapped operation.

                                //  Accepts:
                                //  A device handle returned by CreateFile.
                                //  A pointer to an overlapped structure.
                                //  A pointer to a variable to hold the number of bytes read.
                                //  False to return immediately.

                                //  Returns: non-zero on success and the number of bytes read.	

                                FileIODeclarations.GetOverlappedResult(readHandle, nonManagedOverlapped, ref numberOfBytesRead, false);

                                break;

                            case FileIODeclarations.WaitTimeout:

                                //  Cancel the operation on timeout

                                CancelTransfer(hidHandle, readHandle, writeHandle, eventObject);
                                Debug.WriteLine("Readfile timeout");
                                success = false;
                                myDeviceDetected = false;
                                break;
                            default:

                                //  Cancel the operation on other error.

                                CancelTransfer(hidHandle, readHandle, writeHandle, eventObject);
                                Debug.WriteLine("Readfile undefined error");
                                success = false;
                                myDeviceDetected = false;
                                break;
                        }

                    }
                    if (success)
                    {
                        // A report was received.
                        // Copy the received data to inputReportBuffer for the application to use.

                        Marshal.Copy(nonManagedBuffer, inputReportBuffer, 0, numberOfBytesRead);
                    }
                }
                catch (Exception ex)
                {
                    DisplayException(ModuleName, ex);
                    throw;
                }
            }
        }

        ///  <summary>
        ///  For reports the host sends to the device.
        ///  </summary>

        internal abstract class ReportOut
        {
            ///  <summary>
            ///  Each class that handles writing reports defines a Write method for 
            ///  writing a type of report.
            ///  </summary>
            ///  
            ///  <param name="reportBuffer"> contains the report ID and report data. </param>
            ///   <param name="deviceHandle"> handle to the device.  </param>
            ///  
            ///  <returns>
            ///   True on success. False on failure.
            ///  </returns>             

            internal abstract Boolean Write(Byte[] reportBuffer, SafeFileHandle deviceHandle);
        }

        ///  <summary>
        ///  For Feature reports the host sends to the device.
        ///  </summary>

        internal class OutFeatureReport : ReportOut
        {
            ///  <summary>
            ///  writes a Feature report to the device.
            ///  </summary>
            ///  
            ///  <param name="outFeatureReportBuffer"> contains the report ID and report data. </param>
            ///  <param name="hidHandle"> handle to the device.  </param>
            ///  
            ///  <returns>
            ///   True on success. False on failure.
            ///  </returns>            

            internal override Boolean Write(Byte[] outFeatureReportBuffer, SafeFileHandle hidHandle)
            {
                try
                {
                    //  ***
                    //  API function: HidD_SetFeature

                    //  Purpose: Attempts to send a Feature report to the device.

                    //  Accepts:
                    //  A handle to a HID
                    //  A pointer to a buffer containing the report ID and report
                    //  The size of the buffer. 

                    //  Returns: true on success, false on failure.
                    //  ***

                    Boolean success = HidD_SetFeature(hidHandle, outFeatureReportBuffer, outFeatureReportBuffer.Length);

                    Debug.Print("HidD_SetFeature success = " + success);

                    return success;
                }
                catch (Exception ex)
                {
                    DisplayException(ModuleName, ex);
                    throw;
                }
            }
        }

        ///  <summary>
        ///  For writing Output reports via control transfers
        ///  </summary>

        internal class OutputReportViaControlTransfer : ReportOut
        {
            ///  <summary>
            ///  writes an Output report to the device using a control transfer.
            ///  </summary>
            ///  
            ///  <param name="outputReportBuffer"> contains the report ID and report data. </param>
            ///  <param name="hidHandle"> handle to the device.  </param>
            ///  
            ///  <returns>
            ///   True on success. False on failure.
            ///  </returns>            

            internal override Boolean Write(Byte[] outputReportBuffer, SafeFileHandle hidHandle)
            {
                try
                {
                    //  ***
                    //  API function: HidD_SetOutputReport

                    //  Purpose: 
                    //  Attempts to send an Output report to the device using a control transfer.
                    //  Requires Windows XP or later.

                    //  Accepts:
                    //  A handle to a HID
                    //  A pointer to a buffer containing the report ID and report
                    //  The size of the buffer. 

                    //  Returns: true on success, false on failure.
                    //  ***                    

                    Boolean success = HidD_SetOutputReport(hidHandle, outputReportBuffer, outputReportBuffer.Length + 1);

                    Debug.Print("HidD_SetOutputReport success = " + success);

                    return success;
                }
                catch (Exception ex)
                {
                    DisplayException(ModuleName, ex);
                    throw;
                }
            }
        }

        ///  <summary>
        ///  For Output reports the host sends to the device.
        ///  Uses interrupt or control transfers depending on the device and OS.
        ///  </summary>

        internal class OutputReportViaInterruptTransfer : ReportOut
        {
            ///  <summary>
            ///  writes an Output report to the device.
            ///  </summary>
            ///  
            ///  <param name="outputReportBuffer"> contains the report ID and report data. </param>
            ///  <param name="writeHandle"> handle to the device.  </param>
            ///  
            ///  <returns>
            ///   True on success. False on failure.
            ///  </returns>            

            internal override Boolean Write(Byte[] outputReportBuffer, SafeFileHandle writeHandle)
            {
                try
                {
                    //  The host will use an interrupt transfer if the the HID has an interrupt OUT
                    //  endpoint (requires USB 1.1 or later) AND the OS is NOT Windows 98 Gold (original version). 
                    //  Otherwise the the host will use a control transfer.
                    //  The application doesn't have to know or care which type of transfer is used.

                    Int32 numberOfBytesWritten = 0;

                    //  ***
                    //  API function: WriteFile

                    //  Purpose: writes an Output report to the device.

                    //  Accepts:
                    //  A handle returned by CreateFile
                    //  An integer to hold the number of bytes written.

                    //  Returns: True on success, False on failure.
                    //  ***

                    Boolean success = FileIODeclarations.WriteFile(writeHandle, outputReportBuffer, outputReportBuffer.Length, ref numberOfBytesWritten, IntPtr.Zero);

                    Debug.Print("WriteFile success = " + success);

                    if (!((success)))
                    {

                        if ((!(writeHandle.IsInvalid)))
                        {
                            writeHandle.Close();
                        }
                    }
                    return success;
                }
                catch (Exception ex)
                {
                    DisplayException(ModuleName, ex);
                    throw;
                }
            }
        }

        ///  <summary>
        ///  Remove any Input reports waiting in the buffer.
        ///  </summary>
        ///  
        ///  <param name="hidHandle"> a handle to a device.   </param>
        ///  
        ///  <returns>
        ///  True on success, False on failure.
        ///  </returns>

        internal Boolean FlushQueue(SafeFileHandle hidHandle)
        {
            try
            {
                //  ***
                //  API function: HidD_FlushQueue

                //  Purpose: Removes any Input reports waiting in the buffer.

                //  Accepts: a handle to the device.

                //  Returns: True on success, False on failure.
                //  ***

                Boolean success = HidD_FlushQueue(hidHandle);

                return success;
            }
            catch (Exception ex)
            {
                DisplayException(ModuleName, ex);
                throw;
            }
        }

        ///  <summary>
        ///  Retrieves a structure with information about a device's capabilities. 
        ///  </summary>
        ///  
        ///  <param name="hidHandle"> a handle to a device. </param>
        ///  
        ///  <returns>
        ///  An HIDP_CAPS structure.
        ///  </returns>

        internal HidpCaps GetDeviceCapabilities(SafeFileHandle hidHandle)
        {
            IntPtr preparsedData = new IntPtr();

            try
            {
                //  ***
                //  API function: HidD_GetPreparsedData

                //  Purpose: retrieves a pointer to a buffer containing information about the device's capabilities.
                //  HidP_GetCaps and other API functions require a pointer to the buffer.

                //  Requires: 
                //  A handle returned by CreateFile.
                //  A pointer to a buffer.

                //  Returns:
                //  True on success, False on failure.
                //  ***

                HidD_GetPreparsedData(hidHandle, ref preparsedData);

                //  ***
                //  API function: HidP_GetCaps

                //  Purpose: find out a device's capabilities.
                //  For standard devices such as joysticks, you can find out the specific
                //  capabilities of the device.
                //  For a custom device where the software knows what the device is capable of,
                //  this call may be unneeded.

                //  Accepts:
                //  A pointer returned by HidD_GetPreparsedData
                //  A pointer to a HIDP_CAPS structure.

                //  Returns: True on success, False on failure.
                //  ***

                Int32 result = HidP_GetCaps(preparsedData, ref Capabilities);
                if ((result != 0))
                {
                    Debug.WriteLine("");
                    Debug.WriteLine("  Usage: " + Convert.ToString(Capabilities.Usage, 16));
                    Debug.WriteLine("  Usage Page: " + Convert.ToString(Capabilities.UsagePage, 16));
                    Debug.WriteLine("  Input Report Byte Length: " + Capabilities.InputReportByteLength);
                    Debug.WriteLine("  Output Report Byte Length: " + Capabilities.OutputReportByteLength);
                    Debug.WriteLine("  Feature Report Byte Length: " + Capabilities.FeatureReportByteLength);
                    Debug.WriteLine("  Number of Link Collection Nodes: " + Capabilities.NumberLinkCollectionNodes);
                    Debug.WriteLine("  Number of Input Button Caps: " + Capabilities.NumberInputButtonCaps);
                    Debug.WriteLine("  Number of Input Value Caps: " + Capabilities.NumberInputValueCaps);
                    Debug.WriteLine("  Number of Input Data Indices: " + Capabilities.NumberInputDataIndices);
                    Debug.WriteLine("  Number of Output Button Caps: " + Capabilities.NumberOutputButtonCaps);
                    Debug.WriteLine("  Number of Output Value Caps: " + Capabilities.NumberOutputValueCaps);
                    Debug.WriteLine("  Number of Output Data Indices: " + Capabilities.NumberOutputDataIndices);
                    Debug.WriteLine("  Number of Feature Button Caps: " + Capabilities.NumberFeatureButtonCaps);
                    Debug.WriteLine("  Number of Feature Value Caps: " + Capabilities.NumberFeatureValueCaps);
                    Debug.WriteLine("  Number of Feature Data Indices: " + Capabilities.NumberFeatureDataIndices);

                    //  ***
                    //  API function: HidP_GetValueCaps

                    //  Purpose: retrieves a buffer containing an array of HidP_ValueCaps structures.
                    //  Each structure defines the capabilities of one value.
                    //  This application doesn't use this data.

                    //  Accepts:
                    //  A report type enumerator from hidpi.h,
                    //  A pointer to a buffer for the returned array,
                    //  The NumberInputValueCaps member of the device's HidP_Caps structure,
                    //  A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.

                    //  Returns: True on success, False on failure.
                    //  ***                    


                    Int32 vcSize = Capabilities.NumberInputValueCaps;
                    Byte[] valueCaps = new Byte[vcSize];
                    HidP_GetValueCaps(HidPInput, valueCaps, ref vcSize, preparsedData);

                    //result = HidP_GetValueCaps(HidP_Input, ref valueCaps[0], ref Capabilities.NumberInputValueCaps, preparsedData); 

                    // (To use this data, copy the ValueCaps byte array into an array of structures.)                   

                }
            }
            catch (Exception ex)
            {
                DisplayException(ModuleName, ex);
                throw;
            }
            finally
            {
                //  ***
                //  API function: HidD_FreePreparsedData

                //  Purpose: frees the buffer reserved by HidD_GetPreparsedData.

                //  Accepts: A pointer to the PreparsedData structure returned by HidD_GetPreparsedData.

                //  Returns: True on success, False on failure.
                //  ***

                if (preparsedData != IntPtr.Zero)
                {
                    HidD_FreePreparsedData(preparsedData);
                }
            }

            return Capabilities;
        }

        ///  <summary>
        ///  Creates a 32-bit Usage from the Usage Page and Usage ID. 
        ///  Determines whether the Usage is a system mouse or keyboard.
        ///  Can be modified to detect other Usages.
        ///  </summary>
        ///  
        ///  <param name="capabilities"> a HIDP_CAPS structure retrieved with HidP_GetCaps. </param>
        ///  
        ///  <returns>
        ///  A String describing the Usage.
        ///  </returns>

        internal String GetHidUsage(HidpCaps capabilities)
        {
            String usageDescription = "";

            try
            {
                //  Create32-bit Usage from Usage Page and Usage ID.

                Int32 usage = capabilities.UsagePage * 256 + capabilities.Usage;

                if (usage == Convert.ToInt32(0X102))
                {
                    usageDescription = "mouse";
                }

                if (usage == Convert.ToInt32(0X106))
                {
                    usageDescription = "keyboard";
                }
            }
            catch (Exception ex)
            {
                DisplayException(ModuleName, ex);
                throw;
            }

            return usageDescription;
        }

        ///  <summary>
        ///  Retrieves the number of Input reports the host can store.
        ///  </summary>
        ///  
        ///  <param name="hidDeviceObject"> a handle to a device  </param>
        ///  <param name="numberOfInputBuffers"> an integer to hold the returned value. </param>
        ///  
        ///  <returns>
        ///  True on success, False on failure.
        ///  </returns>

        internal Boolean GetNumberOfInputBuffers(SafeFileHandle hidDeviceObject, ref Int32 numberOfInputBuffers)
        {
            try
            {
                Boolean success;
                if (!IsWindows98Gold())
                {
                    //  ***
                    //  API function: HidD_GetNumInputBuffers

                    //  Purpose: retrieves the number of Input reports the host can store.
                    //  Not supported by Windows 98 Gold.
                    //  If the buffer is full and another report arrives, the host drops the 
                    //  ldest report.

                    //  Accepts: a handle to a device and an integer to hold the number of buffers. 

                    //  Returns: True on success, False on failure.
                    //  ***

                    success = HidD_GetNumInputBuffers(hidDeviceObject, ref numberOfInputBuffers);
                }
                else
                {
                    //  Under Windows 98 Gold, the number of buffers is fixed at 2.

                    numberOfInputBuffers = 2;
                    success = true;
                }

                return success;
            }
            catch (Exception ex)
            {
                DisplayException(ModuleName, ex);
                throw;
            }
        }

        ///  <summary>
        ///  sets the number of input reports the host will store.
        ///  Requires Windows XP or later.
        ///  </summary>
        ///  
        ///  <param name="hidDeviceObject"> a handle to the device.</param>
        ///  <param name="numberBuffers"> the requested number of input reports.  </param>
        ///  
        ///  <returns>
        ///  True on success. False on failure.
        ///  </returns>

        internal Boolean SetNumberOfInputBuffers(SafeFileHandle hidDeviceObject, Int32 numberBuffers)
        {
            try
            {
                if (!IsWindows98Gold())
                {
                    //  ***
                    //  API function: HidD_SetNumInputBuffers

                    //  Purpose: Sets the number of Input reports the host can store.
                    //  If the buffer is full and another report arrives, the host drops the 
                    //  oldest report.

                    //  Requires:
                    //  A handle to a HID
                    //  An integer to hold the number of buffers. 

                    //  Returns: true on success, false on failure.
                    //  ***

                    HidD_SetNumInputBuffers(hidDeviceObject, numberBuffers);
                    return true;
                }
                //  Not supported under Windows 98 Gold.

                return false;
            }
            catch (Exception ex)
            {
                DisplayException(ModuleName, ex);
                throw;
            }
        }

        ///  <summary>
        ///  Find out if the current operating system is Windows XP or later.
        ///  (Windows XP or later is required for HidD_GetInputReport and HidD_SetInputReport.)
        ///  </summary>

        internal Boolean IsWindowsXpOrLater()
        {
            try
            {
                OperatingSystem myEnvironment = Environment.OSVersion;

                //  Windows XP is version 5.1.

                Version versionXP = new Version(5, 1);

                if (myEnvironment.Version >= versionXP)
                {
                    Debug.Write("The OS is Windows XP or later.");
                    return true;
                }
                
                Debug.Write("The OS is earlier than Windows XP.");
                return false;
            }
            catch (Exception ex)
            {
                DisplayException(ModuleName, ex);
                throw;
            }
        }

        ///  <summary>
        ///  Find out if the current operating system is Windows 98 Gold (original version).
        ///  Windows 98 Gold does not support the following:
        ///  Interrupt OUT transfers (WriteFile uses control transfers and Set_Report).
        ///  HidD_GetNumInputBuffers and HidD_SetNumInputBuffers
        ///  (Not yet tested on a Windows 98 Gold system.)
        ///  </summary>

        internal Boolean IsWindows98Gold()
        {
            try
            {
                OperatingSystem myEnvironment = Environment.OSVersion;

                //  Windows 98 Gold is version 4.10 with a build number less than 2183.

                Version version98Se = new Version(4, 10, 2183);

                Boolean result;
                if (myEnvironment.Version < version98Se)
                {
                    Debug.Write("The OS is Windows 98 Gold.");
                    result = true;
                }
                else
                {
                    Debug.Write("The OS is more recent than Windows 98 Gold.");
                    result = false;
                }
                return result;
            }
            catch (Exception ex)
            {
                DisplayException(ModuleName, ex);
                throw;
            }
        }

        ///  <summary>
        ///  Provides a central mechanism for exception handling.
        ///  Displays a message box that describes the exception.
        ///  </summary>
        ///  
        ///  <param name="moduleName">  the module where the exception occurred. </param>
        ///  <param name="e"> the exception </param>

        internal static void DisplayException(String moduleName, Exception e)
        {
            //  Create an error message.

            string message = "Exception: " + e.Message + "\r\n" + "Module: " + moduleName + "\r\n" + "Method: " + e.TargetSite.Name;

            //MessageBox.Show(message, caption, MessageBoxButtons.OK);
            Debug.Write(message);
        }
    }
}

