Hide

SftTree/DLL 7.5 - Tree Control

Display
Print

Virtual Sample (C)

This sample illustrates a tree control in virtual mode, used to display a list with 1 million items.

The source code is located at C:\Program Files (x86)\Softelvdm\SftTree DLL 7.5\Samples\C\Virtual\Virtual.c or C:\Program Files\Softelvdm\SftTree DLL 7.5\Samples\C\Virtual\Virtual.c (on 32-bit Windows versions).

/****************************************************************************/
/* SftTree/DLL 7.5 - Tree Control for C/C++                                 */
/* Copyright (C) 1995, 2016  Softel vdm, Inc. All Rights Reserved.          */
/****************************************************************************/

#include <windows.h>

#include "SftTree.h"                     /* SftTree/DLL Header File */

#include "resource.h"                    // resource IDs

/**********************************************************************/
/*                              Globals                               */
/**********************************************************************/

HINSTANCE g_hInst;                      // App Instance Handle
HWND g_hwndTree;                        /* Tree control */

#define IDC_TREE 100                    /* Tree control ID */

// Miscellaneous bitmaps

HBITMAP m_hItem;

HBITMAP m_hBgBitmap;                    /* Background bitmap */

SFT_PICTURE m_aThreeItemPictures[3];    /* Three default item pictures, see SetPictures in online help */
SFT_PICTURE m_OtherItemPicture;         /* Another item picture, see SetItemPicture in online help */

HBITMAP m_hCellBitmap;                  /* A cell bitmap */

HBITMAP m_hRowBitmap;                   /* Row header bitmap */

SFT_PICTURE m_RowColHeaderPicture;            /* Row/column picture */

/**********************************************************************/
/*                          ToolTips Callback                         */
/**********************************************************************/

// Callback of type SFTTREE_TOOLTIPSPROC
void CALLBACK Tree_ToolTipsCallback(HWND hwnd,
    LPTSTR lpszBuffer, int type, int index, int column, SFTTREE_DWORD_PTR UserData, BOOL FAR* fInPlace)
{
    switch (type) {
    case SFTTREE_TOOLTIP_VSCROLL:        /* Vertical scrolling */
        wsprintf(lpszBuffer, TEXT("Item %d is on top"), index);
        break;
    case SFTTREE_TOOLTIP_CELL:           /* Cell tooltip */
        // If lpszBuffer is left as-is, the cell tooltip will be displayed, otherwise
        // the text in lpszBuffer will be shown as an explanatory tooltip.
        // we don't modify lpszBuffer, so we get the default in-place tooltip
        //wsprintf(lpszBuffer, TEXT("An explanatory tooltip for cell %d/%d"), index, column);
        break;
    case SFTTREE_TOOLTIP_COLUMN_HEADER:         /* Column header tooltip */
        wsprintf(lpszBuffer, TEXT("A tooltip for column %d"), column);
        break;
    default:                             /* unhandled type (future expansion) */
        return;
    }
}

/*------------------------------------------------------------------------------*/
/* This sample code implements the virtual data source member functions to      */
/* retrieve/release data from an external data source.                          */
/*------------------------------------------------------------------------------*/

// Callback of type LPFNSFTTREE_VGETITEM
void CALLBACK Tree_VirtualStorageGetItemCallback(HWND hwnd,
        SFTTREE_DWORD_PTR UserData, int totCols, LONG index, LPSFTTREE_ITEM FAR* lplpItem)
{
    // All item information (including all strings) MUST remain valid until VirtualStorageReleaseItem
    // is called. For this reason, the strings must be allocated using "calloc/malloc" or be static and CANNOT be
    // objects located on the stack (i.e., NO local variables).

    int col;
    static SFTTREE_ITEM m_WorkingItem;
    static TCHAR aText[3][80];           /* Cell text */
    static LPTSTR aCellText[3];
    static SFTTREE_CELL aCells[3];
    static SFTTREE_ROW rowInfo;

    /* Initialize */
    memset(&m_WorkingItem, 0, sizeof(m_WorkingItem));
    memset(&aCells, 0, sizeof(aCells));
    memset(&aCellText, 0, sizeof(aCellText));
    memset(&rowInfo, 0, sizeof(rowInfo));

    /* Basic item information */
    m_WorkingItem.level = 0;             // Provide the level number (must be 0)
    m_WorkingItem.fShown = TRUE;         // Must be shown (it's a flat list)
    m_WorkingItem.fEnabled = TRUE;       // Item is enabled (visually)
    m_WorkingItem.dwdData = 0;           // Userdata for this item (can be 0)
    m_WorkingItem.lpszRowHeader = NULL;  // Row header text (can be NULL)

    if ((index % 6) == 0)                /* Randomly change item bitmap */
        Sft_SetPictureBitmap(&m_WorkingItem.ItemPicture, m_hItem);

    /* Cell text */
    aCellText[0] = aText[0];
    wsprintf(aCellText[0], TEXT("Item %09ld"), index);
    for (col = 1 ; col < totCols ; ++col) {
        aCellText[col] = aText[col];
        wsprintf(aCellText[col], TEXT("Column %d(%d)"), col, index);
    }
    m_WorkingItem.alpszString = aCellText;/* Cell text array */

    // (Optional) Initialize cells
    m_WorkingItem.aCells = aCells;
    for (col = 0 ; col < totCols ; ++col) {
        LPSFTTREE_CELL lpCell = &m_WorkingItem.aCells[col];
        lpCell->colorBg = lpCell->colorFg =   /* Cell colors */
            lpCell->colorBgSel = lpCell->colorFgSel = SFTTREE_NOCOLOR;
        lpCell->hFont = NULL;            /* Cell font */
        lpCell->flag = SFTTREE_BMP_LEFT; /* Cell bitmap alignment */
        if ((index % 5) == 0 && col == 1) {/* Randomly add bitmaps */
            Sft_SetPictureBitmap(&lpCell->CellPicture1, m_hCellBitmap);/* Cell picture */
            lpCell->flag |= SFTTREE_BMP_RIGHT;/* Cell picture alignment */
        }
        if (col == 2 && (index % 5) == 0) {/* Randomly change colors */
            lpCell->colorBg = 0x80000000 | COLOR_BTNFACE;
            lpCell->colorFg = 0x80000000 | COLOR_BTNTEXT;
        }
    }

    // (Optional) Create row header information
    m_WorkingItem.lpszRowHeader = NULL;  /* Row header text (can be NULL) */
    m_WorkingItem.lpRow = &rowInfo;      /* Row header information (can be NULL) */
    rowInfo.colorBg = rowInfo.colorFg =  /* Row header colors */
        rowInfo.colorBgSel = rowInfo.colorFgSel = SFTTREE_NOCOLOR;
    if ((index % 8) == 0) {/*randomly add bitmaps */
        Sft_SetPictureBitmap(&rowInfo.RowPicture1, m_hRowBitmap);/* Row header picture */
        rowInfo.flag = SFTTREE_BMP_LEFT; /* Row header picture alignment */
    }

    *lplpItem = &m_WorkingItem;
}

// Callback of type LPFNSFTTREE_VRELEASEITEM
void CALLBACK Tree_VirtualStorageReleaseItemCallback(HWND hwnd,
        SFTTREE_DWORD_PTR UserData, int totCols, LONG index, LPSFTTREE_ITEM lpItem)
{
    // free storage allocated during previous Tree_VirtualStorageGetItemCallback call
}

/**********************************************************************/
/*                          Frame Window Proc                         */
/**********************************************************************/

LRESULT CALLBACK SDI_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {

    case WM_CREATE: {
        RECT rect;
        GetClientRect(hwnd, &rect);
        g_hwndTree = CreateWindowEx(
            WS_EX_CLIENTEDGE,
            TEXT(SFTTREESPLIT_CLASS),        /* Window class */
            TEXT(""),                        /* Caption (none) */
            SFTTREESTYLE_NOTIFY |            /* Notify parent window */
            SFTTREESTYLE_LEFTBUTTONONLY |    /* Only respond to left mouse button */
            SFTTREESTYLE_SCROLL |            /* Honor WS_H/VSCROLL */
            SFTTREESTYLE_DISABLENOSCROLL |   /* Disable scrollbars instead of hiding */
            WS_HSCROLL | WS_VSCROLL |        /* Vertical and horizontal scrollbars */
            WS_VISIBLE | WS_CHILD,           /* Visible, child window */
            rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,/* Location */
            hwnd,                            /* Parent window */
            (HMENU) IDC_TREE,                /* Tree control ID */
            g_hInst,                         /* Application instance */
            NULL);
        if (!g_hwndTree)
            return -1;

        m_hItem = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_ITEM));/* Another item bitmap */

        /* Resources, such as bitmaps, should be loaded and must remain    */
        /* valid until the tree control is destroyed or no longer uses     */
        /* these.  For example, use DeleteObject to delete any bitmaps.    */

        /* Initialize "virtual" data callback routines.  The       */
        /* routines used are defined below.                        */
        {
            SFTTREE_VIRTUALDEF virt = {
                SFTTREE_VERSION_700,
                0,
                Tree_VirtualStorageGetItemCallback,
                Tree_VirtualStorageReleaseItemCallback,
            };
            if (!SftTreeSplit_VirtualInitialize(g_hwndTree, &virt))
                ; /* error handling goes here */
            /* Set current number of items in the control.             */
            if (!SftTreeSplit_VirtualCount(g_hwndTree, 1000000L, 1000000L, 0))
                ; /* error handling goes here */
        }

        SftTreeSplit_SetShowHeader(g_hwndTree, TRUE);/* Show column headers */
        /* Define the background bitmap.                           */
        m_hBgBitmap = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BACKGROUND));/* Load a background bitmap */
        SftTreeSplit_SetBackgroundBitmap(g_hwndTree, m_hBgBitmap, 0, 0, 0);/* Define the background bitmap */
        /* Register the item pictures.  These pictures are used    */
        /* for all items in the tree control. All three pictures   */
        /* must be the same size.                                  */
        Sft_InitPicture(&m_aThreeItemPictures[0]);
        Sft_InitPicture(&m_aThreeItemPictures[1]);
        Sft_InitPicture(&m_aThreeItemPictures[2]);
        Sft_SetPictureBitmap(&m_aThreeItemPictures[0], LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_EXPANDABLE)));/* Expandable picture */
        Sft_SetPictureBitmap(&m_aThreeItemPictures[1], LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_EXPANDED)));/* Expanded picture */
        Sft_SetPictureBitmap(&m_aThreeItemPictures[2], LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_LEAF)));/* Leaf picture */
        SftTreeSplit_SetPictures(g_hwndTree, m_aThreeItemPictures);/* Use item picture */
        SftTreeSplit_SetItemBitmapAlign(g_hwndTree, TRUE);/* Align item bitmaps */
        /* Register the cell picture size.  All cell pictures used */
        /* must be the same size.  Only one picture needs to be    */
        /* registered, even if several are used.                   */
        {
            SFTTREE_CELLINFOPARM CellInfo;
            CellInfo.version = 7;
            CellInfo.index = -1;             /* Registering picture size */
            m_hCellBitmap = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_SMILE1));/* Cell picture */
            Sft_InitPicture(&CellInfo.Cell.CellPicture1);
            Sft_SetPictureBitmap(&CellInfo.Cell.CellPicture1, m_hCellBitmap);
            SftTreeSplit_SetCellInfo(g_hwndTree, &CellInfo);/* Register use of cell pictures */
        }
        SftTreeSplit_SetTreeLineStyle(g_hwndTree, SFTTREE_TREELINE_NONE);/* No tree lines */
        SftTreeSplit_SetShowButtons(g_hwndTree, FALSE);/* No expand/collapse buttons */
        SftTreeSplit_SetShowGrid(g_hwndTree, TRUE);/* Show grid */
        SftTreeSplit_SetGridStyle(g_hwndTree, SFTTREE_GRID_BOTH_DOT);/* Dotted grid lines */
        SftTreeSplit_SetShowTruncated(g_hwndTree, TRUE);/* Show ... if truncated */
        SftTreeSplit_SetSelectionStyle(g_hwndTree, SFTTREE_SELECTION_CELL1);/* Select first cell only */
        SftTreeSplit_SetSelectionArea(g_hwndTree, SFTTREE_SELECTIONAREA_ALL);/* Selection changes by clicking anywhere on an item */
        SftTreeSplit_SetFlyby(g_hwndTree, TRUE);/* Flyby highlighting */
        SftTreeSplit_SetScrollTips(g_hwndTree, TRUE);/* Show Scrolltips */
        SftTreeSplit_SetReorderColumns(g_hwndTree, TRUE);/* Column reordering */
        SftTreeSplit_SetOpenEnded(g_hwndTree, TRUE, TRUE);/* Left tree open ended*/
        SftTreeSplit_SetOpenEnded(g_hwndTree, TRUE, FALSE);/* Right tree open ended */
        SftTreeSplit_SetShowHeaderButtons(g_hwndTree, TRUE);/* Show column header as buttons */

        /* Define columns */
        {
            SFTTREE_COLUMN_EX aCol[3] = {
              { 0, 0,                        /* Reserved */
                116,                         /* Width (in pixels) */
                ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
                ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
                TEXT("First Column"),        /* Column header title */
                NULL, NULL,                  /* Reserved field and bitmap handle */
                SFTTREE_BMP_RIGHT,           /* Bitmap alignment */
                0, 0, 0,                     /* Reserved fields */
                SFTTREE_NOCOLOR,             /* Cell background color */
                SFTTREE_NOCOLOR,             /* Cell foreground color */
                SFTTREE_NOCOLOR,             /* Selected cell background color */
                SFTTREE_NOCOLOR,             /* Selected cell foreground color */
                0,                           /* Real column position (set by SetColumns call) */
                0,                           /* Display column number (display position) */
                SFTTREE_COL_MERGE |          /* Column can merge with next */
                SFTTREE_COL_MERGEINTO |      /* Previous column can merge into this column */
                0,                           /* Column flag */
                30,                          /* Minimum column width */
              },
              { 0, 0,                        /* Reserved */
                131,                         /* Width (in pixels) */
                ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
                ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
                TEXT("Second Column"),       /* Column header title */
                NULL, NULL,                  /* Reserved field and bitmap handle */
                SFTTREE_BMP_RIGHT,           /* Bitmap alignment */
                0, 0, 0,                     /* Reserved fields */
                SFTTREE_NOCOLOR,             /* Cell background color */
                SFTTREE_NOCOLOR,             /* Cell foreground color */
                SFTTREE_NOCOLOR,             /* Selected cell background color */
                SFTTREE_NOCOLOR,             /* Selected cell foreground color */
                0,                           /* Real column position (set by SetColumns call) */
                1,                           /* Display column number (display position) */
                SFTTREE_COL_MERGE |          /* Column can merge with next */
                SFTTREE_COL_MERGEINTO |      /* Previous column can merge into this column */
                0,                           /* Column flag */
                30,                          /* Minimum column width */
              },
              { 0, 0,                        /* Reserved */
                131,                         /* Width (in pixels) */
                ES_LEFT | SFTTREE_TOOLTIP,   /* Cell alignment */
                ES_LEFT | SFTTREE_HEADER_UP, /* Title style */
                TEXT("Third Column"),        /* Column header title */
                NULL, NULL,                  /* Reserved field and bitmap handle */
                SFTTREE_BMP_RIGHT,           /* Bitmap alignment */
                0, 0, 0,                     /* Reserved fields */
                SFTTREE_NOCOLOR,             /* Cell background color */
                SFTTREE_NOCOLOR,             /* Cell foreground color */
                SFTTREE_NOCOLOR,             /* Selected cell background color */
                SFTTREE_NOCOLOR,             /* Selected cell foreground color */
                0,                           /* Real column position (set by SetColumns call) */
                2,                           /* Display column number (display position) */
                0,                           /* Column flag */
                30,                          /* Minimum column width */
              }
            };
            SftTreeSplit_SetColumnsEx(g_hwndTree, 3, aCol);/* Set column attributes */
            SftTreeSplit_SetSplitColumn(g_hwndTree, 1);/* Column split position */
        }

        SftTreeSplit_SetShowRowHeader(g_hwndTree, SFTTREE_ROWSTYLE_BUTTONCOUNT0);/* Row style */
        /* Register the row header picture size.  All row header   */
        /* pictures used must be the same size.  Only one picture  */
        /* needs to be registered, even if several are used.       */
        {
            SFTTREE_ROWINFOPARM RowInfo;
            RowInfo.version = 7;
            RowInfo.index = -1;
            m_hRowBitmap = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_ROW));/* Row header picture */
            Sft_InitPicture(&RowInfo.Row.RowPicture1);
            Sft_SetPictureBitmap(&RowInfo.Row.RowPicture1, m_hRowBitmap);
            SftTreeSplit_SetRowInfo(g_hwndTree, &RowInfo);
        }
        SftTreeSplit_SetRowColHeaderText(g_hwndTree, TEXT("?"));/* Row/column header text */
        SftTreeSplit_SetRowColHeaderStyle(g_hwndTree, ES_LEFT | SFTTREE_HEADER_UP);/* Row/column header style */
        Sft_InitPicture(&m_RowColHeaderPicture);
        Sft_SetPictureBitmap(&m_RowColHeaderPicture, LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_SMILE1)));/* Row/column header picture */
        SftTreeSplit_SetRowColHeaderPicture(g_hwndTree, &m_RowColHeaderPicture);/* Row/column picture */
        SftTreeSplit_SetRowColHeaderPictureStyle(g_hwndTree, SFTTREE_BMP_RIGHT);/* Row/column picture alignment */
        SftTreeSplit_SetCalcVisibleOnly(g_hwndTree, TRUE);/* Visible items only (for calculations) */
        SftTreeSplit_SetCharSearchMode(g_hwndTree, SFTTREE_CHARSEARCH_NONE, -1);/* Ignore typed characters */
        /* Use a ToolTips callback routine */
        {
            SFTTREE_TOOLTIPSPARM Parm;       /* Parameter list */
            Parm.lpfnToolTips = (SFTTREE_TOOLTIPSPROC) Tree_ToolTipsCallback;/* User supplied routine */
            Parm.UserData = (SFTTREE_DWORD_PTR)0;/* User supplied data */
            SftTreeSplit_SetToolTipsCallback(g_hwndTree, &Parm);
        }
        /* Change the default colors */
        {
            SFTTREE_COLORS Colors;
            SftTreeSplit_GetCtlColors(g_hwndTree, &Colors);/* Get current color settings */
            Colors.colorSelBgNoFocus = COLOR_BTNFACE | 0x80000000L;/* Selection background color (no input focus) */
            Colors.colorSelFgNoFocus = COLOR_BTNTEXT | 0x80000000L;/* Selection foreground color (no input focus) */
            SftTreeSplit_SetCtlColors(g_hwndTree, &Colors);/* Set new colors */
        }

        // In our example, we use SetCalcLimit(50) which will only consider 50 items when
        // MakeColumnOptimal, MakeRowHeaderOptimal or MakeSplitterOptimal is used.  Because our sample
        // data is wider at the end of the list, we'll change the TopIndex to the very last few items.
        // That way the last 50 items are analyzed.  In a typical application this is not necessary.
        SftTreeSplit_SetTopIndex(g_hwndTree, SftTreeSplit_GetCount(g_hwndTree) - 50);


        /* Make all column widths optimal, so text and pictures    */
        /* are not clipped horizontally.                           */
        SftTreeSplit_SetCalcLimit(g_hwndTree, 50);/* Evaluate up to 50 items */
        SftTreeSplit_MakeColumnOptimal(g_hwndTree, -1);/* Make column widths optimal */

        /* Make row header width optimal, so text and pictures are */
        /* not clipped horizontally.                               */
        SftTreeSplit_SetCalcLimit(g_hwndTree, 50);/* Evaluate up to 50 items */
        SftTreeSplit_MakeRowHeaderOptimal(g_hwndTree);/* Make row header width optimal */

        SftTreeSplit_SetCalcLimit(g_hwndTree, 50);/* Evaluate up to 50 items */
        SftTreeSplit_RecalcHorizontalExtent(g_hwndTree);/* Update horizontal scroll bar */
        SftTreeSplit_MakeSplitterOptimal(g_hwndTree);/* Optimal splitter position */


        SftTreeSplit_SetTopIndex(g_hwndTree, 0);

        return 0;
     }
    case WM_DESTROY:

        DeleteObject(m_hItem);

        DeleteObject(m_hBgBitmap);           /* Background bitmap */

        DeleteObject(m_aThreeItemPictures[0].Picture.hBitmap);/* Default item pictures */
        DeleteObject(m_aThreeItemPictures[1].Picture.hBitmap);
        DeleteObject(m_aThreeItemPictures[2].Picture.hBitmap);

        DeleteObject(m_hCellBitmap);         /* A cell picture */

        DeleteObject(m_hRowBitmap);          /* Row header picture */

        DeleteObject(m_RowColHeaderPicture.Picture.hBitmap);/* Row/column picture */

        if (g_hwndTree)
            DestroyWindow(g_hwndTree);
        PostQuitMessage(0);
        break;

    case WM_SIZE: {
        int cx = LOWORD(lParam);
        int cy = HIWORD(lParam);
        SetWindowPos(g_hwndTree, NULL, 0, 0, cx, cy, SWP_NOACTIVATE | SWP_NOZORDER);
        return 0;
     }

    case WM_CONTEXTMENU:
        MessageBox(NULL, TEXT("Received WM_CONTEXTMENU message from the tree control.  You could bring up a context menu."),
            TEXT("WM_CONTEXTMENU"), MB_OK| MB_TASKMODAL);
        return 0;

    case WM_SETFOCUS:
        if (g_hwndTree)
            SetFocus(g_hwndTree);
        break;

    case WM_COMMAND: {
        HWND hwndCtl = (HWND) lParam;
        int id = LOWORD(wParam);
        int code = HIWORD(wParam);
        switch (id) {
        case IDC_TREE:
            switch(code) {
            case SFTTREEN_LBUTTONDBLCLK_COLUMNRES: {
                // a column resizing area has been double clicked, we'll resize the column
                /* Resize column optimally */
                int realCol = SftTreeSplit_GetResizeColumn(g_hwndTree);
                if (realCol >= 0) {
                    SftTreeSplit_SetCalcLimit(g_hwndTree, 50);/* Evaluate up to 50 items */
                    SftTreeSplit_MakeColumnOptimal(g_hwndTree, realCol);/* Make column width optimal */
                    SftTreeSplit_RecalcHorizontalExtent(g_hwndTree);/* Update horizontal scroll bar */
                } else {
                    SftTreeSplit_MakeSplitterOptimal(g_hwndTree);/* Optimal splitter position */
                }
                break;
              }
            case SFTTREEN_LBUTTONDBLCLK_ITEM: {
                int index;
                /* Get current position */
                index = SftTreeSplit_GetCaretIndex(hwndCtl);/* Get caret location */
                /* User defined processing goes here */
                break;
             }
            }
            break;

        case 1000:                      // Menu command, Exit
            DestroyWindow(hwnd);
            break;

        case 1001:                      // Menu command, Resize Splitter
            SftTreeSplit_EnterResizeMode(g_hwndTree);
            break;
        }
        break;
     }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

/**********************************************************************/
/*                              WinMain                               */
/**********************************************************************/

int PASCAL WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int cmdShow)
{
    MSG msg;
    HWND hwndMain;

    // Initialize
    g_hInst = hinst;

    if (!hinstPrev) {
        WNDCLASS cls;

        cls.hCursor         = LoadCursor(NULL, IDC_ARROW);
        cls.hIcon           = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ICON1));
        cls.lpszMenuName    = MAKEINTRESOURCE(IDR_MAINMENU);
        cls.hInstance       = g_hInst;
        cls.lpszClassName   = TEXT("SoftelSampleFrame");
        cls.hbrBackground   = (HBRUSH)(COLOR_WINDOW+1);
        cls.lpfnWndProc     = (WNDPROC) SDI_WndProc;
        cls.style           = CS_DBLCLKS;
        cls.cbWndExtra      = 0;
        cls.cbClsExtra      = 0;
        if (!RegisterClass(&cls))
            return 0;
    }

    SftTree_RegisterApp(hinst);   /* Register with SftTree/DLL */

    // Initialize, run, and terminate the application
    hwndMain = CreateWindowEx(
            0L,
            TEXT("SoftelSampleFrame"),
            TEXT("Softel vdm, Inc. - Virtual Sample"),
            WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
            CW_USEDEFAULT, CW_USEDEFAULT,
            CW_USEDEFAULT, CW_USEDEFAULT,
            NULL,
            NULL,
            g_hInst,
            NULL);
    if (!hwndMain)
        return 0;

    ShowWindow(hwndMain, cmdShow);
    UpdateWindow(hwndMain);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    SftTree_UnregisterApp(hinst); /* Unregister from SftTree/DLL */

    return (int) msg.wParam;
}