Client Management Suite

 View Only

Altiris Custom Inventory... Re-dux Edition 

Aug 22, 2007 02:27 PM

Here's another option that can help you tackle that beast we all call custom inventory. And what a beast it is, like something straight outta Compton... I mean Star Wars... This is a pretty old applet, but it works and gets the job done, with a few kinks here and there. Caveat Emptor... Altiris-eat Emptor as well.

Overview

The ocx is the primary component. It is written so that it can be used within a regular application by using it as a child control within a dialog, or as a web control by using it on an HTML page.

The purpose of the ocx is to provide a user-friendly visual front-end to the CustInv program. The CustInv program retrieves inventory from a machine based on an XML input file. The ocx creates the XML based on the selections the user makes in the ocx.

Architecture.

The workings of the ocx are actually contained in a simple Cdialog based dialog. The ocx serves only as a wrapper to the dialog. The only real work the ocx does is to act as a registration agent. Beyond that, any activity is performed by the dialog. The ocx creates an instance of the dialog at startup, then only intervenes in a few cases:

  1. OnDraw: The ocx's OnDraw function merely performs a MoveWindow on the dialog which serves to size the dialog to the same coordinates as the ocx control. The dialog takes up the entire ocx window.
  2. PreTranslateMesage: The ocx's PreTranslateMessage inspects for accelerator keys and passes them on to the dialog for handling.

So at this point the ocx architecture looks like the following:

Main Dialog Architecture.

The majority of the work is performed from within the Main Dialog. The main dialog does not know (or care) that it is wrapped by an ocx. It has no child-parent interaction. The only interaction comes from the parent (ocx) in the form of the 2 handlers described above.

The main dialog is a CHILD dialog and is resizable. It is derived from a custom resizing class that handles more than just resizing. It also handles the dynamic repositioning of the controls on the dialog. If the dialog grows, the controls on the dialog also grow and vice versa.

There are 3 primary controls on the main dialog:

  1. The top menu, which is not really a menu, it just appears as one. It is really just a series of static controls. The static controls recognize MOUSEOVER events and OnClick they present a popup menu the way a regular menu system would.
  2. The Tree Control. This is where the user will create and adjust the individual elements of the xml. The user will see these elements as icons and be able to copy, paste and move these elements to adjust the final xml output.
  3. The Tabbed control. This is a series of tabs, each owning a child dialog that will present the data represented by the tab.

Main Dialog Controls

As described above, the main dialog has 3 primary controls.

Top Menu

The top menu consists of several static text fields that look and act as regular menus. The static controls respond to mouse clicks the same way regular menus do: by presenting a popup menu. The texts of these menu items are initially blue, but upon MOUSEOVER they turn to white. Then back to their original color when the mouse leaves them.

File.
  New...
  Open...
  Close...
  ------------
  Save...
  SaveAs...
  ------------
  Exit

Options.
  Preferences...

Help.
  Contents
  ------------
  About...

Tree Control

The tree control is a standard CtreeCtrl and contains a visual representation of the xml that will serve as input to the CustInv program. The tree allows the user to create, edit and delete 1 or more complete queries. The user can then save selected (or all) the queries to a disk file for later use, distribution, etc.

The tree control will respond to user right-clicks by presenting a popup context menu containing choices that are appropriate for the selected tree item. Some items will be grayed out, some will be added, some deleted etc. The complete popup menu contains the following structure:

New ->
  Query...
  Group...
  Field...
  Statement ->
      If...
      ForEach...
      Set...
      Write...
====
Delete
=====
<Item Specific choices added as needed>

Tabbed Control

The tabbed control presents several dialogs related to the tree control contents.

  1. Properties: This dialog shows the properties of any selected tree item. This tab actually controls several dialogs, presenting the appropriate dialog based on the type of tree item selected by the user. The user will only ever see 1 dialog on this tab. There will be a unique dialog for each tree type in the tree. The tabbed control will manage which "Detail" dialog to present to the user based on the selected tree item.

    The individual dialogs presented in the properties tab will be the same dialogs, using the same dialog class and template, as the dialog presented to the user when creating a new tree item. The only difference will be that the dialog will appear as a child dialog in the tab control and will have its fields set to read-only. Only by double-clicking the selected tree item or right-clicking and selecting the "Edit" option will the user be able to edit the properties.

  2. XML: This dialog will show the user what the resulting XML will look like based on the items they have created/edited in the tree. This will be a read-only edit field, allow the user to view and copy/paste, but not directly alter.
  3. Tools: This dialog will present the user with a listing of various tools that can be applied to the current tree, such as exporting, running CustInv, etc.

So at this point the ocx architecture looks like the following:

OCX
  Main Dialog
  
    Menu (static text fields)

    Tree Control

    Tabbed Control

      XML Dialog 

      Tools Dialog

      Details Dialog(s) (Series of dialogs swapped in and out at runtime)

        Tree item type 1 dialog
        Tree item type 2 dialog
        Etc....

The ocx CLASS hierarchy is as follows:

OCX - COleControl
  Main Dialog - Cdialog, child dlg
  
    Menu (static text fields) - CstaticToMenu custom CStatic class

    Tree View - CTreeCtrl

    Tabbed Control - CXTabCtrl custom CTabCtrl

      XML Dialog - cdxCDynamicDialog custom dialog

      Tools Dialog - cdxCDynamicDialog custom dialog

      Details Dialog(s) (Series of dialogs swapped in and out at runtime)

        Tree item type 1 dialog, a cdxCDynamicDialog
        Tree item type 2 dialog, a cdxCDynamicDialog
        Etc....

A Note on CdxCDynamicDialog

This is a custom class that is derived from both CDialog and a cdxCDynamicWnd custom dynamic window class that allows the developer to specify how controls placed on the dialog respond to dialog resizing.

On a standard CDialog, when controls such as listboxes or edit boxes are placed on the dialog, they stay fixed regardless of how the dialog is sized. If the user sizes the dialog larger to allow for more space, the controls cannot take advantage of it. If the user sizes the dialog to smaller than its original size, the dialog clips controls and the user cannot see the controls. The cdxCDynamicDialog class allows for the automatic resizing and repositioning of controls within a dialog when the dialog is sized.

The Main Dialog and each of the child dialogs in the tabbed control are derived from and and employ the cdxCDynamicDialog so that all the controls within all the dialogs are dynamically repositioned when the dialog is resized.

Note: The dialog presented for the "For Each" tree node is derived from the dynamic dialog class but does not make use of its control auto-positioning since the dialog actually contains several sets of controls, which are moved into various positions, and only shown to the user based on the combo entry they select within the dialog. The dynamic dialog does not handle this custom movement. (See the dialog template IID_FOREACH and the CdlgForEach class in DlgForEach.h and DlgForEach.cpp).

To specify resizing for controls within a dialog, a DYNAMIC_MAP_ENTRY macro is placed in the dialog's implementation (.cpp) file for each control to be resized, specifying the ID of the control and how it is to respond to changes in the dialog size on the x and y axis.

In the following example, the edit control has an ID of IDC_QUERY_MIFCLASS and is to be automatically resized to fit the width (x axis) of the dialog as the dialog is sized, but is to remain in its y axis (not move up or down).

BEGIN_DYNAMIC_MAP(CDlgQuery,cdxCDynamicDialog)
DYNAMIC_MAP_ENTRY(IDC_QUERY_MIFCLASS, mdResize, mdNone) 
Etc. 
Etc.
END_DYNAMIC_MAP()

Of course the dialog class (in this case CdlgQuery) has to be derived from cdxCDynamicDialog and it must have the following macro placed in its header:

DECLARE_DYNAMIC_MAP();

See DlgQuery.cpp and DlgQuery.h for a complete example of this usage.

A Note on shared dialog templates and classes and their use by the "New Item" dialog and the Properties tab.

The dialogs presented to the user when the user creates a new item and needs to provide the initial data, are the same dialogs, templates and classes used by the tabbed control to show the item properties. This technique eliminates needing to maintain 2 separate dialogs for each tree item.

Note: The properties dialogs must all be defined in the resource template as invisible since the application creates all the dialogs at startup and only swaps in the needed dialog at runtime depending on the tree item selected. The container dialog used to show individual dialogs when creating a new node will show the child dialogs as visible. When the tabbed control swaps in each dialog for display it will make the current dialog visible as well.

Each item's dialog is defined as a child dialog with no OK or CANCEL buttons. This definition is needed by the tabbed dialog control. When creating a new tree item, the dialog will appear as a normal modal framed dialog complete with OK and CANCEL buttons. This is achieved through the use of a generic modal dialog that has an OK and CANCEL button and acts as a parent container for the child dialog. Since the child dialog does not have a frame or border, it appears within the parent container as 1 modal dialog.

Each child dialog must implement a virtual function of CdlgBase (the class from which all child property dialogs are derived) called IsRequiredDataValid() which returns TRUE or FALSE depending on the validity of the dialog data. This function is called from the container dialog since the child dialog has no OK or CANCEL buttons. The OK and CANCEL buttons are on the container dialog so when the user presses OK, the container dialog asks the child dialog if all data is present and valid. If not, the child dialog will present a message to the user and will return FALSE to the container dialog. The container dialog will then keep the dialog open until the user enters valid data or presses the CANCEL button.

Serialization of Tree / Queries

The program gives the user the ability to save the tree contents to a disk file and to load the contents of a previously saved file.

Save

During the SAVE process, the tree is traversed from top-down and each node is passed the Carchive object and saves itself to the object. This process saves all the information about the tree node to disk sequentially.

Open

Opening an existing data file, the archive is scanned sequentially and each object type encountered in the file results in that object being created dynamically and added to the tree. In this way the exact contents of the tree is replicated.

Note: Since it is possible that individual tree node items may have additional data members added to them in future releases of the program, a "serialization version" has been added to the serialization process that will enable the program to track which "version" of the data is being read/written. ANY TIME THE FORMAT OF THE DATA IS CHANGED THIS VERSION NUMBER MUST BE INCREMENTED AND THE PROGRAM MUST BE MODIFIED TO ACCOUNT FOR THE VERSION DIFFERENCE. OTHERWISE PREVIOUSLY SAVED FILES WILL BE UN-READABLE BY THE PROGRAM!. The version number is contained in a #define called SERIALIZATION_VERSION_NUMBER and is stored in DlgMain.h. The version number is a simple number (initially set to 1) and should simply be incremented by 1 for any data formatting change to any of the data saved to disk.

The components that make up a tree node.

If a new tree node type is to be added to the program, the following is a basic guide to the required components and architecture, and steps to create a new node type.

  1. Create a Cdata derived item. This object defines all the data required of that particular data type including fields the user does not see such as the GUID assigned to that object. The object is passed to the display dialog for data display, is used to serialize the data to disk etc. You will notice many existing items from which to use as examples such as CDataQuery and CDataGroup etc. The Cdata class defines a number of pure virtual functions which must be defined and coded in the derived class.
  2. Create a CdlgBase derived dialog. This dialog will serve as both the properties display and the property editing dialog. It will use the Cdata derived class as a pointer to its data. See CdlgQuery and CdlgGroup as examples. Be sure to change the dialog class definition to derive from CdlgBase.
  3. Modify the main dialog class to recognize and utilize these new classes. The CdlgMain::OnInitDialog must create the dialog at startup. It will not be displayed at that time but must be defined and created. Also modify the CdlgMain::OnNew... handlers to invoke the new object creation process. See any of the OnNew... handlers for examples.
  4. Modify the CdlgContainer class to include the new dialog class. The Container dialog is the dialog that acts as a "container" for the child dialog that enables the user to edit the dialog data. The container dialog is a popup dialog with a dialog frame. It is unlike the properties tabbed dialogs which are read-only child dialogs.
  5. Make any necessary modifications to the serialization driver class CdataLoader. There should be very little, if any changes required there.
  6. There will be a few other minor changes to make, such as adding an icon to the image list for the new node type (Be sure you add it to the end of the image bitmap and add its IID_ value to the end of the existing IID_ values, but before the NON_IMAGE_... values. Best way is to simply use any of the existing node types as examples.
  7. Update the CdragItem class to handle the drag and drop transfer of nodes from one tree location to another. (See Drag and Drop below).
  8. Also be sure to set the dialog attributes in the resource editor to CHILD, Clip Children, No Border, Control, and Control Parent.

A note on the CdlgMain::OnNew... handlers.

I have created separate OnNew... handlers for each of the tree node types initially since there were some small differences in the handling of some of the tree node types. For now this separation allow for more flexibility, but once the program is completely finished it may warrant some retooling to consolidate much of the OnNew... handling into a single dialog.

Drag and Drop.

The program allows the user to drag and drop node items around the tree. This is done via the use of the ColeDropTarget derived member variable m_dropTarget in the Main Dialog and the CdragItem class that handles the transfer of data and tree from one location to another when the user drops a dragged item. Any new tree node types should be handled in these classes. There are just a few functions required to support Drag and Drop.

The functions in blue are the ones that will require the updating based on new items added or on changing the rules for exiting item drag/drop.

CdlgMain:: OnBeginDrag This function is called by the framework when the user first begins a drag operation.

CDlgMain::CCustOleDropTarget::OnDragEnter This function is called by the framework when an item is first dragged over the tree control window. Subsequent movement is handled by the OnDragOver function. Its function is to provide visual feedback in the form of a "drag cursor".

CDlgMain::CCustOleDropTarget::OnDragOver This function is called by the framework when an item is dragged over the tree control window subsequent to the OnDragEnter call. Its function is to provide visual feedback in the form of a "drag cursor" that gives a visual indication as to whether a drop of the item is allowed over a particular part of the tree.

CDlgMain::CCustOleDropTarget::OnDrop This function is called when the dragged item is dropped into the tree control window. Its function is to handle the drop by performing any tree node MOVE or COPY operations etc.

CDlgMain::CCustOleDropTarget::SetDropEffect This function is called by the above functions to provide visual feedback as to whether the item being dragged is allowed to be dropped at its current location in the tree control window.

CDragItem::Transfer This function is called by the OnDrop() function to transfer a tree item from one location to another based on which type of item was dragged/dropped and where it was dropped.

Command Line Parms / Automation Functions

The following are the automation functions provided by the ocx, and also the command line parms accepted by the ocx's parent application AeXAeXCustInvHelperApp.exe.

Automation Functions.

long SetParms(LPCTSTR lpctstrParms); (long SetParms(BSTR lpctstrParms);)

This function instructs the ocx to scan the passed command line parms string and execute any parms applicable. This is an easier approach than writing a series of automation functions. All the tasks can be executed in one method call.

AeXAeXCustInvHelperApp Command Line Parms.

The helper app takes all command line parms and passes them to the ocx in a single call to SetParms (see 'Automation Functions' above)

/LoadFile <filename> where <filename> is the full path and filename of the file to instruct the ocx to load. The helper app calls the ocx's automation function LoadFile() with this filename.

/Ini <filename> where <filename> is the full path and filename of the file use as the default ini file. The ocx also provides a dropdown menu option to select a different ini file.

UNDOCUMENTED TESTONLY ALTIRIS ONLY COMMAND LINE PARMS

/ocx <ocxname> where <ocxname> is the name of an alternate AeXCustInvHelper ocx to use instead of the default one in the current directory. This can be either a full path and filename or just the filename in which case the current directory is assumed.

Tree Node Placements

All tree node items created by the user (such as a QUERY, GROUP, etc) are created at the point in the tree where the user created them except for the FIELD and WRITE types.

FIELD All FIELD types are placed immediately following the GROUP that owns them. This results in all FIELD statements appearing together immediately following the owning GROUP.

WRITE All WRITE types are placed and kept together in the tree following the creation of the first WRITE item. The first WRITE item created is placed at the point where it was defined. All subsequent WRITE items are placed alongside the first WRITE statement. This results in all WRITE statements for a GROUP being kept together. When any single WRITE statement is moved, all sibling WRITE statements are also moved, keeping the WRITE statements together.

Displaying the generated XML

Each time the user clicks on the tree, the program will determine if the XML view is the currently selected view in the tabbed control. If it is, the XML to be passed to the CustInv program will be generated and displayed in the XML view window. If some other view (such as the properties view) is selected, the XML will not be built until either the XML view is selected or the user chooses to export the XML or run the CustInv program.

The XML builder takes as a parm any tree item (CtreeCursor) belonging to the query. It can be a GROUP item, a FIELD item etc. It then find the owning QUERY item and from there traverses through the child GROUP, FIELD and STATEMENT items to build the XML.

License:AJSL
By clicking the download link below, you agree to the terms and conditions in the Altiris Juice Software License
Support:User-contributed tools on the Juice are not supported by Altiris Technical Support. If you have questions about a tool, please communicate directly with the author by visiting their profile page and clicking the 'contact' tab.

Statistics
0 Favorited
0 Views
3 Files
0 Shares
0 Downloads
Attachment(s)
zip file
Altiris Custom Inventory OCX.zip   356 KB   1 version
Uploaded - Feb 25, 2020
doc file
Custon Inventory Helper OCX Files.doc   22 KB   1 version
Uploaded - Feb 25, 2020
doc file
Custon Inventory Helper OCX.doc   59 KB   1 version
Uploaded - Feb 25, 2020

Tags and Keywords

Related Entries and Links

No Related Resource entered.