home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / windows / c / bsscdemo / treedem3 / treedem3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-28  |  91.0 KB  |  2,085 lines

  1. /*
  2.    Copyright (c) 1993 by Barking Spider Software Inc.  All rights reserved
  3.                                                                            
  4.    Filename...:  treedem3.c
  5.    
  6.    Version,,,,:  1.0
  7.    
  8.    Language...:  Microsoft C/C++ 7.0
  9.    
  10.    Model......:  Small
  11.    
  12.    Environment:  Microsoft Windows 3.1
  13.                                                                            
  14.    Description:  Sample MDI code that demonstrates the functionality of the
  15.                  tree control.  The window procedures TreeCtrlFrameWndProc
  16.                  and ListCtrlFrameWndProc are the center of attention.  They
  17.                  are the window procedures of the MDI child windows.  When
  18.                  these procedures receive their WM_CREATE message, the
  19.                  handlers each create a BSS Tree Control.
  20.                  
  21.                  After the tree controls are created, they are populated with
  22.                  a root and the first level tree nodes.  The 
  23.                  TreeCtrlFrameWndProc populates it's tree control with the
  24.                  database stored in the user-defined resource TREEDB RCDATA
  25.                  which is located in the file TREEDB.DAT.  This database 
  26.                  describes the tree control exported API.  The 
  27.                  ListCtrlFrameWndProc populates it's tree control with the
  28.                  database stored in the user-defined resource LISTDB RCDATA
  29.                  which is located in the file TREEDB.DAT.  This database
  30.                  describes the list control exported API.
  31.  
  32.                  When a user double clicks on any of these tree nodes, the MDI
  33.                  child window will receive a notification.  This 
  34.                  notification describes the node that was selected by the
  35.                  double click.  The MDI child window will respond by taking
  36.                  the key index of the tree node that was selected, use it to
  37.                  access the database, and retrieve the list of children for 
  38.                  that node.  The BSS Tree Control is sent this list via the
  39.                  exported API, BST_AddChildrenToParent, and SLAM!  The list
  40.                  of children for the selected node is displayed in the tree.
  41.                  
  42.                  The MDI child window procedure also demonstrates the passing
  43.                  of the WM_SYSCOLORCHANGE notification to the BSS Tree Control
  44.                  for system color changes.
  45.                  
  46.                  REMEMBER:
  47.  
  48.                  The static databases that are used in this example are just
  49.                  one type of storage system.  The database could be a file
  50.                  system, a finite state machine, a relational database
  51.                  browser, a network map, etc.
  52.                  
  53.    Notes......:             
  54.                                                                            
  55.    History....:  
  56.                                                                               
  57.    Author.....:  Peter J. Kaufman
  58. */    
  59.  
  60. #include <windows.h>
  61. #include <stdlib.h>
  62. #include "treedem3.h"
  63. #include "..\bscore.h"  // Contains tree control structures, notification
  64.                         // messages, error codes, etc.
  65. #include "..\bstree.h"  // Contains exported tree control API prototypes.
  66.  
  67. #include <string.h>
  68. #include <malloc.h>
  69.  
  70. // Database that describes the tree control exported API.
  71. #define TREE_SIZE 908
  72. TREE_DATABASE TreeDatabase [TREE_SIZE];
  73.  
  74. // Database that describes the list control exported API.
  75. #define LIST_SIZE 719
  76. TREE_DATABASE ListDatabase [LIST_SIZE];
  77.  
  78. char   szFrameClass [] = "Frame" ;
  79. char   szTreeCtrlFrameClass [] = "TreeCtrlFrame";
  80. char   szListCtrlFrameClass [] = "ListCtrlFrame";
  81.  
  82. HANDLE hInst ;
  83. HMENU  hMenuInit, hMenuTreeCtrl , hMenuListCtrl;
  84. HMENU  hMenuInitWindow, hMenuTreeCtrlWindow, hMenuListCtrlWindow;
  85.  
  86. // Bitmaps used in the tree control.
  87. HBITMAP hbmClosedActive;
  88. HBITMAP hbmClosed;
  89. HBITMAP hbmOpenActive;
  90. HBITMAP hbmOpen;
  91. HBITMAP hbmSheetActive;
  92. HBITMAP hbmSheet;
  93. HBITMAP hbm[MAX_BITMAP_ID];
  94.  
  95. /*****************************************************************************
  96. int PASCAL WinMain ( HANDLE hInstance,
  97.                      HANDLE hPrevInstance,
  98.                      LPSTR lpszCmdLine,
  99.                      int nCmdShow);
  100.                      
  101. The following code registers the MDI Frame window and the MDI child window
  102. classes.  It then sets up the menus, creates the Frame window and then
  103. processes the messages in the main message loop. 
  104. *****************************************************************************/
  105.  
  106. int PASCAL WinMain ( HANDLE hInstance,
  107.                      HANDLE hPrevInstance,
  108.                      LPSTR lpszCmdLine,
  109.                      int nCmdShow)
  110. {
  111.    HWND     hwndFrame, hwndClient ;
  112.    MSG      msg ;
  113.    WNDCLASS wndclass ;
  114.  
  115.    hInst = hInstance ;
  116.  
  117.    if (!hPrevInstance) 
  118.    {
  119.       wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  120.       wndclass.lpfnWndProc   = FrameWndProc ;
  121.       wndclass.cbClsExtra    = 0 ;
  122.       wndclass.cbWndExtra    = 0 ;
  123.       wndclass.hInstance     = hInstance ;
  124.       wndclass.hIcon         = LoadIcon (hInst,
  125.                                          MAKEINTRESOURCE(IDR_TREEDEMO_ICON)) ;
  126.       wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  127.       wndclass.hbrBackground = COLOR_APPWORKSPACE + 1 ;
  128.       wndclass.lpszMenuName  = NULL ;
  129.       wndclass.lpszClassName = szFrameClass ;
  130.  
  131.       RegisterClass (&wndclass) ;
  132.  
  133.       // Register the MDI child that will create the tree control describing
  134.       // the tree control exported APIs.
  135.       wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  136.       wndclass.lpfnWndProc   = TreeCtrlFrameWndProc ;
  137.       wndclass.cbClsExtra    = 0 ;
  138.       wndclass.cbWndExtra    = TREECTRL_WND_EXTRA;
  139.       wndclass.hInstance     = hInstance ;
  140.       wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  141.       wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  142.       wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
  143.       wndclass.lpszMenuName  = NULL ;
  144.       wndclass.lpszClassName = szTreeCtrlFrameClass ;
  145.  
  146.       RegisterClass (&wndclass) ;
  147.  
  148.       // Register the MDI child that will create the tree control describing
  149.       // the list control exported APIs.
  150.       wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
  151.       wndclass.lpfnWndProc   = ListCtrlFrameWndProc ;
  152.       wndclass.cbClsExtra    = 0 ;
  153.       wndclass.cbWndExtra    = LISTCTRL_WND_EXTRA;
  154.       wndclass.hInstance     = hInstance ;
  155.       wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
  156.       wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
  157.       wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;
  158.       wndclass.lpszMenuName  = NULL ;
  159.       wndclass.lpszClassName = szListCtrlFrameClass ;
  160.  
  161.       RegisterClass (&wndclass) ;
  162.    }
  163.  
  164.    // Convert the RCDATA of both the tree control exported API and
  165.    // the list control exported API.
  166.    if(ReadInDatabases () == 0)
  167.    {
  168.       hMenuInit  =  LoadMenu(hInst, "InitialMenu") ;
  169.       hMenuTreeCtrl = LoadMenu (hInst, "TreeCtrlMenu") ;
  170.       hMenuListCtrl = LoadMenu (hInst, "ListCtrlMenu") ;
  171.  
  172.       hMenuInitWindow  = GetSubMenu (hMenuInit,   INIT_MENU_POS) ;
  173.       hMenuTreeCtrlWindow = GetSubMenu (hMenuTreeCtrl, TREECTRL_MENU_POS) ;
  174.       hMenuListCtrlWindow = GetSubMenu (hMenuListCtrl, LISTCTRL_MENU_POS) ;
  175.  
  176.       hwndFrame = CreateWindow ( szFrameClass,
  177.                                  "Barking Spider Software, Inc. Tree Demo 3 - MDI",
  178.                                  WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  179.                                  CW_USEDEFAULT,
  180.                                  CW_USEDEFAULT,
  181.                                  CW_USEDEFAULT,
  182.                                  CW_USEDEFAULT,
  183.                                  NULL,
  184.                                  hMenuInit,
  185.                                  hInstance,
  186.                                  NULL) ;
  187.  
  188.       hwndClient = GetWindow (hwndFrame, GW_CHILD) ;
  189.  
  190.       ShowWindow (hwndFrame, nCmdShow) ;
  191.       UpdateWindow (hwndFrame) ;
  192.    
  193.       SendMessage (hwndFrame, WM_COMMAND, IDM_NEW_TREECTRL, 0L);
  194.       SendMessage (hwndFrame, WM_COMMAND, IDM_NEW_LISTCTRL, 0L);
  195.       SendMessage (hwndFrame, WM_COMMAND, IDM_CASCADE, 0L);
  196.    
  197.       while (GetMessage (&msg, NULL, 0, 0))
  198.       {
  199.          if (! TranslateMDISysAccel (hwndClient, &msg))
  200.          {
  201.             TranslateMessage (&msg) ;
  202.             DispatchMessage (&msg) ;
  203.          }
  204.       }
  205.       DestroyMenu (hMenuTreeCtrl) ;
  206.       DestroyMenu (hMenuListCtrl);
  207.    }
  208.    return msg.wParam ;
  209. }
  210.  
  211.  
  212. /*****************************************************************************
  213. long FAR PASCAL _export FrameWndProc ( HWND hwnd,
  214.                                        UINT message,
  215.                                        UINT wParam,
  216.                                        LONG lParam);
  217.                                        
  218.  This is the window procedure for the MDI Frame window created above.  
  219.  It mainly processes the menu messages.  The two most important menu messages
  220.  are the WM_COMMAND message with wParam set to IDM_NEW_TREECTRL and the 
  221.  the WM_COMMAND message with wParam set to IDM_NEW_LISTCTRL.
  222.  When FrameWndProc receives these messages, it means that the user has
  223.  selected the "New Tree" or the "New List" menu item under File.  The code
  224.  that handles these messages creates the appropriate MDI child window which
  225.  in turn creates a single tree control.
  226.  
  227.  Another important message is the WM_SYSCOLORCHANGE message which is sent to 
  228.  all top level windows when a system color changes.  For example, if a user
  229.  opens the Color Dialog and changes the background window color,
  230.  Windows will send the WM_SYSCOLORCHANGE notification to this window procedure
  231.  but not to any of the MDI children.  So... since the tree controls are
  232.  children of the MDI child window, the tree controls will not receive the
  233.  WM_SYSCOLORCHANGE notification.  The tree control handles the
  234.  WM_SYSCOLORCHANGE notification if it is sent.  When FrameWndProc,
  235.  the window procedure below, receives a WM_SYSCOLORCHANGE notification,
  236.  it enumerates all of the MDI children, getting each of the window handles,
  237.  so to send the notification onto them.  In turn the MDI children window
  238.  procedures send the WM_SYSCOLORCHANGE notification to the tree controls.
  239.  The tree controls then handles the color change and repaints the trees.
  240.  
  241.  Notice that all of the bitmaps are loaded here.  These are global to all
  242.  MDI child windows.
  243.  
  244. *****************************************************************************/
  245.  
  246. long FAR PASCAL _export FrameWndProc ( HWND hwnd,
  247.                                        UINT message,
  248.                                        UINT wParam,
  249.                                        LONG lParam)
  250. {
  251.    static HWND        hwndClient ;
  252.    CLIENTCREATESTRUCT clientcreate ;
  253.    FARPROC            lpfnEnum ;
  254.    HWND               hwndChild ;
  255.    MDICREATESTRUCT    mdicreate ;
  256.    WORD               i;
  257.  
  258.    switch (message)
  259.    {
  260.       case WM_CREATE:
  261.          hbm[0] = LoadBitmap (hInst, MAKEINTRESOURCE(IDR_API));
  262.          hbm[1] = LoadBitmap (hInst, MAKEINTRESOURCE(IDR_ARG)); 
  263.          hbm[2] = LoadBitmap (hInst, MAKEINTRESOURCE(IDR_TXT)); 
  264.          hbm[3] = LoadBitmap (hInst, MAKEINTRESOURCE(IDR_RET)); 
  265.          hbm[4] = LoadBitmap (hInst, MAKEINTRESOURCE(IDR_DSC)); 
  266.          hbm[5] = LoadBitmap (hInst, MAKEINTRESOURCE(IDR_COM)); 
  267.  
  268.          // CreateBackgroundMatchedBitmap creates the folders used in 
  269.          // the BSS Tree Control.  CreateBackgroundMatchedBitmap  does what
  270.          // it says.  It loads the initial folder bitmap from the resource,
  271.          // and converts the bitmap's background color to match the system 
  272.          // window color.  This is done for the closed, open. and sheet
  273.          // folder bitmaps.  The bitmaps above are rectangular and need no
  274.          // background masking.
  275.             
  276.          // Notice that this procedure is also done for the COLOR_HIGHLIGHT
  277.          // color.  COLOR_HIGHLIGHT is the color used to show the current
  278.          // selection (active node).
  279.    
  280.          hbmClosed = CreateBackgroundMatchedBitmap (
  281.                                                    GetSysColor (COLOR_WINDOW),
  282.                                                    IDR_CLOSED_FOLDER);
  283.    
  284.          hbmClosedActive = CreateBackgroundMatchedBitmap (
  285.                                                 GetSysColor (COLOR_HIGHLIGHT),
  286.                                                 IDR_CLOSED_FOLDER);
  287.    
  288.          hbmOpen = CreateBackgroundMatchedBitmap (
  289.                                                    GetSysColor (COLOR_WINDOW),
  290.                                                    IDR_OPEN_FOLDER);
  291.             
  292.          hbmOpenActive = CreateBackgroundMatchedBitmap (
  293.                                                 GetSysColor (COLOR_HIGHLIGHT),
  294.                                                 IDR_OPEN_FOLDER);
  295.                                                    
  296.          hbmSheet = CreateBackgroundMatchedBitmap (
  297.                                                    GetSysColor (COLOR_WINDOW),
  298.                                                    IDR_SHEET);
  299.             
  300.          hbmSheetActive = CreateBackgroundMatchedBitmap (
  301.                                                 GetSysColor (COLOR_HIGHLIGHT),
  302.                                                 IDR_SHEET); 
  303.  
  304.          clientcreate.hWindowMenu  = hMenuInitWindow ;
  305.          clientcreate.idFirstChild = IDM_FIRSTCHILD ;
  306.  
  307.          hwndClient = CreateWindow ("MDICLIENT",
  308.                                      NULL,
  309.                                      WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
  310.                                      0,
  311.                                      0,
  312.                                      0,
  313.                                      0,
  314.                                      hwnd,
  315.                                      1,
  316.                                      hInst,
  317.                                      (LPSTR) &clientcreate) ;
  318.           
  319.          ShowWindow (hwndClient,SW_SHOW);
  320.          return 0 ;
  321.          
  322.       case WM_COMMAND:
  323.          switch (wParam)
  324.          {
  325.             // Creates the MDI child that will in turn create the tree control
  326.             // which will display the database in TREEDB.DAT.  TREEDB.DAT
  327.             // describes the tree control exported APIs.
  328.             case IDM_NEW_TREECTRL:
  329.             
  330.                mdicreate.szClass = szTreeCtrlFrameClass ;
  331.                mdicreate.szTitle = "BSS Tree Control" ;
  332.                mdicreate.hOwner  = hInst ;
  333.                mdicreate.x       = CW_USEDEFAULT ;
  334.                mdicreate.y       = CW_USEDEFAULT ;
  335.                mdicreate.cx      = CW_USEDEFAULT ;
  336.                mdicreate.cy      = CW_USEDEFAULT ;
  337.                mdicreate.style   = 0 ;
  338.                mdicreate.lParam  = NULL ;
  339.  
  340.                hwndChild = (HWND) SendMessage ( hwndClient,
  341.                                                 WM_MDICREATE,
  342.                                                 0,
  343.                                         (long) (LPMDICREATESTRUCT) &mdicreate) ;
  344.                return 0 ;
  345.                
  346.                
  347.             // Creates the MDI child that will in turn create the tree control
  348.             // which will display the database in LISTDB.DAT.  LISTDB.DAT
  349.             // describes the list control exported APIs.
  350.             
  351.             case IDM_NEW_LISTCTRL:
  352.             
  353.                mdicreate.szClass = szListCtrlFrameClass ;
  354.                mdicreate.szTitle = "BSS List Control" ;
  355.                mdicreate.hOwner  = hInst ;
  356.                mdicreate.x       = CW_USEDEFAULT ;
  357.                mdicreate.y       = CW_USEDEFAULT ;
  358.                mdicreate.cx      = CW_USEDEFAULT ;
  359.                mdicreate.cy      = CW_USEDEFAULT ;
  360.                mdicreate.style   = 0 ;
  361.                mdicreate.lParam  = NULL ;
  362.  
  363.                hwndChild = (HWND) SendMessage ( hwndClient,
  364.                                                 WM_MDICREATE,
  365.                                                 0,
  366.                                         (long) (LPMDICREATESTRUCT) &mdicreate) ;
  367.                return 0 ;
  368.  
  369.             case IDM_CLOSE:
  370.  
  371.                hwndChild = LOWORD (SendMessage (hwndClient,
  372.                                                 WM_MDIGETACTIVE,
  373.                                                 0,
  374.                                                 0L)) ;
  375.  
  376.                if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0L))
  377.                   SendMessage ( hwndClient, WM_MDIDESTROY, hwndChild, 0L) ;
  378.                return 0 ;
  379.  
  380.             case IDM_EXIT:
  381.                SendMessage (hwnd, WM_CLOSE, 0, 0L) ;
  382.                return 0 ;
  383.  
  384.             case IDM_TILE:
  385.                SendMessage (hwndClient, WM_MDITILE, 0, 0L) ;
  386.                return 0 ;
  387.  
  388.             case IDM_CASCADE:
  389.                SendMessage (hwndClient, WM_MDICASCADE, 0, 0L) ;
  390.                return 0 ;
  391.  
  392.             case IDM_ARRANGE:
  393.                SendMessage (hwndClient, WM_MDIICONARRANGE, 0, 0L) ;
  394.                return 0 ;
  395.  
  396.             case IDM_CLOSEALL:
  397.                lpfnEnum = MakeProcInstance ((FARPROC) CloseEnumProc,
  398.                                                       hInst) ;
  399.                EnumChildWindows (hwndClient, lpfnEnum, 0L) ;
  400.                FreeProcInstance (lpfnEnum) ;
  401.                return 0 ;
  402.  
  403.             default:
  404.                hwndChild = LOWORD (SendMessage (hwndClient,
  405.                                                 WM_MDIGETACTIVE, 0, 0L)) ;
  406.  
  407.                if (IsWindow (hwndChild))
  408.                   SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ;
  409.                break;
  410.          }
  411.          break ;
  412.  
  413.       case WM_QUERYENDSESSION:
  414.       case WM_CLOSE:
  415.          SendMessage (hwnd, WM_COMMAND, IDM_CLOSEALL, 0L) ;
  416.  
  417.          if (NULL != GetWindow (hwndClient, GW_CHILD))
  418.             return 0 ;
  419.          break ;
  420.  
  421.       /* 
  422.          Passed on all MDI children so that they may pass it onto their 
  423.          BSS Tree Control child.
  424.       */
  425.       case WM_SYSCOLORCHANGE:
  426.          ChangeBitmapToMatchBackground ( GetSysColor (COLOR_WINDOW),
  427.                                          hbmClosed,
  428.                                          IDR_CLOSED_FOLDER);
  429.          ChangeBitmapToMatchBackground ( GetSysColor (COLOR_WINDOW),
  430.                                          hbmOpen,
  431.                                          IDR_OPEN_FOLDER);
  432.          ChangeBitmapToMatchBackground ( GetSysColor (COLOR_HIGHLIGHT),
  433.                                          hbmClosedActive,
  434.                                          IDR_CLOSED_FOLDER);
  435.          ChangeBitmapToMatchBackground ( GetSysColor (COLOR_HIGHLIGHT),
  436.                                          hbmOpenActive,
  437.                                          IDR_OPEN_FOLDER);
  438.          ChangeBitmapToMatchBackground ( GetSysColor (COLOR_WINDOW),
  439.                                          hbmSheet,
  440.                                          IDR_SHEET);
  441.          ChangeBitmapToMatchBackground ( GetSysColor (COLOR_HIGHLIGHT),
  442.                                          hbmSheetActive,
  443.                                          IDR_SHEET);      
  444.          lpfnEnum = MakeProcInstance ((FARPROC) SysColorChangeEnumProc, hInst) ;
  445.          EnumChildWindows (hwndClient, lpfnEnum, 0L) ;
  446.          FreeProcInstance (lpfnEnum) ;
  447.          return 0 ;
  448.          
  449.       case WM_DESTROY :
  450.          // Destroy the bitmaps used in the tree.
  451.          DeleteObject(hbmClosed);
  452.          DeleteObject(hbmClosedActive);
  453.          DeleteObject(hbmOpen);
  454.          DeleteObject(hbmOpenActive);
  455.          DeleteObject(hbmSheet);
  456.          DeleteObject(hbmSheetActive);
  457.          
  458.          for (i = 0; i < MAX_BITMAP_ID; i++)
  459.              DeleteObject(hbm[i]);
  460.        
  461.          for( i = 0; i < TREE_SIZE; i++)
  462.             _ffree(TreeDatabase[i].lpszNodeText);
  463.          
  464.          for( i = 0; i < LIST_SIZE; i++)
  465.             _ffree(ListDatabase[i].lpszNodeText);
  466.             
  467.          PostQuitMessage (0) ;
  468.          return 0 ;
  469.    }
  470.    return DefFrameProc (hwnd, hwndClient, message, wParam, lParam) ;
  471. }
  472.  
  473.  
  474.  
  475. /*****************************************************************************
  476. BOOL FAR PASCAL _export SysColorChangeEnumProc ( HWND hwnd,
  477.                                                  LONG lParam)
  478.                                                  
  479.  All this callback does, is send a WM_SYSCOLORCHANGE notification to the 
  480.  window identified by hwnd.  This routine gets called as a result of the 
  481.  Frame window enumerating all of its children when it receives a 
  482.  WM_SYSCOLORCHANGE notification.  Windows sends this notification when any
  483.  of the system colors change.  Since only top level windows receive
  484.  this notification, the Frame window must pass it to it's children so that
  485.  it's children can pass it onto their controls namely the BSS Tree Control.
  486.  The BSS Tree Control handles this notification nicely.
  487. *****************************************************************************/
  488.  
  489. BOOL FAR PASCAL _export SysColorChangeEnumProc ( HWND hwnd,
  490.                                                  LONG lParam)
  491. {
  492.    SendMessage (hwnd, WM_SYSCOLORCHANGE, 0, 0L);
  493.    return TRUE;
  494. }
  495.  
  496. /*****************************************************************************
  497. BOOL FAR PASCAL _export CloseEnumProc (HWND hwnd, LONG lParam)
  498.  
  499. Callback in which Windows calls for each child MDI window when the Frame
  500. window to be destroyed.
  501. ******************************************************************************/
  502.  
  503. BOOL FAR PASCAL _export CloseEnumProc (HWND hwnd, LONG lParam)
  504. {
  505.    if (GetWindow (hwnd, GW_OWNER))
  506.       return TRUE;
  507.  
  508.    SendMessage (GetParent (hwnd), WM_MDIRESTORE, hwnd, 0L) ;
  509.  
  510.    if (!SendMessage (hwnd, WM_QUERYENDSESSION, 0, 0L))
  511.       return TRUE;
  512.  
  513.    SendMessage (GetParent (hwnd), WM_MDIDESTROY, hwnd, 0L) ;
  514.       return TRUE;
  515. }
  516.  
  517.  
  518.  
  519.  
  520. /*****************************************************************************
  521. long FAR PASCAL _export TreeCtrlFrameWndProc ( HWND hwnd,
  522.                                                UINT message,
  523.                                                UINT wParam,
  524.                                                LONG lParam)
  525.  
  526.  
  527.  This is the window procedure of the MDI child window.  When this procedure
  528.  receives it's WM_CREATE message, a BSS Tree Control is created as a child
  529.  window (control).  
  530.                  
  531.  After this tree is created, it is populated with the root node and the first
  532.  level nodes taken from the database described in the file TREEDB.DAT which
  533.  is in RCDATA format.
  534.                  
  535.  When a user double clicks on any of these nodes, the MDI child window (which
  536.  is the parent of the BSS Tree Control) will receive a notification.
  537.  This notification describes the node that was selected by the
  538.  double click.  The MDI child window will respond by taking the key index of
  539.  the node that was clicked on, use it to access the database, and retrieve the
  540.  list of children for that node.  The BSS Tree Control is sent this list via
  541.  the exported API, BST_AddChildrenToParent, and SLAM!  The list of children
  542.  for the selected node is displayed. 
  543.  
  544.  This MDI child window procedure also demonstrates the passing of the
  545.  WM_SYSCOLORCHANGE notification to the BSS Tree Control for system color
  546.  changes.
  547.  
  548.  REMEMBER:
  549.  
  550.  The database that is used in this example is just one storage system.
  551.  The database could be a file system, a finite state machine, a relational
  552.  database browser, a network map, etc.
  553. ******************************************************************************/
  554.  
  555.  
  556. #define SPACE_BEFORE_TEXT 4
  557.  
  558. long FAR PASCAL _export TreeCtrlFrameWndProc ( HWND hwnd,
  559.                                                UINT message,
  560.                                                UINT wParam,
  561.                                                LONG lParam)
  562. {
  563.    static HWND        hwndClient;
  564.    static HWND        hwndFrame ;
  565.    // The following are important pointers in the process of building the
  566.    // tree.  The structure definition that these pointers point to are defined
  567.    // in bstree.h
  568.    LP_TREE_NODE       lpParentTreeNode; // Points to a tree node
  569.    LP_TREE_NODE_DEF   lpTreeNodeDef;    // Points to an array of 1 or more
  570.                                         // tree node definitions that are
  571.                                         // defined by the application.
  572.    LP_TREE_NODE_DEF   lpTreeNodeDef2;   // Runner used to traverse the list
  573.                                         // tree node definitions pointed to 
  574.                                         // by the pointer above.
  575.    LP_SELECT_NOTIF    lpSelectNotif;    // Pointer to the tree control owned
  576.                                         // notification structure used to 
  577.                                         // pass information about a tree node
  578.                                         // to the application.
  579.    WORD               i;
  580.    WORD               j;
  581.    HWND               hwndTree;         
  582.    WORD               wNumberOfChildren;
  583.    WORD               wIndexOfChildren;
  584.    LOCALHANDLE        hTreeData ;
  585.    NP_TREE_DATA       npTreeData ;   
  586.    short              cx, cy;
  587.    WORD               wErrCode;
  588.    LONG               lResult;
  589.    
  590.    switch (message)
  591.    {
  592.       case WM_CREATE:
  593.          hwndClient = GetParent (hwnd) ;
  594.                   
  595.          hwndFrame  = GetParent (hwndClient) ;      
  596.       
  597.          lResult = 0xFFFFFFFF;
  598.  
  599.          // Allocate the instance data for this MDI child window. This data
  600.          // structure will hold the window handle of the tree control and the
  601.          // handles of the bitmaps to be displayed in the tree nodes.  The
  602.          // BSS Tree Control window handle is used in almost all the APIs
  603.          // to the tree control.
  604.  
  605.          hTreeData = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT,
  606.                                                           sizeof (TREE_DATA)) ;
  607.          if(hTreeData != NULL)
  608.          {                                                 
  609.             // Save the above memory handle in the extra window memory reserved
  610.             // during the registration of the "TreeCtrlFrame" class (MDI child
  611.             // window). 
  612.  
  613.             SetWindowWord (hwnd, WND_EXTRA_TREE_DATA, hTreeData) ;
  614.                    
  615.             // Lock down the memory to get the pointer to the instance data 
  616.             // structure.  We will be assigning the newly created BSS Tree
  617.             // Control window handle to the hwndTree member of TREE_DATA.
  618.             // The bitmap handles will also be assigned to members in TREE_DATA
  619.             // to be referenced later.
  620.  
  621.             npTreeData = (NP_TREE_DATA) LocalLock (hTreeData) ;
  622.  
  623.             // Not necessary since the structure allocated above was zero 
  624.             // initialized but the below statement will remain only as a
  625.             // reminder that messages may come into this window procedure
  626.             // during the call to create a tree.  And if the tree control
  627.             // handle is referenced before the return from the call
  628.             // BST_CreateTree, the tree control handle will be invalid.
  629.             // This is the case with WM_SYSCOLORCHANGE.  For unregistered
  630.             // copies of the BSS Tree Control, a modal dialog box is
  631.             // created during the WM_CREATE message of the Tree Control.
  632.             // While this message is up, a user can open the Color Dialog and
  633.             // change a color causing a WM_SYSCOLORCHANGE to be sent to all
  634.             // the top level windows.  Since execution has not returned from 
  635.             // the call to BST_CreateTree but yet the message 
  636.             // WM_SYSCOLORCHANGE is sent to this procedure by its parent, the
  637.             // reference to npTreeData->hwndTree will be invalid and a GP
  638.             // will occur.  Trust me.  This happened.
  639.  
  640.             npTreeData->hwndTree = NULL;
  641.  
  642.             // BST_CreateTree creates a BSS Tree Control.  The parameters are
  643.             // similar to the Windows API CreateWindowEx.  Why have the call
  644.             // anyway?  The API guarantees that the Window style will include
  645.             // the scroll bars, clipping, and helps the programmer use the 
  646.             // right class.  Notice I added a border to the style.  Looks
  647.             // great!  Notice that the starting x, y, width, and height are
  648.             // 0?  This works because the WM_SIZE message handler of this
  649.             // window procedure does a MoveWindow to the BSS Tree Control to
  650.             // keep the tree control sized to the MDI child window.
  651.          
  652.             hwndTree = BST_CreateTree (hInst,hwnd,0, 0, 0,0,WS_BORDER, 0);
  653.          
  654.             if(hwndTree != NULL)
  655.             {
  656.                // Now the assignment of instance data.
  657.  
  658.                npTreeData->hwndTree = hwndTree;
  659.             
  660.   
  661.                // This is a  commented out example to setting the font in the 
  662.                // BSS Tree Control using the BST_SetFont API.  The font could
  663.                // be a result of the font common dialog.
  664.    
  665. //             BST_SetFont( hwndTree,GetStockObject(ANSI_VAR_FONT));
  666.                                    
  667.                // Bitmaps spaces are locations bitmaps are placed in a tree
  668.                // node.  The bitmap spaces are placed left of the text.
  669.                // Below, two bitmap spaces are defined.  The max width
  670.                // and height are defined.  The first argument is the BSS
  671.                // Tree Control handle, the second is the bitmap space
  672.                // identifier (which bitmap space is being defined).  The
  673.                // third and fourth arguments are the width and height
  674.                // respectively.  The last argument signals the BSS Tree
  675.                // Control whether to center or left justify the currently
  676.                // assigned bitmap in this bitmap space.  TRUE means center, 
  677.                // FALSE means left justify.
  678.             
  679.                // This defines the bitmap spaces globally for every tree node.
  680.                // This keeps column alignment of bitmaps on the same level.
  681.    
  682.                BST_SetBitmapSpace( hwndTree, 0, 22, 17, TRUE);
  683.               
  684.                BST_SetBitmapSpace( hwndTree, 1, 42, 20, TRUE);
  685.             
  686.                // Tells the BSS Tree Control to place so many pixels after the
  687.                // last bitmap (if any) and before the first character of the
  688.                // text string.
  689.    
  690.                BST_SetXSpaceBeforeText( hwndTree, SPACE_BEFORE_TEXT);
  691.             
  692.                // By default this is TRUE, but for purpose of demonstration...
  693.    
  694. //               BST_ShowLines( hwndTree, TRUE);                    
  695.    
  696.                // Now, the fun part...  Defining tree nodes.
  697.             
  698.                // First... define the root!
  699.             
  700.                // Allocate a tree node definition for the root. It
  701.                // is best if this memory is initialize to zero.  The tree node
  702.                // definition structure is the vehicle that the application uses
  703.                // to define tree nodes to the BSS Tree Control.  This memory is 
  704.                // the property of the application.  Its contents are copied to 
  705.                // the a newly created tree node in the tree control.  Once the
  706.                // node is defined, this memory can be freed.
  707.    
  708.                lpTreeNodeDef = (LP_TREE_NODE_DEF)
  709.                           MAKEP( GlobalAlloc (GPTR|GMEM_SHARE, 
  710.                                        MAKELONG(sizeof(TREE_NODE_DEF)*1,0)),0);
  711.            
  712.                if(lpTreeNodeDef)
  713.                {                         
  714.                   // Assign the text that will be displayed for the tree node.
  715.       
  716.                   lpTreeNodeDef->lpszText= TreeDatabase[0].lpszNodeText;
  717.                
  718.                   // Length of the above text.
  719.       
  720.                   lpTreeNodeDef->wTextLength = lstrlen(lpTreeNodeDef->lpszText);
  721.  
  722.                   // Since the string for this node is in a static database
  723.                   // and will never be deleted or modified by the application,
  724.                   // there is no need for the tree control to allocated
  725.                   // memory to store it.  Setting the high bit
  726.                   // (0x8000) of the wTextLength member tells the tree control
  727.                   // to use the given pointer directly.  The tree control will
  728.                   // not try to free this memory when the tree node is
  729.                   // deleted.  The tree control simply copies the given
  730.                   // string pointer into the TREE_NODE and uses the pointer
  731.                   // to access the string.
  732.  
  733.                   lpTreeNodeDef->wTextLength |= 0x8000;
  734.  
  735.                   // Setup the lpUserData member.  This member can be used
  736.                   // to store a pointer to application defined memory that
  737.                   // takes advantage of the tree control's structure.  If
  738.                   // this is used for application defined memory, then it
  739.                   // is the responsibility of the application to maintain
  740.                   // it.
  741.                   // To aid in this adventure, the BSS Tree Control exported
  742.                   // API provides a way for the application to define a
  743.                   // callback that will be called everytime a node is deleted.
  744.                
  745.                   // In the below case, the lpUserData is used as a DWORD
  746.                   // storage instead of a pointer for two values that
  747.                   // describe the children of the parent.  The low word is
  748.                   // the offset into the database where the children definition
  749.                   // starts and the high word is the number of children of the
  750.                   // parent.
  751.       
  752.                   wNumberOfChildren = TreeDatabase[0].wNumberOfChildren;
  753.     
  754.       
  755.                   lpTreeNodeDef->lpUserData = MAKEP(wNumberOfChildren,
  756.                                            TreeDatabase[0].wIndexOfChildren);
  757.                                            
  758.                   // No dynamically allocated memory needed from the tree control
  759.                   lpTreeNodeDef->wUserDataSize = 0;                                           
  760.                                            
  761.                   // Assign bitmaps created earlier to the first bitmap space
  762.                   // which were also defined earlier.  PS.  The active bitmap
  763.                   // is the bitmap that is displayed when the tree node is
  764.                   // highlighted.  Currently, there are two bitmap spaces
  765.                   // defined per node.  If more is needed, then the source
  766.                   //  can be purchased and the number of bitmap spaces can
  767.                   // be increased.  In most case only two bitmaps are good
  768.                   // enough.  If any of the bitmap spaces are not used, then
  769.                   // make sure that a NULL handle is assigned to the bitmap
  770.                   // space.
  771.                
  772.                   lpTreeNodeDef->hBitmap[0] = hbmClosed;
  773.       
  774.                   lpTreeNodeDef->hActiveBitmap[0] = hbmClosedActive;
  775.       
  776.                   if(TreeDatabase[0].wBitmapIndex != 0)
  777.                      lpTreeNodeDef->hBitmap[1] = 
  778.                                         hbm[TreeDatabase[0].wBitmapIndex - 1];
  779.                   else 
  780.                      lpTreeNodeDef->hBitmap[1] = NULL;
  781.       
  782.       
  783.                   lpTreeNodeDef->hActiveBitmap[1] = NULL;
  784.                   lpTreeNodeDef->hBitmap[2] = NULL;
  785.                
  786.                
  787.                   // Since the tree node definition structure is defined then
  788.                   // call the BST_AddChildrenToParent API.  Notice the 0L value.
  789.                   // This is the indicator that this node is the root.  The
  790.                   // tree can only have one root.  If the root is NOT defined
  791.                   // then calling any other API will cause havoc.
  792.       
  793.                   wErrCode = 
  794.                         BST_AddChildrenToParent(hwndTree, 0L, 1,lpTreeNodeDef);
  795.                
  796.                   if(HandleAddChildrenError( hwnd, wErrCode) == 0)
  797.                   {
  798.                      // The lpTreeNode member is an important animal.  When 
  799.                      // BST_AddChildrenToParent is called with the tree
  800.                      // node definitions, the tree control internally allocates
  801.                      // the tree node memory in which it stores the tree node
  802.                      // definition information.
  803.                      // The tree control then assigns this new tree node
  804.                      // pointer to the tree node definition member 'lpTreeNode'.
  805.                      // Remember, the tree node definition structure is
  806.                      // shared memory between the application and the tree
  807.                      // control.  The application could use the 'lpTreeNode'
  808.                      // value for future references to the new node such as 
  809.                      // adding nodes as children.
  810.                   
  811.                      // Below, the 'lpTreeNode' member of the tree node
  812.                      // definition is saved.  It will be used as a reference
  813.                      // to add children.  This pointer points to the root tree
  814.                      // node in the tree control.
  815.          
  816.                      lpParentTreeNode = lpTreeNodeDef->lpTreeNode;
  817.          
  818.                      FREEP(lpTreeNodeDef);
  819.                   
  820.                      // Next... define the children of the root.
  821.                      // Allocate the memory (application grown and owned).
  822.          
  823.                      lpTreeNodeDef = (LP_TREE_NODE_DEF)
  824.                         MAKEP(GlobalAlloc(GPTR|GMEM_SHARE, 
  825.                         MAKELONG(sizeof(TREE_NODE_DEF)
  826.                                                  * wNumberOfChildren ,0)),0);
  827.        
  828.                      if(lpTreeNodeDef)
  829.                      {         
  830.                         // Traverse the memory, initializing text, text
  831.                         // length, user data, bitmaps, etc.
  832.             
  833.                         lpTreeNodeDef2 = lpTreeNodeDef; 
  834.             
  835.                         for (i = 0, j = TreeDatabase[0].wIndexOfChildren;
  836.                              i < wNumberOfChildren;
  837.                              i++, lpTreeNodeDef2++, j++)
  838.                         {                         
  839.                            lpTreeNodeDef2->lpszText 
  840.                                               =  TreeDatabase[j].lpszNodeText;
  841.                         
  842.                            lpTreeNodeDef2->lpUserData 
  843.                                      = MAKEP(TreeDatabase[j].wNumberOfChildren,
  844.                                          TreeDatabase[j].wIndexOfChildren);
  845.                                           
  846.                            // No dynamically allocated memory needed from the
  847.                            // tree control
  848.                            lpTreeNodeDef2->wUserDataSize = 0;                                           
  849.                                           
  850.                            if(TreeDatabase[j].wNumberOfChildren == 0)
  851.                            {
  852.                               lpTreeNodeDef2->hBitmap[0] = hbmSheet;
  853.                               lpTreeNodeDef2->hActiveBitmap[0] = hbmSheetActive;
  854.                            }
  855.                            else
  856.                            {
  857.                               lpTreeNodeDef2->hBitmap[0] = hbmClosed;
  858.                               lpTreeNodeDef2->hActiveBitmap[0] 
  859.                                                            = hbmClosedActive;
  860.                            }
  861.                            if(TreeDatabase[j].wBitmapIndex != 0)
  862.                               lpTreeNodeDef2->hBitmap[1] = 
  863.                                         hbm[TreeDatabase[j].wBitmapIndex - 1];
  864.                            else 
  865.                               lpTreeNodeDef2->hBitmap[1] = NULL;
  866.                            lpTreeNodeDef2->hActiveBitmap[1] = NULL;
  867.                            lpTreeNodeDef2->hBitmap[2] = NULL;
  868.                         
  869.                            lpTreeNodeDef2->wTextLength = 
  870.                                              lstrlen(lpTreeNodeDef2->lpszText);
  871.  
  872.                            // Since the string for this node is in a static
  873.                            // database and will never be deleted or
  874.                            // modified by the application, there is no need
  875.                            // for the tree control to allocated memory to
  876.                            // store it.  Setting the high bit (0x8000) of the
  877.                            // wTextLength member tells the tree control to use
  878.                            // the given pointer directly.  The tree control
  879.                            // will not try to free this memory when the tree
  880.                            // node is deleted.  The tree control simply
  881.                            // copies the given string pointer into the
  882.                            // TREE_NODE and uses the pointer to access the
  883.                            // string.
  884.  
  885.                            lpTreeNodeDef2->wTextLength |= 0x8000;
  886.  
  887.                         }          
  888.                      
  889.                         // Add the children to the parent 'lpTreeNode'.
  890.                         // We do not need to store the tree node pointer that
  891.                         // was created as a result of the below call because
  892.                         // we will rely on the notification message that will
  893.                         // be generated when the user clicks or double
  894.                         // clicks on any of these nodes.
  895.             
  896.                         wErrCode = BST_AddChildrenToParent( hwndTree,
  897.                                                  lpParentTreeNode,   // Parent which is the root
  898.                                                  wNumberOfChildren,
  899.                                                  lpTreeNodeDef);
  900.  
  901.                         if(HandleAddChildrenError( hwnd, wErrCode) == 0)
  902.                         {
  903.                            FREEP(lpTreeNodeDef);
  904.                            lpTreeNodeDef = NULL;
  905.                            // Open the folder
  906.  
  907.                            BST_SetBitmapAndActiveBitmap( hwndTree,
  908.                                                          0,
  909.                                                          lpParentTreeNode,
  910.                                                          hbmOpen,
  911.                                                          hbmOpenActive);         
  912.                      
  913.                            SetFocus (hwndTree);
  914.                        
  915.                            ShowWindow (hwndTree, SW_SHOW);
  916.                      
  917.                            lResult = 0L;
  918.                         }
  919.                      }
  920.                      else
  921.                         lResult = 1L;
  922.                   }
  923.                }
  924.                else 
  925.                   lResult = 1L;
  926.             }
  927.             LocalUnlock (hTreeData) ;
  928.             
  929.             if(hwndTree == NULL)
  930.             {
  931.               MessageBox ( hwnd, 
  932.                            "Problem creating tree control.", 
  933.                            "WM_CREATE", 
  934.                            MB_OK);
  935.             
  936.               SetWindowWord (hwnd, WND_EXTRA_TREE_DATA, NULL) ;
  937.               LocalFree (hTreeData);
  938.             }
  939.             else if (lResult != 0L)
  940.             {
  941.                if(lResult == 1L)
  942.                   MessageBox (hwnd, "Out of memory.", "WM_CREATE", MB_OK);
  943.                if(lpTreeNodeDef != NULL)
  944.                   FREEP(lpTreeNodeDef);
  945.                BST_EraseTree( hwndTree);
  946.                LocalFree (hTreeData);
  947.                SetWindowWord (hwnd, WND_EXTRA_TREE_DATA, NULL) ;
  948.                lResult = 0xFFFFFFFF;
  949.             }
  950.          }
  951.          return lResult ;
  952.  
  953.  
  954.       case WM_BST_SELECT_NOTIF_DBLCLK:
  955.       
  956.          // WM_BST_SELECT_NOTIF_DBLCLK is a notification message sent to
  957.          // the application when the user double clicks on a tree node.
  958.          // lParam is a pointer to a notification structure that is owned by
  959.          // the tree control.  DO NOT FREE THIS MEMORY OR ALL HELL WILL 
  960.          // BREAK LOOSE.  The members of the SELECT_NOTIF structure consist
  961.          // of the pointer to the tree node that was selected and a flags
  962.          // member that describes what region of the tree node that was
  963.          // clicked on and if the tree node had children or not (OPEN or
  964.          // CLOSED).
  965.  
  966.          lpSelectNotif = (LP_SELECT_NOTIF) lParam;
  967.          lpParentTreeNode = lpSelectNotif->lpTreeNode;
  968.  
  969.  
  970.          hTreeData  = GetWindowWord (hwnd, WND_EXTRA_TREE_DATA) ;
  971.  
  972.          npTreeData = (NP_TREE_DATA) LocalLock (hTreeData) ; 
  973.          
  974.          // Is the tree node that was selected, OPENED or CLOSED?                 
  975.  
  976.          if(lpSelectNotif->wFlags & NODE_OPENED)
  977.          {
  978.             // Yes... then delete the children
  979.  
  980.             BST_DeleteChildrenOfParent( (HWND)wParam, lpParentTreeNode);
  981.  
  982.             // Close the folder
  983.             BST_SetBitmapAndActiveBitmap( wParam,
  984.                                           0,
  985.                                           lpParentTreeNode,
  986.                                           hbmClosed,
  987.                                           hbmClosedActive);
  988.             }
  989.          else
  990.          {
  991.             // No... then open it and add children if this tree node gots them.
  992.  
  993.             
  994.             // Notice the use of the lpUserData member of the tree node.
  995.             // Creativity is a desire not a disease.
  996.  
  997.             wIndexOfChildren = LOWORD (lpParentTreeNode->lpUserData);
  998.  
  999.             wNumberOfChildren = HIWORD (lpParentTreeNode->lpUserData);
  1000.             
  1001.             if(wNumberOfChildren > 0)
  1002.             {
  1003.                // Define the children as in WM_CREATE: but use the 
  1004.                // tree node pointer defined in the SELECT_NOTIF structure 
  1005.                // (lParam) as the parent.
  1006.  
  1007.                lpTreeNodeDef = (LP_TREE_NODE_DEF)
  1008.                       MAKEP(GlobalAlloc(GPTR|GMEM_SHARE, 
  1009.                       MAKELONG(sizeof(TREE_NODE_DEF)* wNumberOfChildren ,0)),0);
  1010.               
  1011.                if(lpTreeNodeDef)
  1012.                {
  1013.                   lpTreeNodeDef2 = lpTreeNodeDef;
  1014.    
  1015.                   for (i = 0, j = wIndexOfChildren;
  1016.                        i < wNumberOfChildren;
  1017.                        i++, lpTreeNodeDef2++, j++)
  1018.                   {         
  1019.                      lpTreeNodeDef2->lpszText = TreeDatabase[j].lpszNodeText;
  1020.                      lpTreeNodeDef2->wTextLength = 
  1021.                                              lstrlen(lpTreeNodeDef2->lpszText);
  1022.  
  1023.                      // Since the string for this node is in a static
  1024.                      // database and will never be deleted or
  1025.                      // modified by the application, there is no need
  1026.                      // for the tree control to allocated memory to
  1027.                      // store it.  Setting the high bit (0x8000) of the
  1028.                      // wTextLength member tells the tree control to use
  1029.                      // the given pointer directly.  The tree control
  1030.                      // will not try to free this memory when the tree
  1031.                      // node is deleted.  The tree control simply
  1032.                      // copies the given string pointer into the
  1033.                      // TREE_NODE and uses the pointer to access the
  1034.                      // string.
  1035.  
  1036.                      lpTreeNodeDef2->wTextLength |= 0x8000;
  1037.  
  1038.                      lpTreeNodeDef2->lpUserData =
  1039.                                         MAKEP(TreeDatabase[j].wNumberOfChildren,
  1040.                                              TreeDatabase[j].wIndexOfChildren);
  1041.                                              
  1042.                      // No dynamically allocated memory needed from the
  1043.                      // tree control
  1044.                      lpTreeNodeDef2->wUserDataSize = 0;                                           
  1045.                                               
  1046.                      if(TreeDatabase[j].wNumberOfChildren == 0)
  1047.                      {
  1048.                         lpTreeNodeDef2->hBitmap[0] = hbmSheet;
  1049.                         lpTreeNodeDef2->hActiveBitmap[0] = hbmSheetActive;
  1050.                      }
  1051.                      else
  1052.                      {
  1053.                         lpTreeNodeDef2->hBitmap[0] = hbmClosed;
  1054.                         lpTreeNodeDef2->hActiveBitmap[0] = hbmClosedActive;
  1055.                      }   
  1056.                      
  1057.                      if(TreeDatabase[j].wBitmapIndex != 0)
  1058.                         lpTreeNodeDef2->hBitmap[1] = 
  1059.                                            hbm[TreeDatabase[j].wBitmapIndex - 1];
  1060.                      else                   
  1061.                         lpTreeNodeDef2->hBitmap[1] = NULL;
  1062.                      lpTreeNodeDef2->hActiveBitmap[1] = NULL;
  1063.                      lpTreeNodeDef2->hBitmap[2] = NULL;
  1064.                   }
  1065.                   // Add 'em ...
  1066.    
  1067.                   wErrCode = BST_AddChildrenToParent( wParam,
  1068.                                                       lpParentTreeNode,
  1069.                                                       wNumberOfChildren,
  1070.                                                       lpTreeNodeDef);
  1071.                                                       
  1072.                   if(HandleAddChildrenError( hwnd, wErrCode) == 0)
  1073.                   {
  1074.                      // Open the folder of the parent
  1075.    
  1076.                      BST_SetBitmapAndActiveBitmap( wParam,
  1077.                                                    0,
  1078.                                                    lpParentTreeNode,
  1079.                                                    hbmOpen,
  1080.                                                    hbmOpenActive);
  1081.                   }               
  1082.                   FREEP(lpTreeNodeDef);
  1083.                }
  1084.                else
  1085.                {
  1086.                   MessageBox ( hwnd, 
  1087.                                "Out of memory.", 
  1088.                                "WM_BST_SELECT_NOTIF_DBLCLK",
  1089.                                MB_OK);
  1090.                }
  1091.             }
  1092.             }
  1093.          LocalUnlock (hTreeData) ;            
  1094.          return 0;
  1095.  
  1096.  
  1097.       case WM_SYSCOLORCHANGE:
  1098.  
  1099.          // Sad but true...  The WM_SYSCOLORCHANGE notification has be sent
  1100.          // to the tree control since only top level windows get this
  1101.          // notification.  Since the colors are going to change in the 
  1102.          // tree control, better make sure that the background color of
  1103.          // the bitmaps is correct.
  1104.  
  1105.          hTreeData  = GetWindowWord (hwnd, WND_EXTRA_TREE_DATA) ;
  1106.          npTreeData = (NP_TREE_DATA) LocalLock (hTreeData);
  1107.          if(npTreeData->hwndTree)
  1108.             SendMessage (npTreeData->hwndTree, message, wParam, lParam);
  1109.          LocalUnlock (hTreeData) ;            
  1110.          return 0;       
  1111.  
  1112.  
  1113.       case WM_SETFOCUS:
  1114.       
  1115.          // Keep the focus on the tree control.
  1116.          
  1117.          hTreeData  = GetWindowWord (hwnd, WND_EXTRA_TREE_DATA) ;
  1118.          if(hTreeData)
  1119.          {
  1120.             npTreeData = (NP_TREE_DATA) LocalLock (hTreeData) ;
  1121.             SetFocus(npTreeData->hwndTree);
  1122.             LocalUnlock (hTreeData) ;       
  1123.          }
  1124.          break;
  1125.          
  1126.       case WM_SIZE:
  1127.          // Keep the tree control in the client area of the
  1128.          // MDI child window.
  1129.  
  1130.          hTreeData  = GetWindowWord (hwnd, WND_EXTRA_TREE_DATA) ;
  1131.          if(hTreeData)
  1132.          {
  1133.             npTreeData = (NP_TREE_DATA) LocalLock (hTreeData) ;
  1134.             cx = GetSystemMetrics ( SM_CXVSCROLL) / 2;
  1135.             cy = GetSystemMetrics ( SM_CYHSCROLL) / 2;
  1136.             MoveWindow ( npTreeData->hwndTree,
  1137.                          cx,
  1138.                          cy,
  1139.                          max(LOWORD(lParam) - 2 * cx, 0),
  1140.                          max(HIWORD(lParam) - 2 * cy, 0),
  1141.                          TRUE);
  1142.  
  1143.             LocalUnlock (hTreeData) ;             
  1144.          }
  1145.          break;
  1146.          
  1147.       case WM_MDIACTIVATE:
  1148.       
  1149.          if (wParam == TRUE)
  1150.             SendMessage ( hwndClient,
  1151.                           WM_MDISETMENU,
  1152.                           0,
  1153.                           MAKELONG (hMenuTreeCtrl, hMenuTreeCtrlWindow)) ;
  1154.  
  1155.          if (wParam == FALSE)
  1156.             SendMessage ( hwndClient,
  1157.                           WM_MDISETMENU,
  1158.                           0,
  1159.                           MAKELONG (hMenuInit, hMenuInitWindow)) ;
  1160.  
  1161.          DrawMenuBar (hwndFrame) ;
  1162.          return 0 ;
  1163.          
  1164.       case WM_DESTROY:
  1165.  
  1166.          // Clean up time.  The tree control will receive a WM_DESTROY
  1167.          // therefore it will automatically free all memory it owns.
  1168.          // But the bitmaps are the property of the application so it must
  1169.          // free these objects.
  1170.  
  1171.          hTreeData  = GetWindowWord (hwnd, WND_EXTRA_TREE_DATA) ;
  1172.          if(hTreeData)
  1173.          {
  1174.             npTreeData = (NP_TREE_DATA) LocalLock (hTreeData) ;
  1175.             BST_EraseTree( npTreeData->hwndTree);  // Do a erase tree first before
  1176.                                                 // freeing bitmaps since the
  1177.                                                 // tree may need these objects
  1178.             LocalUnlock (hTreeData) ;             
  1179.             LocalFree(hTreeData);
  1180.          }            
  1181.          return 0 ;
  1182.    }
  1183.    return DefMDIChildProc (hwnd, message, wParam, lParam) ;
  1184. }
  1185.  
  1186.  
  1187.  
  1188.  
  1189.  
  1190. /*****************************************************************************
  1191. long FAR PASCAL _export ListCtrlFrameWndProc ( HWND hwnd,
  1192.                                                UINT message,
  1193.                                                UINT wParam,
  1194.                                                LONG lParam)
  1195.  
  1196.  
  1197.  This is the window procedure of the MDI child window.  When this procedure
  1198.  receives it's WM_CREATE message, a BSS Tree Control is created as a child
  1199.  window (control).  
  1200.                  
  1201.  After this tree is created, it is populated with the root node and the first
  1202.  level nodes taken from the database described in the file which
  1203.  is in RCDATA format.
  1204.                  
  1205.  When a user double clicks on any of these nodes, the MDI child window (which
  1206.  is the parent of the BSS Tree Control) will receive a notification.
  1207.  This notification describes the node that was selected by the
  1208.  double click.  The MDI child window will respond by taking the key index of
  1209.  the node that was clicked on, use it to access the database, and retrieve the
  1210.  list of children for that node.  The BSS Tree Control is sent this list via
  1211.  the exported API, BST_AddChildrenToParent, and SLAM!  The list of children
  1212.  for the selected node is displayed. 
  1213.  
  1214.  This MDI child window procedure also demonstrates the passing of the
  1215.  WM_SYSCOLORCHANGE notification to the BSS Tree Control for system color
  1216.  changes.
  1217.  
  1218.  REMEMBER:
  1219.  
  1220.  The database that is used in this example is just one storage system.
  1221.  The database could be a file system, a finite state machine, a relational
  1222.  database browser, a network map, etc.
  1223.  
  1224. ******************************************************************************/
  1225.  
  1226. long FAR PASCAL _export ListCtrlFrameWndProc ( HWND hwnd,
  1227.                                                UINT message,
  1228.                                                UINT wParam,
  1229.                                                LONG lParam)
  1230. {
  1231.    static HWND        hwndClient;
  1232.    static HWND        hwndFrame ;
  1233.    // The following are important pointers in the process of building the
  1234.    // tree.  The structure definition that these pointers point to are defined
  1235.    // in bstree.h
  1236.    LP_TREE_NODE       lpParentTreeNode; // Points to a tree node
  1237.    LP_TREE_NODE_DEF   lpTreeNodeDef;    // Points to an array of 1 or more
  1238.                                         // tree node definitions that are
  1239.                                         // defined by the application.
  1240.    LP_TREE_NODE_DEF   lpTreeNodeDef2;   // Runner used to traverse the list
  1241.                                         // tree node definitions pointed to 
  1242.                                         // by the pointer above.
  1243.    LP_SELECT_NOTIF    lpSelectNotif;    // Pointer to the tree control owned
  1244.                                         // notification structure used to 
  1245.                                         // pass information about a tree node
  1246.                                         // to the application.
  1247.    WORD               i;
  1248.    WORD               j;
  1249.    HWND               hwndTree;         
  1250.    WORD               wNumberOfChildren;
  1251.    WORD               wIndexOfChildren;
  1252.    LOCALHANDLE        hListData ;
  1253.    NP_LIST_DATA       npListData ;   
  1254.    short              cx, cy;
  1255.    WORD               wErrCode;
  1256.    LONG               lResult;
  1257.    
  1258.    switch (message)
  1259.    {
  1260.       case WM_CREATE:
  1261.          hwndClient = GetParent (hwnd) ;
  1262.                   
  1263.          hwndFrame  = GetParent (hwndClient) ;      
  1264.       
  1265.          lResult = 0xFFFFFFFF;
  1266.  
  1267.          // Allocate the instance data for this MDI child window. This data
  1268.          // structure will hold the window handle of the tree control and the
  1269.          // handles of the bitmaps to be displayed in the tree nodes.  The
  1270.          // BSS Tree Control window handle is used in almost all the APIs
  1271.          // to the tree control.
  1272.  
  1273.          hListData = LocalAlloc (LMEM_MOVEABLE | LMEM_ZEROINIT,
  1274.                                                           sizeof (LIST_DATA)) ;
  1275.          if(hListData != NULL)
  1276.          {                                                 
  1277.             // Save the above memory handle in the extra window memory reserved
  1278.             // during the registration of the "ListCtrlFrame" class (MDI child
  1279.             // window). 
  1280.  
  1281.             SetWindowWord (hwnd, WND_EXTRA_LIST_DATA, hListData) ;
  1282.                    
  1283.             // Lock down the memory to get the pointer to the instance data 
  1284.             // structure.  We will be assigning the newly created BSS Tree
  1285.             // Control window handle to the hwndTree member of LIST_DATA.
  1286.             // The bitmap handles will also be assigned to members in
  1287.             // LIST_DATA to be referenced later.
  1288.  
  1289.             npListData = (NP_LIST_DATA) LocalLock (hListData) ;
  1290.  
  1291.             // Not necessary since the structure allocated above was zero 
  1292.             // initialized but the below statement will remain only as a
  1293.             // reminder that messages may come into this window procedure
  1294.             // during the call to create a tree.  And if the tree control
  1295.             // handle is referenced before the return from the call
  1296.             // BST_CreateTree, the tree control handle will be invalid.
  1297.             // This is the case with WM_SYSCOLORCHANGE.  For unregistered
  1298.             // copies of the BSS Tree Control, a modal dialog box is
  1299.             // created during the WM_CREATE message of the Tree Control.
  1300.             // While this message is up, a user can open the Color Dialog and
  1301.             // change a color causing a WM_SYSCOLORCHANGE to be sent to all
  1302.             // the top level windows.  Since execution has not returned from 
  1303.             // the call to BST_CreateTree but yet the message 
  1304.             // WM_SYSCOLORCHANGE is sent to this procedure by its parent, the
  1305.             // reference to npListData->hwndTree will be invalid and a GP
  1306.             // will occur.  Trust me.  This happened.
  1307.  
  1308.             npListData->hwndTree = NULL;
  1309.  
  1310.             // BST_CreateTree creates a BSS Tree Control.  The parameters are
  1311.             // similar to the Windows API CreateWindowEx.  Why have the call
  1312.             // anyway?  The API guarantees that the Window style will include
  1313.             // the scroll bars, clipping, and helps the programmer use the 
  1314.             // right class.  Notice I added a border to the style.  Looks
  1315.             // great!  Notice that the starting x, y, width, and height are
  1316.             // 0?  This works because the WM_SIZE message handler of this
  1317.             // window procedure does a MoveWindow to the BSS Tree Control to
  1318.             // keep the tree control sized to the MDI child window.
  1319.          
  1320.             hwndTree = BST_CreateTree (hInst,hwnd,0, 0, 0,0,WS_BORDER, 0);
  1321.          
  1322.             if(hwndTree != NULL)
  1323.             {
  1324.                // Now the assignment of instance data.
  1325.  
  1326.                npListData->hwndTree = hwndTree;
  1327.             
  1328.   
  1329.                // This is a  commented out example to setting the font in the 
  1330.                // BSS Tree Control using the BST_SetFont API.  The font could
  1331.                // be a result of the font common dialog.
  1332.    
  1333.    //         BST_SetFont( hwndTree,GetStockObject(ANSI_VAR_FONT));
  1334.                                    
  1335.                // Bitmaps spaces are locations bitmaps are placed in a tree
  1336.                // node.  The bitmap spaces are placed left of the text.
  1337.                // Below, two bitmap spaces are defined.  The max width
  1338.                // and height are defined.  The first argument is the BSS
  1339.                // Tree Control handle, the second is the bitmap space
  1340.                // identifier (which bitmap space is being defined).  The
  1341.                // third and fourth arguments are the width and height
  1342.                // respectively.  The last argument signals the BSS Tree
  1343.                // Control whether to center or left justify the currently
  1344.                // assigned bitmap in this bitmap space.  TRUE means center, 
  1345.                // FALSE means left justify.
  1346.             
  1347.                // This defines the bitmap spaces globally for every tree node.
  1348.                // This keeps column alignment of bitmaps on the same level.
  1349.    
  1350.                BST_SetBitmapSpace( hwndTree, 0, 22, 17, TRUE);
  1351.               
  1352.                BST_SetBitmapSpace( hwndTree, 1, 42, 20, TRUE);
  1353.             
  1354.                // Tells the BSS Tree Control to place so many pixels after the
  1355.                // last bitmap (if any) and before the first character of the
  1356.                // text string.
  1357.    
  1358.                BST_SetXSpaceBeforeText( hwndTree, SPACE_BEFORE_TEXT);
  1359.             
  1360.                // By default this is TRUE, but for purpose of demonstration...
  1361.    
  1362. //               BST_ShowLines( hwndTree, TRUE);                    
  1363.    
  1364.                // Now, the fun part...  Defining tree nodes.
  1365.             
  1366.                // First... define the root!
  1367.             
  1368.                // Allocate a tree node definition for the root. It
  1369.                // is best if this memory is initialize to zero.  The tree node
  1370.                // definition structure is the vehicle that the application uses
  1371.                // to define tree nodes to the BSS Tree Control.  This memory is 
  1372.                // the property of the application.  Its contents are copied to 
  1373.                // the a newly created tree node in the tree control.  Once the
  1374.                // node is defined, this memory can be freed.
  1375.    
  1376.                lpTreeNodeDef = (LP_TREE_NODE_DEF)
  1377.                           MAKEP( GlobalAlloc (GPTR|GMEM_SHARE, 
  1378.                                        MAKELONG(sizeof(TREE_NODE_DEF)*1,0)),0);
  1379.            
  1380.                if(lpTreeNodeDef)
  1381.                {                         
  1382.                   // Assign the text that will be displayed for the tree node.
  1383.       
  1384.                   lpTreeNodeDef->lpszText = ListDatabase[0].lpszNodeText;
  1385.                
  1386.                   // Length of the above text.
  1387.       
  1388.                   lpTreeNodeDef->wTextLength = lstrlen(lpTreeNodeDef->lpszText);
  1389.  
  1390.                   // Since the string for this node is in a static database
  1391.                   // and will never be deleted or modified by the application,
  1392.                   // there is no need for the tree control to allocated
  1393.                   // memory to store it.  Setting the high bit
  1394.                   // (0x8000) of the wTextLength member tells the tree control
  1395.                   // to use the given pointer directly.  The tree control will
  1396.                   // not try to free this memory when the tree node is
  1397.                   // deleted.  The tree control simply copies the given
  1398.                   // string pointer into the TREE_NODE and uses the pointer
  1399.                   // to access the string.
  1400.  
  1401.                   lpTreeNodeDef->wTextLength |= 0x8000;
  1402.  
  1403.                   // Setup the lpUserData member.  This member can be used
  1404.                   // to store a pointer to application defined memory that
  1405.                   // takes advantage of the tree control's structure.  If
  1406.                   // this is used for application defined memory, then it
  1407.                   // is the responsibility of the application to maintain
  1408.                   // it.
  1409.                   // To aid in this adventure, the BSS Tree Control exported
  1410.                   // API provides a way for the application to define a
  1411.                   // callback that will be called everytime a node is deleted.
  1412.                
  1413.                   // In the below case, the lpUserData is used as a DWORD
  1414.                   // storage instead of a pointer for two values that
  1415.                   // describe the children of the parent.  The low word is
  1416.                   // the offset into the database where the children definition
  1417.                   // starts and the high word is the number of children of the
  1418.                   // parent.
  1419.       
  1420.                   wNumberOfChildren = ListDatabase[0].wNumberOfChildren;
  1421.     
  1422.       
  1423.                   lpTreeNodeDef->lpUserData = MAKEP(wNumberOfChildren,
  1424.                                            ListDatabase[0].wIndexOfChildren);
  1425.                                            
  1426.                   // No dynamically allocated memory needed from the tree control
  1427.                   lpTreeNodeDef->wUserDataSize = 0;                                           
  1428.                                            
  1429.                   // Assign bitmaps created earlier to the first bitmap space
  1430.                   // which were also defined earlier.  PS.  The active bitmap
  1431.                   // is the bitmap that is displayed when the tree node is
  1432.                   // highlighted.  Currently, there are two bitmap spaces
  1433.                   // defined per node.  If more is needed, then the source
  1434.                   //  can be purchased and the number of bitmap spaces can
  1435.                   // be increased.  In most case only two bitmaps are good
  1436.                   // enough.  If any of the bitmap spaces are not used, then
  1437.                   // make sure that a NULL handle is assigned to the bitmap
  1438.                   // space.
  1439.                
  1440.                   lpTreeNodeDef->hBitmap[0] = hbmClosed;
  1441.       
  1442.                   lpTreeNodeDef->hActiveBitmap[0] = hbmClosedActive;
  1443.       
  1444.                   if(ListDatabase[0].wBitmapIndex != 0)
  1445.                      lpTreeNodeDef->hBitmap[1] = 
  1446.                                         hbm[ListDatabase[0].wBitmapIndex - 1];
  1447.                   else 
  1448.                      lpTreeNodeDef->hBitmap[1] = NULL;
  1449.       
  1450.       
  1451.                   lpTreeNodeDef->hActiveBitmap[1] = NULL;
  1452.                   lpTreeNodeDef->hBitmap[2] = NULL;
  1453.                
  1454.                
  1455.                   // Since the tree node definition structure is defined then
  1456.                   // call the BST_AddChildrenToParent API.  Notice the 0L value.
  1457.                   // This is the indicator that this node is the root.  The
  1458.                   // tree can only have one root.  If the root is NOT defined
  1459.                   // then calling any other API will cause havoc.
  1460.       
  1461.                   wErrCode = 
  1462.                         BST_AddChildrenToParent(hwndTree, 0L, 1,lpTreeNodeDef);
  1463.                
  1464.                   if(HandleAddChildrenError( hwnd, wErrCode) == 0)
  1465.                   {
  1466.                      // The lpTreeNode member is an important animal.  When 
  1467.                      // BST_AddChildrenToParent is called with the tree
  1468.                      // node definitions, the tree control internally allocates
  1469.                      // the tree node memory in which it stores the tree node
  1470.                      // definition information.
  1471.                      // The tree control then assigns this new tree node
  1472.                      // pointer to the tree node definition member 'lpTreeNode'.
  1473.                      // Remember, the tree node definition structure is
  1474.                      // shared memory between the application and the tree
  1475.                      // control.  The application could use the 'lpTreeNode'
  1476.                      // value for future references to the new node such as 
  1477.                      // adding nodes as children.
  1478.                   
  1479.                      // Below, the 'lpTreeNode' member of the tree node
  1480.                      // definition is saved.  It will be used as a reference
  1481.                      // to add children.  This pointer points to the root tree
  1482.                      // node in the tree control.
  1483.          
  1484.                      lpParentTreeNode = lpTreeNodeDef->lpTreeNode;
  1485.          
  1486.                      FREEP(lpTreeNodeDef);
  1487.                   
  1488.                      // Next... define the children of the root.
  1489.                      // Allocate the memory (application grown and owned).
  1490.          
  1491.                      lpTreeNodeDef = (LP_TREE_NODE_DEF)
  1492.                                 MAKEP(GlobalAlloc(GPTR|GMEM_SHARE, 
  1493.                                         MAKELONG(sizeof(TREE_NODE_DEF)
  1494.                                                  * wNumberOfChildren ,0)),0);
  1495.        
  1496.                      if(lpTreeNodeDef)
  1497.                      {         
  1498.                         // Traverse the memory, initializing text, text
  1499.                         // length, user data, bitmaps, etc.
  1500.             
  1501.                         lpTreeNodeDef2 = lpTreeNodeDef; 
  1502.             
  1503.                         for (i = 0, j = ListDatabase[0].wIndexOfChildren;
  1504.                              i < wNumberOfChildren;
  1505.                              i++, lpTreeNodeDef2++, j++)
  1506.                         {                         
  1507.                            lpTreeNodeDef2->lpszText 
  1508.                                               = ListDatabase[j].lpszNodeText;
  1509.                         
  1510.                            lpTreeNodeDef2->lpUserData 
  1511.                                      = MAKEP(ListDatabase[j].wNumberOfChildren,
  1512.                                          ListDatabase[j].wIndexOfChildren);
  1513.                                           
  1514.                            // No dynamically allocated memory needed from the
  1515.                            // tree control
  1516.                            lpTreeNodeDef2->wUserDataSize = 0;                                           
  1517.                                           
  1518.                            if(ListDatabase[j].wNumberOfChildren == 0)
  1519.                            {
  1520.                               lpTreeNodeDef2->hBitmap[0] = hbmSheet;
  1521.                               lpTreeNodeDef2->hActiveBitmap[0] = hbmSheetActive;
  1522.                            }
  1523.                            else
  1524.                            {
  1525.                               lpTreeNodeDef2->hBitmap[0] = hbmClosed;
  1526.                               lpTreeNodeDef2->hActiveBitmap[0] 
  1527.                                                            = hbmClosedActive;
  1528.                            }
  1529.                            if(ListDatabase[j].wBitmapIndex != 0)
  1530.                               lpTreeNodeDef2->hBitmap[1] = 
  1531.                                         hbm[ListDatabase[j].wBitmapIndex - 1];
  1532.                            else 
  1533.                               lpTreeNodeDef2->hBitmap[1] = NULL;
  1534.                            lpTreeNodeDef2->hActiveBitmap[1] = NULL;
  1535.                            lpTreeNodeDef2->hBitmap[2] = NULL;
  1536.                         
  1537.                            lpTreeNodeDef2->wTextLength = 
  1538.                                              lstrlen(lpTreeNodeDef2->lpszText);
  1539.  
  1540.                            // Since the string for this node is in a static
  1541.                            // database and will never be deleted or
  1542.                            // modified by the application, there is no need
  1543.                            // for the tree control to allocated memory to
  1544.                            // store it.  Setting the high bit (0x8000) of the
  1545.                            // wTextLength member tells the tree control to use
  1546.                            // the given pointer directly.  The tree control
  1547.                            // will not try to free this memory when the tree
  1548.                            // node is deleted.  The tree control simply
  1549.                            // copies the given string pointer into the
  1550.                            // TREE_NODE and uses the pointer to access the
  1551.                            // string.
  1552.  
  1553.                            lpTreeNodeDef2->wTextLength |= 0x8000;
  1554.  
  1555.                         }          
  1556.                      
  1557.                         // Add the children to the parent 'lpTreeNode'.
  1558.                         // We do not need to store the tree node pointer that
  1559.                         // was created as a result of the below call because
  1560.                         // we will rely on the notification message that will
  1561.                         // be generated when the user clicks or double
  1562.                         // clicks on any of these nodes.
  1563.             
  1564.                         wErrCode = BST_AddChildrenToParent( hwndTree,
  1565.                                                  lpParentTreeNode,   // Parent which is the root
  1566.                                                  wNumberOfChildren,
  1567.                                                  lpTreeNodeDef);
  1568.  
  1569.                         if(HandleAddChildrenError( hwnd, wErrCode) == 0)
  1570.                         {
  1571.                            FREEP(lpTreeNodeDef);
  1572.                            lpTreeNodeDef = NULL;
  1573.                            // Open the folder
  1574.  
  1575.                            BST_SetBitmapAndActiveBitmap( hwndTree,
  1576.                                                          0,
  1577.                                                          lpParentTreeNode,
  1578.                                                          hbmOpen,
  1579.                                                          hbmOpenActive);         
  1580.                      
  1581.                            SetFocus (hwndTree);
  1582.                        
  1583.                            ShowWindow (hwndTree, SW_SHOW);
  1584.                      
  1585.                            lResult = 0L;
  1586.                         }
  1587.                      }
  1588.                      else
  1589.                         lResult = 1L;
  1590.                   }
  1591.                }
  1592.                else 
  1593.                   lResult = 1L;
  1594.             }
  1595.             LocalUnlock (hListData) ;
  1596.             
  1597.             if(hwndTree == NULL)
  1598.             {
  1599.               MessageBox ( hwnd, 
  1600.                            "Problem creating tree control.", 
  1601.                            "WM_CREATE", 
  1602.                            MB_OK);
  1603.             
  1604.               SetWindowWord (hwnd, WND_EXTRA_LIST_DATA, NULL) ;
  1605.               LocalFree (hListData);
  1606.             }
  1607.             else if (lResult != 0L)
  1608.             {
  1609.                if(lResult == 1L)
  1610.                   MessageBox (hwnd, "Out of memory.", "WM_CREATE", MB_OK);
  1611.                if(lpTreeNodeDef != NULL)
  1612.                   FREEP(lpTreeNodeDef);
  1613.                BST_EraseTree( hwndTree);
  1614.                LocalFree (hListData);
  1615.                SetWindowWord (hwnd, WND_EXTRA_LIST_DATA, NULL) ;
  1616.                lResult = 0xFFFFFFFF;
  1617.             }
  1618.          }
  1619.          return lResult ;
  1620.  
  1621.  
  1622.       case WM_BST_SELECT_NOTIF_DBLCLK:
  1623.       
  1624.          // WM_BST_SELECT_NOTIF_DBLCLK is a notification message sent to
  1625.          // the application when the user double clicks on a tree node.
  1626.          // lParam is a pointer to a notification structure that is owned by
  1627.          // the tree control.  DO NOT FREE THIS MEMORY OR ALL HELL WILL 
  1628.          // BREAK LOOSE.  The members of the SELECT_NOTIF structure consist
  1629.          // of the pointer to the tree node that was selected and a flags
  1630.          // member that describes what region of the tree node that was
  1631.          // clicked on and if the tree node had children or not (OPEN or
  1632.          // CLOSED).
  1633.  
  1634.          lpSelectNotif = (LP_SELECT_NOTIF) lParam;
  1635.          lpParentTreeNode = lpSelectNotif->lpTreeNode;
  1636.  
  1637.  
  1638.          hListData  = GetWindowWord (hwnd, WND_EXTRA_LIST_DATA) ;
  1639.  
  1640.          npListData = (NP_LIST_DATA) LocalLock (hListData) ; 
  1641.          
  1642.          // Is the tree node that was selected, OPENED or CLOSED?                 
  1643.  
  1644.          if(lpSelectNotif->wFlags & NODE_OPENED)
  1645.          {
  1646.             // Yes... then delete the children
  1647.  
  1648.             BST_DeleteChildrenOfParent( (HWND)wParam, lpParentTreeNode);
  1649.  
  1650.             // Close the folder
  1651.             BST_SetBitmapAndActiveBitmap( wParam,
  1652.                                           0,
  1653.                                           lpParentTreeNode,
  1654.                                           hbmClosed,
  1655.                                           hbmClosedActive);
  1656.             }
  1657.          else
  1658.          {
  1659.             // No... then open it and add children if this tree node gots them.
  1660.  
  1661.             
  1662.             // Notice the use of the lpUserData member of the tree node.
  1663.             // Creativity is a desire not a disease.
  1664.  
  1665.             wIndexOfChildren = LOWORD (lpParentTreeNode->lpUserData);
  1666.  
  1667.             wNumberOfChildren = HIWORD (lpParentTreeNode->lpUserData);
  1668.             
  1669.             if(wNumberOfChildren > 0)
  1670.             {
  1671.                // Define the children as in WM_CREATE: but use the 
  1672.                // tree node pointer defined in the SELECT_NOTIF structure 
  1673.                // (lParam) as the parent.
  1674.  
  1675.                lpTreeNodeDef = (LP_TREE_NODE_DEF)
  1676.                       MAKEP(GlobalAlloc(GPTR|GMEM_SHARE, 
  1677.                       MAKELONG(sizeof(TREE_NODE_DEF)* wNumberOfChildren ,0)),0);
  1678.               
  1679.                if(lpTreeNodeDef)
  1680.                {
  1681.                   lpTreeNodeDef2 = lpTreeNodeDef;
  1682.    
  1683.                   for (i = 0, j = wIndexOfChildren;
  1684.                        i < wNumberOfChildren;
  1685.                        i++, lpTreeNodeDef2++, j++)
  1686.                   {         
  1687.                      lpTreeNodeDef2->lpszText = ListDatabase[j].lpszNodeText;
  1688.                      lpTreeNodeDef2->wTextLength = 
  1689.                                              lstrlen(lpTreeNodeDef2->lpszText);
  1690.  
  1691.                      // Since the string for this node is in a static
  1692.                      // database and will never be deleted or
  1693.                      // modified by the application, there is no need
  1694.                      // for the tree control to allocated memory to
  1695.                      // store it.  Setting the high bit (0x8000) of the
  1696.                      // wTextLength member tells the tree control to use
  1697.                      // the given pointer directly.  The tree control
  1698.                      // will not try to free this memory when the tree
  1699.                      // node is deleted.  The tree control simply
  1700.                      // copies the given string pointer into the
  1701.                      // TREE_NODE and uses the pointer to access the
  1702.                      // string.
  1703.  
  1704.                      lpTreeNodeDef2->wTextLength |= 0x8000;
  1705.  
  1706.                      lpTreeNodeDef2->lpUserData =
  1707.                                         MAKEP(ListDatabase[j].wNumberOfChildren,
  1708.                                              ListDatabase[j].wIndexOfChildren);
  1709.                                              
  1710.                      // No dynamically allocated memory needed from the
  1711.                      // tree control
  1712.                      lpTreeNodeDef2->wUserDataSize = 0;                                           
  1713.                                               
  1714.                      if(ListDatabase[j].wNumberOfChildren == 0)
  1715.                      {
  1716.                         lpTreeNodeDef2->hBitmap[0] = hbmSheet;
  1717.                         lpTreeNodeDef2->hActiveBitmap[0] = hbmSheetActive;
  1718.                      }
  1719.                      else
  1720.                      {
  1721.                         lpTreeNodeDef2->hBitmap[0] = hbmClosed;
  1722.                         lpTreeNodeDef2->hActiveBitmap[0] = hbmClosedActive;
  1723.                      }   
  1724.                      
  1725.                      if(ListDatabase[j].wBitmapIndex != 0)
  1726.                         lpTreeNodeDef2->hBitmap[1] = 
  1727.                                            hbm[ListDatabase[j].wBitmapIndex - 1];
  1728.                      else                   
  1729.                         lpTreeNodeDef2->hBitmap[1] = NULL;
  1730.                      lpTreeNodeDef2->hActiveBitmap[1] = NULL;
  1731.                      lpTreeNodeDef2->hBitmap[2] = NULL;
  1732.                   }
  1733.                   // Add 'em ...
  1734.    
  1735.                   wErrCode = BST_AddChildrenToParent( wParam,
  1736.                                                       lpParentTreeNode,
  1737.                                                       wNumberOfChildren,
  1738.                                                       lpTreeNodeDef);
  1739.                                                       
  1740.                   if(HandleAddChildrenError( hwnd, wErrCode) == 0)
  1741.                   {
  1742.                      // Open the folder of the parent
  1743.    
  1744.                      BST_SetBitmapAndActiveBitmap( wParam,
  1745.                                                    0,
  1746.                                                    lpParentTreeNode,
  1747.                                                    hbmOpen,
  1748.                                                    hbmOpenActive);
  1749.                   }               
  1750.                   FREEP(lpTreeNodeDef);
  1751.                }
  1752.                else
  1753.                {
  1754.                   MessageBox ( hwnd, 
  1755.                                "Out of memory.", 
  1756.                                "WM_BST_SELECT_NOTIF_DBLCLK",
  1757.                                MB_OK);
  1758.                }
  1759.             }
  1760.             }
  1761.          LocalUnlock (hListData) ;            
  1762.          return 0;
  1763.  
  1764.  
  1765.       case WM_SYSCOLORCHANGE:
  1766.  
  1767.          // Sad but true...  The WM_SYSCOLORCHANGE notification has be sent
  1768.          // to the tree control since only top level windows get this
  1769.          // notification.  Since the colors are going to change in the 
  1770.          // tree control, better make sure that the background color of
  1771.          // the bitmaps is correct.
  1772.  
  1773.          hListData  = GetWindowWord (hwnd, WND_EXTRA_LIST_DATA) ;
  1774.          npListData = (NP_LIST_DATA) LocalLock (hListData);
  1775.          if(npListData->hwndTree)
  1776.             SendMessage (npListData->hwndTree, message, wParam, lParam);
  1777.          LocalUnlock (hListData) ;            
  1778.          return 0;       
  1779.  
  1780.  
  1781.       case WM_SETFOCUS:
  1782.       
  1783.          // Keep the focus on the tree control.
  1784.          
  1785.          hListData  = GetWindowWord (hwnd, WND_EXTRA_LIST_DATA) ;
  1786.          if(hListData)
  1787.          {
  1788.             npListData = (NP_LIST_DATA) LocalLock (hListData) ;
  1789.             SetFocus(npListData->hwndTree);
  1790.             LocalUnlock (hListData) ;       
  1791.          }
  1792.          break;
  1793.          
  1794.       case WM_SIZE:
  1795.          // Keep the tree control in the client area of the
  1796.          // MDI child window.
  1797.  
  1798.          hListData  = GetWindowWord (hwnd, WND_EXTRA_LIST_DATA) ;
  1799.          if(hListData)
  1800.          {
  1801.             npListData = (NP_LIST_DATA) LocalLock (hListData) ;
  1802.             cx = GetSystemMetrics ( SM_CXVSCROLL) / 2;
  1803.             cy = GetSystemMetrics ( SM_CYHSCROLL) / 2;
  1804.             MoveWindow ( npListData->hwndTree,
  1805.                          cx,
  1806.                          cy,
  1807.                          max(LOWORD(lParam) - 2 * cx, 0),
  1808.                          max(HIWORD(lParam) - 2 * cy, 0),
  1809.                          TRUE);
  1810.  
  1811.             LocalUnlock (hListData) ;             
  1812.          }
  1813.          break;
  1814.          
  1815.       case WM_MDIACTIVATE:
  1816.       
  1817.          if (wParam == TRUE)
  1818.             SendMessage ( hwndClient,
  1819.                           WM_MDISETMENU,
  1820.                           0,
  1821.                           MAKELONG (hMenuTreeCtrl, hMenuTreeCtrlWindow)) ;
  1822.  
  1823.          if (wParam == FALSE)
  1824.             SendMessage ( hwndClient,
  1825.                           WM_MDISETMENU,
  1826.                           0,
  1827.                           MAKELONG (hMenuInit, hMenuInitWindow)) ;
  1828.  
  1829.          DrawMenuBar (hwndFrame) ;
  1830.          return 0 ;
  1831.          
  1832.       case WM_DESTROY:
  1833.  
  1834.          // Clean up time.  The tree control will receive a WM_DESTROY
  1835.          // therefore it will automatically free all memory it owns.
  1836.          // But the bitmaps are the property of the application so it must
  1837.          // free these objects.
  1838.  
  1839.          hListData  = GetWindowWord (hwnd, WND_EXTRA_LIST_DATA) ;
  1840.          if(hListData)
  1841.          {
  1842.             npListData = (NP_LIST_DATA) LocalLock (hListData) ;
  1843.             BST_EraseTree( npListData->hwndTree);  // Do a erase tree first before
  1844.                                                 // freeing bitmaps since the
  1845.                                                 // tree may need these objects
  1846.             LocalUnlock (hListData) ;             
  1847.             LocalFree(hListData);
  1848.          }            
  1849.          return 0 ;
  1850.    }
  1851.    return DefMDIChildProc (hwnd, message, wParam, lParam) ;
  1852. }
  1853.  
  1854.  
  1855.  
  1856.  
  1857.  
  1858.  
  1859.  
  1860. char * npszAddChildrenErrors [] =
  1861. {
  1862. "Memory allocation failure.",
  1863. "Level limit exceeded.",
  1864. "The number of nodes supported has been exeeded.",
  1865. "Only on root per tree.",
  1866. "Given parent node is invalid.",
  1867. "Invalid error code."
  1868. };                     
  1869.  
  1870. WORD HandleAddChildrenError( HWND hwnd, WORD wErrCode)
  1871. {
  1872.    WORD i;
  1873.      
  1874.    switch (wErrCode)
  1875.    {
  1876.       case BST_NO_ERROR:
  1877.          i = 0;
  1878.          break;
  1879.  
  1880.       case BST_ERR_MEMORY_ALLOC_FAILED:
  1881.          i = 1;
  1882.          break;
  1883.                      
  1884.       case BST_ERR_LEVEL_LIMIT_EXCEEDED:
  1885.          i = 2;
  1886.          break;
  1887.                      
  1888.       case BST_ERR_TOO_MANY_NODES:
  1889.          i = 3;
  1890.          break;
  1891.                  
  1892.       case BST_ERR_ONLY_ONE_ROOT_ALLOWED: 
  1893.          i = 4;
  1894.          break;
  1895.                      
  1896.       case BST_ERR_INVALID_PARENT_FOR_INSERTION:
  1897.          i = 5;
  1898.          break;
  1899.                
  1900.       default:
  1901.         i = 6;
  1902.         break;
  1903.    }
  1904.    if ( i != 0)
  1905.    {
  1906.       MessageBox ( hwnd, 
  1907.                    npszAddChildrenErrors[i-1],
  1908.                    "BST_AddChildrenToParent",
  1909.                     MB_OK);
  1910.    }
  1911.    return i;   
  1912. }
  1913.  
  1914.  
  1915.  
  1916.  
  1917.  
  1918. /**************************************************************************/
  1919. /* Below are support routines for the 16 color bitmaps used in the tree */
  1920. // Enjoy!
  1921.  
  1922. HBITMAP CreateBackgroundMatchedBitmap (DWORD dwrgbBackground, int nBitmapResouce)
  1923. {
  1924.    HANDLE             hBitmap;
  1925.    HANDLE             hRes;
  1926.    HANDLE             hResMem;
  1927.    LPBITMAPINFOHEADER lpbi;
  1928.    DWORD FAR *        lpColorTable;
  1929.    LPSTR              lpBits;
  1930.    int                bc;
  1931.    HDC                hdc;
  1932.       
  1933.    hRes = FindResource ( hInst,
  1934.                          MAKEINTRESOURCE (nBitmapResouce),
  1935.                          RT_BITMAP);
  1936.                               
  1937.    hResMem = LoadResource (hInst, hRes);
  1938.    lpbi = (LPBITMAPINFOHEADER) LockResource (hResMem);
  1939.          
  1940.    lpColorTable = (DWORD FAR *)(lpbi + 1);
  1941.    lpBits = (LPSTR) (lpColorTable + 16);
  1942.          
  1943.    bc = (lpBits[0] & 0xF0) >> 4;
  1944.          
  1945.    lpColorTable [bc] = RGB( GetBValue (dwrgbBackground),
  1946.                             GetGValue (dwrgbBackground),
  1947.                             GetRValue (dwrgbBackground));
  1948.    hdc = GetDC(NULL);
  1949.    hBitmap =  CreateDIBitmap ( hdc,
  1950.                                lpbi,
  1951.                                (DWORD) CBM_INIT,
  1952.                                lpBits,
  1953.                                (LPBITMAPINFO) lpbi,
  1954.                                DIB_RGB_COLORS);
  1955.    ReleaseDC(NULL, hdc);
  1956.    UnlockResource (hResMem);
  1957.    FreeResource(hResMem);
  1958.    return hBitmap;
  1959. }
  1960.  
  1961.  
  1962. char   rgchBits [2048];
  1963.  
  1964. short ChangeBitmapToMatchBackground ( DWORD dwrgbBackground,
  1965.                                       HANDLE hBitmap,
  1966.                                       int nBitmapResouce)
  1967. {
  1968.    int                bc;
  1969.    HDC                hdc;
  1970.    LPBITMAPINFO       lpbi;
  1971.    HANDLE             hRes;
  1972.    HANDLE             hResMem;
  1973.  
  1974.    hRes = FindResource ( hInst,
  1975.                          MAKEINTRESOURCE (nBitmapResouce),
  1976.                          RT_BITMAP);
  1977.                               
  1978.    hResMem = LoadResource (hInst, hRes);
  1979.    lpbi = ( LPBITMAPINFO ) LockResource (hResMem);
  1980.    
  1981.    hdc = GetDC (NULL);
  1982.    
  1983.    GetDIBits ( hdc,
  1984.                hBitmap,
  1985.                0,
  1986.                LOWORD(lpbi->bmiHeader.biHeight),
  1987.                rgchBits,
  1988.                lpbi,
  1989.                DIB_RGB_COLORS);
  1990.  
  1991.    bc = (rgchBits[0] & 0xF0) >> 4;
  1992.          
  1993.    lpbi->bmiColors[bc].rgbBlue = GetBValue (dwrgbBackground);
  1994.    lpbi->bmiColors[bc].rgbGreen = GetGValue (dwrgbBackground);
  1995.    lpbi->bmiColors[bc].rgbRed =  GetRValue (dwrgbBackground);
  1996.    lpbi->bmiColors[bc].rgbReserved = 0;
  1997.  
  1998.    SetDIBits(hdc,
  1999.              hBitmap,
  2000.              0,
  2001.              LOWORD(lpbi->bmiHeader.biHeight),
  2002.              rgchBits,
  2003.              lpbi,
  2004.              DIB_RGB_COLORS);
  2005.  
  2006.    ReleaseDC(NULL, hdc );
  2007.    UnlockResource (hResMem);
  2008.    FreeResource(hResMem);
  2009.    return 0;
  2010. }
  2011.  
  2012.  
  2013.  
  2014. short ReadInDatabases ( void )
  2015. {
  2016.    HANDLE hResource;
  2017.    LP_TREE_DATABASE lpTreeDB;
  2018.    LPSTR lpsz;
  2019.    short i;
  2020.    
  2021.    hResource = LoadResource (hInst,
  2022.                FindResource (hInst, "TREEDB", RT_RCDATA));
  2023.    lpTreeDB = (LP_TREE_DATABASE) LockResource (hResource);
  2024.    if(lpTreeDB == NULL)
  2025.    {
  2026.       MessageBox (NULL, "Resource lock down error.", "Tree Demo 3", MB_OK);
  2027.       return 1; 
  2028.    } 
  2029.    lpsz = (LPSTR) lpTreeDB;
  2030.    
  2031.    for( i = 0; i < TREE_SIZE; i++)
  2032.    {
  2033.       TreeDatabase[i].wIndexOfThisNode = lpTreeDB->wIndexOfThisNode;
  2034.       TreeDatabase[i].wBitmapIndex = lpTreeDB->wBitmapIndex;
  2035.       TreeDatabase[i].wNumberOfChildren = lpTreeDB->wNumberOfChildren;
  2036.       TreeDatabase[i].wIndexOfChildren = lpTreeDB->wIndexOfChildren;
  2037.       TreeDatabase[i].lpszNodeText = (char _far *) _fmalloc(160);
  2038.       if(TreeDatabase[i].lpszNodeText == NULL)
  2039.       {
  2040.          MessageBox (NULL, "Database memory allocation error.", "Tree Demo 3", MB_OK);
  2041.          return 1; 
  2042.       }
  2043.       lpsz += (sizeof (TREE_DATABASE) - sizeof(LPSTR));
  2044.       lstrcpy (TreeDatabase[i].lpszNodeText, lpsz);
  2045.       lpsz += lstrlen ( (LPSTR) lpsz) + 1;
  2046.       lpTreeDB = (LP_TREE_DATABASE) lpsz;
  2047.    }
  2048.    UnlockResource (hResource);
  2049.    FreeResource (hResource);
  2050.    
  2051.    hResource = LoadResource (hInst,
  2052.                FindResource (hInst, "LISTDB", RT_RCDATA));
  2053.    lpTreeDB = (LP_TREE_DATABASE) LockResource (hResource);
  2054.    if(lpTreeDB == NULL)
  2055.    {
  2056.       MessageBox (NULL, "Resource lock down error.", "Tree Demo 3", MB_OK);
  2057.       return 1; 
  2058.    
  2059.    } 
  2060.    lpsz = (LPSTR) lpTreeDB;
  2061.    
  2062.    for( i = 0; i < LIST_SIZE; i++)
  2063.    {
  2064.       ListDatabase[i].wIndexOfThisNode = lpTreeDB->wIndexOfThisNode;
  2065.       ListDatabase[i].wBitmapIndex = lpTreeDB->wBitmapIndex;
  2066.       ListDatabase[i].wNumberOfChildren = lpTreeDB->wNumberOfChildren;
  2067.       ListDatabase[i].wIndexOfChildren = lpTreeDB->wIndexOfChildren;
  2068.       ListDatabase[i].lpszNodeText = (char _far *) _fmalloc(160);
  2069.       if(TreeDatabase[i].lpszNodeText == NULL)
  2070.       {
  2071.          MessageBox (NULL, "Database memory allocation error.", "Tree Demo 3", MB_OK);
  2072.          return 1; 
  2073.       }
  2074.       lpsz += (sizeof (TREE_DATABASE) - sizeof(LPSTR));
  2075.       lstrcpy (ListDatabase[i].lpszNodeText, lpsz);
  2076.       lpsz += lstrlen ( (LPSTR) lpsz) + 1;
  2077.       lpTreeDB = (LP_TREE_DATABASE) lpsz;
  2078.    }
  2079.    UnlockResource (hResource);   
  2080.    FreeResource (hResource);
  2081.    return 0;
  2082. }
  2083.  
  2084. /*--------------------------------- EOF -----------------------------------*/
  2085.