This is an old revision of the document!
Developing a Noah Fitting Module Using .NET
Noah 3.0 Fitting Module
Module Installation
Installation types:
- External Setup Program: Registering the program using the module’s own Setup Program. (Required)
- Internal Setup Program: Registering the module using the Moduleinstall.ocx Component. (Optional)
Internal Setup
- Create an
install.ini
file. For a native Noah 2.0 fitting module:[MODULEINFO] MODULETYPE=FITTING MANUFCODE=044 MODULENAME=Audina ModuleFile=Fit044WM.exe HelpFile=FITTING.HLP LogoFile=Logo.DLL [INSTALLATION] InstallCmd=NhSetup.exe
- An
install.ini
file for a native Noah 3.0 fitting module:[Installation] ;InstallCmd=NhSetup.exe InstallCmd=installer.bat [Module Install] CLSID={241255F6-0B94-4EBE-993A-030A8A4968FE} Name=ezFIT 5 for NOAH Fitting Module HelpPath=HELP.HLP LocalID=1 LogoDLLPath=LOGO.DLL ManufacturerID=044 Category=Fitting CanMake=CanMakeSection CanShow=CanShowSection [CanMakeSection] 259,500 [CanShowSection] 259,500
And related
installer.bat
file:copy Release\*.exe %1 copy Release\*.dll %1 copy Release\vc\redist\*.dll %1 copy Release\vc\redist\Microsoft.VC80.MFC.manifest %1 copy Release\vc\redist\Microsoft.VC80.CRT.manifest %1 cd %1 FitMod.exe /regserver pause
External Setup Program
The module developer must program his own module setup program (for example, Setup.exe) to register module data with the Module Installation Server component.
- Installer should copy fitting module and related files to path…
- Register the fitting module interface (if native Noah 3.0 module):
C:\> C:\Program Files\HIMSA\Modules\Fitting\044>fitmod.exe /regserver
- Create a .NET 2.0 (or greater) application.
- Add COM reference to ModuleInstallationServer 1.0, which is file
C:\Program Files\Common Files\HIMSA Shared\ModuleInstallationServer.dll
. - Add
using ModuleInstallationServer;
at the top of the files using the Module Installation Server. - Create an instance of
ModuleInstServer
. Eg:using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using ModuleInstallationServer; namespace Nh3FitModInstall { public partial class frmMain : Form { ModuleInstServer ModuleInstServer1 = new ModuleInstServer(); public frmMain() { InitializeComponent(); } } }
- Add code to Install and Uninstall the fitting module. Eg:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using ModuleInstallationServer; namespace Nh3FitModInstall { public partial class frmMain : Form { ModuleInstServer ModuleInstServer1 = new ModuleInstServer(); public frmMain() { InitializeComponent(); } private void frmMain_Load(object sender, EventArgs e) { ModuleInstServer1.Initialize(); } private void btnInstallMod_Click(object sender, EventArgs e) { // create objects Module oMod = new Module(); DataTypes oDTs = new DataTypes(); DataType oDT = new DataType(); Protocols oProts = new Protocols(); Protocol oProt = new Protocol(); SubModule oSub = new SubModule(); try { // Set datatype that the module can make/show oDT.Code = 1; oDT.Format = 100; // Add datatype to collection oDTs.Add(oDT); // Set on-line protocol and related datatype that the module supports oProt.DataTypes = oDTs; oProt.Number = 1; oProts.Add(oProt); // Set submodule oSub.LocalID = 1; //oSub.ManufacturerID = 044; // 044=Audina, 001=HIMSA; oSub.ManufacturerID = Int16.Parse(txtManufCode.Text); // 044=Audina, 001=HIMSA; oMod.CanMake = oDTs; oMod.CanShow = oDTs; // ClassID of the module. Remember that the module must also have a valid ProgID entry. //oMod.CLSID = @"{444DA45F-3BE7-11D1-BAD1-07704FC9C2B9}"; // Noah Sample Module //oMod.CLSID = @"{241255F6-0B94-4EBE-993A-030A8A4968FE}"; // Audina Fitting Module (for native Noah 3.0 module) //oMod.CLSID = @"C:\Program Files\HIMSA\Modules\Fitting\044\FIT044WM.EXE"; // Audina Fitting Module (for native Noah 2.0 module) oMod.CLSID = txtModClassID.Text; //oMod.HelpPath = @"C:\Program Files\HIMSA\Modules\Fitting\044\FITTING.HLP"; oMod.HelpPath = txtModExeFile.Text; //oMod.KeyName := "NoKey"; oMod.LocalID = 2; // Manufacturer's internal Local Module Identifier //oMod.LogoDLLPath = @"C:\Program Files\HIMSA\Modules\Fitting\044\Logo044.dll"; // logo.dll oMod.LogoDLLPath = txtModLogoDll.Text; //oMod.ManufacturerID = 044; // 044=Audina, 1=HIMSA; oMod.ManufacturerID = Int16.Parse(txtManufCode.Text); // 044=Audina, 1=HIMSA; //oMod.Name = "The AudinaTestManuf Module"; // module name oMod.Name = txtModName.Text; // module name oMod.Protocols = oProts; // protocols used in Inter-module Communication (IMC) oMod.Show = true; // Set the module category using the ModuleInstallationServer collection of ModuleCategories oMod.Category = ModuleInstServer1.ModuleCategories.Item[1]; oMod.SubModules.Add(oSub); //ModuleInstServer1.InstallModule("AudinaTestManuf", oMod); ModuleInstServer1.InstallModule(txtManufName.Text, oMod); } catch (Exception exc){ MessageBox.Show(string.Format("Error: {0} {1}", exc.Source, exc.Message)); } //finally //{ // // destroy objects (in reverse order) // oSub = null; // oProt = null; // oProts = null; // oDT = null; // oDTs = null; // oMod = null; //} } private void btnUninstallMod_Click(object sender, EventArgs e) { try { ModuleInstServer1.UninstallModule( 044, // ManufCode assigned by HIMSA 2 // ModuleCode assigned by Manuf ); } catch (Exception exc){ MessageBox.Show(string.Format("Error: {0} {1}", exc.Source, exc.Message)); } } private void btnClose_Click(object sender, EventArgs e) { Close(); } } }
Module Development
Fitting Module Application (FitMod.exe)
This application launches the GUI Wrapper that will contain all the user controls with the actual application functionality.
- Create C++ MFC (Microsoft Foundation Class) application project.
- Build application.
- Register COM server by executing the generated executable file. It generates an error “This server can only be run from a container application.”, but just ignore it. Eg:
C:\> C:\Program Files\MyApp\FitMod.exe
This should create the following registry entries:
REGEDIT ; This .REG file may be used by your SETUP program. ; If a SETUP program is not available, the entries below will be ; registered in your InitInstance automatically with a call to ; CWinApp::RegisterShellFileTypes and COleObjectFactory::UpdateRegistryAll. HKEY_CLASSES_ROOT\FitMod.Document = FitMod.Document HKEY_CLASSES_ROOT\FitMod.Document\protocol\StdFileEditing\server = C:\Program Files\MyApp\FitMod.EXE HKEY_CLASSES_ROOT\FitMod.Document\protocol\StdFileEditing\verb\0 = &Edit HKEY_CLASSES_ROOT\FitMod.Document\Insertable = HKEY_CLASSES_ROOT\FitMod.Document\CLSID = {241255F6-0B94-4EBE-993A-030A8A4968FE} HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE} = FitMod.Document HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\DefaultIcon = C:\Program Files\MyApp\FitMod.EXE,1 HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\LocalServer32 = C:\Program Files\MyApp\FitMod.EXE HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\ProgId = FitMod.Document HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\MiscStatus = 32 HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\AuxUserType\3 = FitMod HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\AuxUserType\2 = FitMod HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\Insertable = HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\verb\1 = &Open,0,2 HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\verb\0 = &Edit,0,2 HKEY_CLASSES_ROOT\CLSID\{241255F6-0B94-4EBE-993A-030A8A4968FE}\InprocHandler32 = ole32.dll
GUI Wrapper (assembly Noah3.FitMod.GUI.dll)
- Create a C# WinForms project.
- Create a WinForms user control which will host the WPF GUI control. Eg:
///---------------------------------------------------------------------------------------- /// <summary> /// Click event handler for btnLoadWpfControl. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> ///---------------------------------------------------------------------------------------- private void btnLoadWpfControl_Click(object sender, EventArgs e) { boxAction.Visible = false; // hide previous controls LoadWpfUserControl(); // load fitting module usercontrol } ///---------------------------------------------------------------------------------------- /// <summary> /// Load and host a WPF user control in WinForms. /// Source: "Hosting a WPF Composite Control in Windows Forms" /// http://msdn.microsoft.com/en-us/library/ms745781.aspx /// </summary> ///---------------------------------------------------------------------------------------- private void LoadWpfUserControl() { try { // Create the ElementHost control for hosting the WPF UserControl. ElementHost host = new ElementHost(); host.Dock = DockStyle.Fill; // Create the WPF UserControl. ezFIT.ucMain uc = new ezFIT.ucMain(); // Assign the WPF UserControl to the ElementHost control's Child property. host.Child = uc; // Add the ElementHost control to the form's collection of child controls. this.Controls.Add(host); } catch (Exception exc) { //AHI.App.Logging.TAppLog.LogException("FitModControl.LoadWpfUserControl", exc); MessageBox.Show( string.Format("{0}(): Exception:\n\r {1}", "FitModControl.LoadWpfUserControl", exc), "Loading Fitting Module", MessageBoxButtons.OK, MessageBoxIcon.Error ); } }
- Structure code to deal with resources correctly when WPF is hosted in WinForms control (see Dr WPF: Managing Application Resources When WPF is Hosted).
GUI
- Create a C# WPF project.
- Add references to project:
AHI.App.Noah.dll
(Noah fitting module libraries)AHI.App.Resources.dll
(resource dictionary with all defined styles)
- Create a WPF user control with all the required functionality.
- If using custom styles, load them from
AHI.App.Resources.dll
- Register control or application with Noah Module Server. Typically the GUI control would call the AppViewModel to do so. Eg: The GUI code:
TAppViewModel AppVM = new TAppViewModel();
The
AppViewMode.cs
methods:///---------------------------------------------------------------------------------------- /// <summary> /// Constructor /// </summary> ///---------------------------------------------------------------------------------------- public TAppViewModel() { TAppLog.LogMessage("TAppViewModel.Constructor", "Start."); InitializeViewModel(); TAppLog.LogMessage("TAppViewModel.Constructor", "End."); } ///---------------------------------------------------------------------------------------- /// <summary> /// Initialize the view model, and register with Noah. /// </summary> ///---------------------------------------------------------------------------------------- private void InitializeViewModel() { if (m_ApplicationExecMode == TAppExecMode.Noah) { // Initialize the module server and register the module with module server. TAppLog.LogMessage("TAppViewModel.InitializeViewModel", "ApplicationExecMode = Noah."); TAppLog.LogMessage("TAppViewModel.InitializeViewModel", "Initializing NoahApp..."); m_NoahApp = new TNoahApp(); } else { TAppLog.LogMessage("TAppViewModel.InitializeViewModel", "ApplicationExecMode = Stand-alone."); } } ///---------------------------------------------------------------------------------------- /// <summary> /// Close the current view model with the purpose of closing application. /// </summary> ///---------------------------------------------------------------------------------------- public void cmdClose() { TAppLog.LogMessage("TAppViewModel.cmdClose", "Start."); if (m_ApplicationExecMode == TAppExecMode.Noah) { TAppLog.LogMessage("TAppViewModel.cmdClose", "ApplicationExecMode = Noah."); // Close the module server and unregister the module with module server. if (m_NoahApp != null) { TAppLog.LogMessage("TAppViewModel.cmdClose", "Calling NoahApp.cmdClose()..."); m_NoahApp.cmdClose(); } } else { TAppLog.LogMessage("TAppViewModel.cmdClose", "ApplicationExecMode = Stand-alone."); } TAppLog.LogMessage("TAppViewModel.cmdClose", "End."); }
Noah Fitting Module Library (assembly AHI.App.Noah.dll)
- Create Class (assembly) project.
- Add references to project:
ModuleServer
(COM server)
- Add all the Noah constants and methods that need Noah interaction, and make these available to the application.
- Methods:
InitializeNoahModServer()
: Instantiating the Module Server component, and registering the module with the Noah Module Server.WriteBinaryDataToFile()
: Write specified actions's public data (binary format) to file.GetActionByActionID()
: Retrieve an action from current session.cmdAddAction()
: Add an action into current session.cmdClose()
: Close the Noah Module Server.NhDisplayInfo()
: Display some NOAH parameters, to test whether it reads NOAH.AddPatient()
: Add a new Noah Patient record.SaveFitting()
: Save fitting to current Client's (Patient's) current session.GetCurrentPatient()
: Get current patient information.GetCurrentAction()
: Get current action information.